Skip to content

Commit 52b3ca4

Browse files
author
Christina Mullen
committed
updated CallControlCad component to support viewing agent viewable global variables
1 parent 64a3f77 commit 52b3ca4

5 files changed

Lines changed: 353 additions & 17 deletions

File tree

packages/contact-center/cc-components/src/components/task/CallControlCAD/call-control-cad.styles.scss

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
}
2323
}
2424

25+
.global-variables {
26+
display: flex;
27+
flex-wrap: wrap;
28+
gap: 1rem;
29+
margin-top: 0.75rem;
30+
31+
.global-variable-item {
32+
font-size: 1rem;
33+
color: var(--mds-color-theme-text-primary-normal);
34+
35+
strong {
36+
font-weight: bold;
37+
}
38+
39+
span {
40+
font-weight: 250;
41+
}
42+
}
43+
}
44+
2545
/* On-hold chip styling */
2646
.on-hold {
2747
display: flex;
@@ -44,7 +64,6 @@
4464
}
4565
}
4666

47-
4867
.recording-indicator {
4968
position: absolute;
5069
top: 0.5rem;
@@ -143,8 +162,6 @@
143162
transform: rotate(180deg);
144163
}
145164

146-
147-
148165
.call-status {
149166
display: flex;
150167
align-items: center;
@@ -200,11 +217,11 @@
200217
}
201218

202219
.digital-customer-name {
203-
width: auto;
220+
width: auto;
204221
}
205222

206223
.digital-phone-number {
207-
width: auto;
224+
width: auto;
208225
}
209226

210227
@media (min-width: 64.0625rem) and (max-width: 75rem) {
@@ -230,8 +247,8 @@
230247
max-width: 15rem;
231248
}
232249
.call-control-task-tooltip {
233-
width: 50%;
234-
text-align: center;
250+
width: 50%;
251+
text-align: center;
235252
}
236253
}
237254

@@ -246,8 +263,8 @@
246263
max-width: 13rem;
247264
}
248265
.call-control-task-tooltip {
249-
width: 50%;
250-
text-align: center;
266+
width: 50%;
267+
text-align: center;
251268
}
252269
}
253270

@@ -262,27 +279,27 @@
262279
max-width: 12rem;
263280
}
264281
.call-control-task-tooltip {
265-
width: 50%;
266-
text-align: center;
282+
width: 50%;
283+
text-align: center;
267284
}
268285
}
269286

270-
@media (min-width: 15.625rem) and (max-width: 20rem){
287+
@media (min-width: 15.625rem) and (max-width: 20rem) {
271288
.call-control-task-tooltip {
272289
width: 50%;
273290
text-align: center;
274291
}
275292
}
276293

277294
.participants-popover {
278-
background: var(--mds-color-theme-background-solid-primary-normal, #FFFFFF) !important;
295+
background: var(--mds-color-theme-background-solid-primary-normal, #ffffff) !important;
279296
align-items: normal;
280297
width: 100%;
281298
padding: 0 !important;
282299
border: var(--mds-color-theme-outline-secondary-normal);
283300

284301
&::part(popover-content) {
285-
background: var(--mds-color-theme-background-solid-primary-normal, #FFFFFF);
302+
background: var(--mds-color-theme-background-solid-primary-normal, #ffffff);
286303
border-radius: 0.75rem;
287304
border: 1px solid var(--mds-color-theme-outline-secondary-normal);
288305
box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.08);
@@ -307,7 +324,7 @@
307324
padding: 0.4rem 0.6rem;
308325
font-size: 0.875rem;
309326
cursor: pointer;
310-
color: var(--mds-color-theme-text-primary-normal, #000000F2);
327+
color: var(--mds-color-theme-text-primary-normal, #000000f2);
311328
border-radius: 0.5rem;
312329
min-width: 0;
313330
max-width: 100%;

packages/contact-center/cc-components/src/components/task/CallControlCAD/call-control-cad.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ import {Brandvisual, Icon, Tooltip, Button} from '@momentum-design/components/di
55
import './call-control-cad.styles.scss';
66
import TaskTimer from '../TaskTimer/index';
77
import CallControlConsultComponent from '../CallControl/CallControlCustom/call-control-consult';
8-
import {MEDIA_CHANNEL as MediaChannelType, CallControlComponentProps, getCallerIdentifier} from '../task.types';
8+
import {
9+
MEDIA_CHANNEL as MediaChannelType,
10+
CallControlComponentProps,
11+
getCallerIdentifier,
12+
CallAssociatedDataMap,
13+
getAgentViewableGlobalVariables,
14+
} from '../task.types';
915

1016
import {getMediaTypeInfo} from '../../../utils';
1117
import {
@@ -69,6 +75,10 @@ const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) =>
6975
//@ts-expect-error To be fixed in SDK - https://jira-eng-sjc12.cisco.com/jira/browse/CAI-6762
7076
const dn = currentTask?.data?.interaction?.callAssociatedDetails?.dn;
7177

78+
//@ts-expect-error To be fixed in SDK - https://jira-eng-sjc12.cisco.com/jira/browse/CAI-6762
79+
const callAssociatedData = currentTask?.data?.interaction?.callAssociatedData as CallAssociatedDataMap | undefined;
80+
const globalVariables = getAgentViewableGlobalVariables(callAssociatedData);
81+
7282
// Create unique IDs for tooltips
7383
const customerNameTriggerId = `customer-name-trigger-${currentTask.data.interaction.interactionId}`;
7484
const customerNameTooltipId = `customer-name-tooltip-${currentTask.data.interaction.interactionId}`;
@@ -275,6 +285,21 @@ const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) =>
275285
</Text>
276286
{renderPhoneNumber()}
277287
</div>
288+
{globalVariables.length > 0 && (
289+
<div className="global-variables" data-testid="cc-cad:global-variables">
290+
{globalVariables.map((variable) => (
291+
<Text
292+
key={variable.name}
293+
className="global-variable-item"
294+
type="body-secondary"
295+
tagName={'small'}
296+
data-testid={`cc-cad:global-var-${variable.name}`}
297+
>
298+
<strong>{variable.displayName || variable.name}:</strong> <span>{variable.value || ''}</span>
299+
</Text>
300+
))}
301+
</div>
302+
)}
278303
</div>
279304
{controlVisibility.isConsultInitiatedOrAccepted && !controlVisibility.wrapup.isVisible && (
280305
<div className={`call-control-consult-container ${callControlConsultClassName || ''}`}>

packages/contact-center/cc-components/src/components/task/task.types.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,61 @@ import {
1616

1717
type Enum<T extends Record<string, unknown>> = T[keyof T];
1818

19+
/**
20+
* Represents a single Call Associated Data (CAD) variable on an interaction.
21+
* Global variables have `global: true` and are set by flow control.
22+
*/
23+
export interface CADVariable {
24+
name: string;
25+
displayName: string;
26+
value: string;
27+
type: string;
28+
agentEditable: boolean;
29+
agentViewable: boolean;
30+
global: boolean;
31+
isSecure: boolean;
32+
secureKeyId: string;
33+
secureKeyVersion: number;
34+
}
35+
36+
/**
37+
* Record of CAD variables keyed by variable name.
38+
* This is the shape of `callAssociatedData` on the interaction at runtime.
39+
*/
40+
export type CallAssociatedDataMap = Record<string, CADVariable>;
41+
42+
/** System CAD variable keys that are already displayed elsewhere in the UI. */
43+
export const SYSTEM_CAD_KEYS = new Set([
44+
'ani',
45+
'dn',
46+
'customerName',
47+
'virtualTeamName',
48+
'ronaTimeout',
49+
'FC-DESKTOP-VIEW',
50+
]);
51+
52+
/**
53+
* Returns agent-viewable global variables from a callAssociatedData map,
54+
* excluding system variables that are already rendered elsewhere.
55+
*/
56+
export const getAgentViewableGlobalVariables = (
57+
callAssociatedData: CallAssociatedDataMap | undefined
58+
): CADVariable[] => {
59+
if (!callAssociatedData || typeof callAssociatedData !== 'object') {
60+
return [];
61+
}
62+
63+
return Object.entries(callAssociatedData)
64+
.filter(([key, cadVar]) => {
65+
if (!cadVar || !cadVar.name) return false;
66+
if (cadVar.agentViewable === false) return false;
67+
if (!cadVar.global) return false;
68+
if (SYSTEM_CAD_KEYS.has(key)) return false;
69+
return true;
70+
})
71+
.map(([, cadVar]) => cadVar);
72+
};
73+
1974
/**
2075
* Target types for consult/transfer operations
2176
*/

packages/contact-center/cc-components/tests/components/task/CallControlCAD/call-control-cad.tsx

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import React from 'react';
22
import {render} from '@testing-library/react';
33
import CallControlCADComponent from '../../../../src/components/task/CallControlCAD/call-control-cad';
4-
import {CallControlComponentProps, TARGET_TYPE, OUTBOUND_TYPE} from '../../../../src/components/task/task.types';
4+
import {
5+
CallControlComponentProps,
6+
TARGET_TYPE,
7+
OUTBOUND_TYPE,
8+
CallAssociatedDataMap,
9+
} from '../../../../src/components/task/task.types';
510
import {mockTask} from '@webex/test-fixtures';
611
import {BuddyDetails} from '@webex/cc-store';
712
import '@testing-library/jest-dom';
@@ -370,4 +375,143 @@ describe('CallControlCADComponent', () => {
370375
const customConsultContainer = customScreen.container.querySelector('.call-control-consult-container');
371376
expect(customConsultContainer).toHaveClass('custom-consult-control');
372377
});
378+
379+
describe('Global Variables', () => {
380+
const mockCallAssociatedData: CallAssociatedDataMap = {
381+
Global_Language: {
382+
name: 'Global_Language',
383+
displayName: 'Customer Language',
384+
value: 'English',
385+
type: 'STRING',
386+
agentEditable: false,
387+
agentViewable: true,
388+
global: true,
389+
isSecure: false,
390+
secureKeyId: '',
391+
secureKeyVersion: 0,
392+
},
393+
Global_FeedbackSurveyOptIn: {
394+
name: 'Global_FeedbackSurveyOptIn',
395+
displayName: 'Post Call Survey Opt-in',
396+
value: 'true',
397+
type: 'STRING',
398+
agentEditable: false,
399+
agentViewable: true,
400+
global: true,
401+
isSecure: false,
402+
secureKeyId: '',
403+
secureKeyVersion: 0,
404+
},
405+
ani: {
406+
name: 'ani',
407+
displayName: 'ani',
408+
value: '555-123-4567',
409+
type: 'STRING',
410+
agentEditable: false,
411+
agentViewable: true,
412+
global: false,
413+
isSecure: false,
414+
secureKeyId: '',
415+
secureKeyVersion: 0,
416+
},
417+
Global_Hidden: {
418+
name: 'Global_Hidden',
419+
displayName: 'Hidden Variable',
420+
value: 'secret',
421+
type: 'STRING',
422+
agentEditable: false,
423+
agentViewable: false,
424+
global: true,
425+
isSecure: false,
426+
secureKeyId: '',
427+
secureKeyVersion: 0,
428+
},
429+
};
430+
431+
const makePropsWithCallAssociatedData = (callAssociatedData: CallAssociatedDataMap) => ({
432+
...defaultProps,
433+
currentTask: {
434+
...defaultProps.currentTask,
435+
data: {
436+
...defaultProps.currentTask.data,
437+
interaction: {
438+
...defaultProps.currentTask.data.interaction,
439+
callAssociatedData,
440+
},
441+
},
442+
},
443+
});
444+
445+
it('should render agent-viewable global variables', () => {
446+
const screen = render(<CallControlCADComponent {...makePropsWithCallAssociatedData(mockCallAssociatedData)} />);
447+
448+
const globalVarsContainer = screen.getByTestId('cc-cad:global-variables');
449+
expect(globalVarsContainer).toBeInTheDocument();
450+
451+
expect(screen.getByTestId('cc-cad:global-var-Global_Language')).toBeInTheDocument();
452+
expect(screen.getByText('Customer Language:')).toBeInTheDocument();
453+
expect(screen.getByText('English')).toBeInTheDocument();
454+
455+
expect(screen.getByTestId('cc-cad:global-var-Global_FeedbackSurveyOptIn')).toBeInTheDocument();
456+
expect(screen.getByText('Post Call Survey Opt-in:')).toBeInTheDocument();
457+
expect(screen.getByText('true')).toBeInTheDocument();
458+
});
459+
460+
it('should not render non-global variables (e.g. system CAD like ani)', () => {
461+
const screen = render(<CallControlCADComponent {...makePropsWithCallAssociatedData(mockCallAssociatedData)} />);
462+
463+
expect(screen.queryByTestId('cc-cad:global-var-ani')).not.toBeInTheDocument();
464+
});
465+
466+
it('should not render global variables where agentViewable is false', () => {
467+
const screen = render(<CallControlCADComponent {...makePropsWithCallAssociatedData(mockCallAssociatedData)} />);
468+
469+
expect(screen.queryByTestId('cc-cad:global-var-Global_Hidden')).not.toBeInTheDocument();
470+
});
471+
472+
it('should not render global variables section when no global variables exist', () => {
473+
const screen = render(<CallControlCADComponent {...defaultProps} />);
474+
475+
expect(screen.queryByTestId('cc-cad:global-variables')).not.toBeInTheDocument();
476+
});
477+
478+
it('should not render global variables section when callAssociatedData is undefined', () => {
479+
const propsWithNoData = {
480+
...defaultProps,
481+
currentTask: {
482+
...defaultProps.currentTask,
483+
data: {
484+
...defaultProps.currentTask.data,
485+
interaction: {
486+
...defaultProps.currentTask.data.interaction,
487+
},
488+
},
489+
},
490+
};
491+
const screen = render(<CallControlCADComponent {...propsWithNoData} />);
492+
493+
expect(screen.queryByTestId('cc-cad:global-variables')).not.toBeInTheDocument();
494+
});
495+
496+
it('should use variable name as label when displayName is empty', () => {
497+
const dataWithEmptyDisplayName: CallAssociatedDataMap = {
498+
Global_NoDisplay: {
499+
name: 'Global_NoDisplay',
500+
displayName: '',
501+
value: 'some value',
502+
type: 'STRING',
503+
agentEditable: false,
504+
agentViewable: true,
505+
global: true,
506+
isSecure: false,
507+
secureKeyId: '',
508+
secureKeyVersion: 0,
509+
},
510+
};
511+
const screen = render(<CallControlCADComponent {...makePropsWithCallAssociatedData(dataWithEmptyDisplayName)} />);
512+
513+
expect(screen.getByText('Global_NoDisplay:')).toBeInTheDocument();
514+
expect(screen.getByText('some value')).toBeInTheDocument();
515+
});
516+
});
373517
});

0 commit comments

Comments
 (0)