Skip to content

Commit 07c4ef1

Browse files
authored
feat(cc-widgets): autoWrapup implemented (#472)
1 parent a0edce1 commit 07c4ef1

11 files changed

Lines changed: 539 additions & 306 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
.wrapup-timer-icon {
2+
--mdc-icon-fill-color: var(--mds-color-theme-text-accent-normal);
3+
}
4+
5+
.wrapup-timer-icon.urgent {
6+
--mdc-icon-fill-color: var(--mds-color-theme-text-error-normal);
7+
}
8+
9+
.wrapup-timer-container {
10+
--mdc-listitem-default-background-color: var(--mds-color-theme-background-alert-theme-normal);
11+
--mdc-listitem-background-color-hover: var(--mds-color-theme-background-alert-theme-normal);
12+
border: 0.0625rem solid var(--mds-color-theme-outline-theme-normal) !important;
13+
border-radius: 0.5rem;
14+
height: 3rem;
15+
}
16+
.wrapup-timer-container.urgent {
17+
--mdc-listitem-default-background-color: var(--mds-color-theme-background-alert-error-normal);
18+
--mdc-listitem-background-color-hover: var(--mds-color-theme-background-alert-error-hover);
19+
}
20+
.wrapup-timer-label {
21+
display: flex;
22+
flex-direction: row;
23+
align-items: left;
24+
gap: 0.3rem;
25+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
import {Button, Icon, Text, ListItem} from '@momentum-design/components/dist/react';
3+
import './AutoWrapupTimer.css';
4+
import {AutoWrapupTimerProps} from '../task.types';
5+
import {UNTIL_AUTO_WRAPUP, CANCEL} from '../constants';
6+
7+
const AutoWrapupTimer: React.FC<AutoWrapupTimerProps> = ({
8+
secondsUntilAutoWrapup,
9+
allowCancelAutoWrapup,
10+
handleCancelWrapup,
11+
}) => {
12+
const isUrgent = secondsUntilAutoWrapup <= 10;
13+
const containerClassName = isUrgent ? 'wrapup-timer-container urgent' : 'wrapup-timer-container';
14+
const iconClassName = isUrgent ? 'wrapup-timer-icon urgent' : 'wrapup-timer-icon';
15+
return (
16+
<>
17+
<ListItem className={containerClassName}>
18+
<Icon
19+
length-unit="rem"
20+
slot="leading-controls"
21+
className={iconClassName}
22+
name={isUrgent ? 'alert-active-bold' : 'recents-bold'}
23+
size={1.25}
24+
></Icon>
25+
<div slot="leading-controls" className="wrapup-timer-label">
26+
<Text slot="leading-controls" type="body-large-bold">
27+
{`${Math.floor(secondsUntilAutoWrapup / 60)
28+
.toString()
29+
.padStart(2, '0')}:${(secondsUntilAutoWrapup % 60).toString().padStart(2, '0')}`}
30+
</Text>
31+
<Text slot="leading-controls" type="body-large-regular">
32+
{UNTIL_AUTO_WRAPUP}
33+
</Text>
34+
</div>
35+
{allowCancelAutoWrapup && (
36+
<Button slot="trailing-controls" variant="secondary" onClick={handleCancelWrapup}>
37+
{CANCEL}
38+
</Button>
39+
)}
40+
</ListItem>
41+
</>
42+
);
43+
};
44+
45+
export default AutoWrapupTimer;

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

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,30 +40,18 @@
4040

4141
.wrapup-select {
4242
flex-grow: 1;
43-
padding: 0.5rem; // 8px to rem
4443
margin-top: 0.5rem; // 8px to rem
4544
margin-bottom: 0.75rem; // 12px to rem
46-
border: 0.0625rem solid #ccc; // 1px to rem
47-
border-radius: 0.25rem; // 4px to rem
4845
align-self: flex-start; // Align similar to .wrapup-header
49-
}
50-
51-
.wrapup-select-arrow-icon {
52-
position: absolute;
53-
right: 1.5rem; /* Adjusted to leave space for the arrow icon */
54-
top: 55%;
55-
transform: translateY(-50%);
56-
display: flex;
57-
align-items: center;
58-
pointer-events: none;
59-
z-index: 1;
46+
width: 100%; // Ensure it takes full width of the container
6047
}
6148

6249
.submit-wrapup-button {
6350
align-self: flex-end;
6451
}
6552

6653
.wrapup-header {
54+
margin-top: 0.7rem;
6755
margin-bottom: 0.7rem;
6856
align-self: flex-start;
6957
}

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

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,26 @@ import React, {useEffect, useState} from 'react';
22

33
import {CallControlComponentProps, DestinationType, CallControlMenuType} from '../task.types';
44
import './call-control.styles.scss';
5-
import {PopoverNext, SelectNext, TooltipNext, Text, ButtonCircle, ButtonPill} from '@momentum-ui/react-collaboration';
6-
import {Item} from '@react-stately/collections';
7-
import {Icon, Button} from '@momentum-design/components/dist/react';
5+
import {PopoverNext, TooltipNext, Text, ButtonCircle} from '@momentum-ui/react-collaboration';
6+
import {Icon, Button, Select, Option} from '@momentum-design/components/dist/react';
87
import ConsultTransferPopoverComponent from './CallControlCustom/consult-transfer-popover';
8+
import AutoWrapupTimer from '../AutoWrapupTimer/AutoWrapupTimer';
99
import type {MEDIA_CHANNEL as MediaChannelType} from '../task.types';
1010
import {getMediaTypeInfo} from '../../../utils';
11+
import {
12+
RESUME_CALL,
13+
HOLD_CALL,
14+
CONSULT_AGENT,
15+
TRANSFER,
16+
PAUSE_RECORDING,
17+
RESUME_RECORDING,
18+
END,
19+
WRAP_UP,
20+
WRAP_UP_INTERACTION,
21+
WRAP_UP_REASON,
22+
SELECT,
23+
SUBMIT_WRAP_UP,
24+
} from '../constants';
1125

1226
function CallControlComponent(props: CallControlComponentProps) {
1327
const [selectedWrapupReason, setSelectedWrapupReason] = useState<string | null>(null);
@@ -41,6 +55,8 @@ function CallControlComponent(props: CallControlComponentProps) {
4155
setLastTargetType,
4256
controlVisibility,
4357
logger,
58+
secondsUntilAutoWrapup,
59+
cancelAutoWrapup,
4460
} = props;
4561

4662
useEffect(() => {
@@ -139,15 +155,15 @@ function CallControlComponent(props: CallControlComponentProps) {
139155
id: 'hold',
140156
icon: isHeld ? 'play-bold' : 'pause-bold',
141157
onClick: () => handletoggleHold(),
142-
tooltip: isHeld ? 'Resume the call' : 'Hold the call',
158+
tooltip: isHeld ? RESUME_CALL : HOLD_CALL,
143159
className: 'call-control-button',
144160
disabled: false,
145161
isVisible: controlVisibility.holdResume,
146162
},
147163
{
148164
id: 'consult',
149165
icon: 'headset-bold',
150-
tooltip: 'Consult with another agent',
166+
tooltip: CONSULT_AGENT,
151167
className: 'call-control-button',
152168
disabled: false,
153169
menuType: 'Consult',
@@ -156,7 +172,7 @@ function CallControlComponent(props: CallControlComponentProps) {
156172
{
157173
id: 'transfer',
158174
icon: 'next-bold',
159-
tooltip: `Transfer ${currentMediaType.labelName}`,
175+
tooltip: `${TRANSFER} ${currentMediaType.labelName}`,
160176
className: 'call-control-button',
161177
disabled: false,
162178
menuType: 'Transfer',
@@ -166,7 +182,7 @@ function CallControlComponent(props: CallControlComponentProps) {
166182
id: 'record',
167183
icon: isRecording ? 'record-paused-bold' : 'record-bold',
168184
onClick: () => toggleRecording(),
169-
tooltip: isRecording ? 'Pause Recording' : 'Resume Recording',
185+
tooltip: isRecording ? PAUSE_RECORDING : RESUME_RECORDING,
170186
className: 'call-control-button',
171187
disabled: false,
172188
isVisible: controlVisibility.pauseResumeRecording,
@@ -175,7 +191,7 @@ function CallControlComponent(props: CallControlComponentProps) {
175191
id: 'end',
176192
icon: 'cancel-regular',
177193
onClick: endCall,
178-
tooltip: `End ${currentMediaType.labelName}`,
194+
tooltip: `${END} ${currentMediaType.labelName}`,
179195
className: 'call-control-button-cancel',
180196
disabled: isHeld,
181197
isVisible: controlVisibility.end,
@@ -317,48 +333,58 @@ function CallControlComponent(props: CallControlComponentProps) {
317333
type="button"
318334
role="button"
319335
>
320-
Wrap up
336+
{WRAP_UP}
321337
</Button>
322338
}
323339
variant="medium"
324340
interactive
325341
offsetDistance={2}
326342
className="wrapup-popover"
327343
>
344+
{currentTask.autoWrapup && (
345+
<AutoWrapupTimer
346+
secondsUntilAutoWrapup={secondsUntilAutoWrapup}
347+
allowCancelAutoWrapup={false} // TODO: https://jira-eng-sjc12.cisco.com/jira/browse/CAI-6752 change to currentTask.autoWrapup.allowCancelAutoWrapup when its made supported in multi session from SDK side
348+
handleCancelWrapup={cancelAutoWrapup}
349+
/>
350+
)}
351+
328352
<Text className="wrapup-header" tagName={'small'} type="body-large-bold">
329-
Wrap-up Interaction
330-
</Text>
331-
<Text className="wrapup-header" tagName={'small'} type="body-secondary">
332-
Wrap-up reason
353+
{WRAP_UP_INTERACTION}
333354
</Text>
334-
<SelectNext
335-
aria-label="wrapup-reason"
355+
<Select
356+
label={WRAP_UP_REASON}
357+
help-text-type=""
358+
height="auto"
359+
data-aria-label="wrapup-reason"
360+
toggletip-text=""
361+
toggletip-placement=""
362+
info-icon-aria-label=""
363+
name=""
336364
className="wrapup-select"
337-
onSelectionChange={(key) => {
365+
placeholder={SELECT}
366+
onChange={(event: CustomEvent) => {
367+
const key = event.detail.value;
338368
const selectedItem = wrapupCodes?.find((code) => code.id === key);
339369
handleWrapupChange(selectedItem.name, selectedItem.id);
340370
}}
341-
items={wrapupCodes}
342-
showBorder={false}
343-
placeholder="Select"
344371
>
345-
{(item) => (
346-
<Item key={item.id} textValue={item.name}>
347-
<Text className="wrapup-name" tagName={'small'}>
348-
{item.name}
349-
</Text>
350-
</Item>
351-
)}
352-
</SelectNext>
353-
<Icon className="wrapup-select-arrow-icon" name="arrow-down-bold" title="" />
354-
<ButtonPill
372+
{wrapupCodes?.map((code) => (
373+
<Option key={code.id} value={code.id}>
374+
{code.name}
375+
</Option>
376+
))}
377+
</Select>
378+
<Button
379+
onClick={handleWrapupCall}
380+
variant="primary"
355381
className="submit-wrapup-button"
356-
onPress={handleWrapupCall}
357-
disabled={selectedWrapupId && selectedWrapupReason ? false : true}
382+
data-testid="submit-wrapup-button"
358383
aria-label="Submit wrap-up"
384+
disabled={selectedWrapupId && selectedWrapupReason ? false : true}
359385
>
360-
Submit & Wrap up
361-
</ButtonPill>
386+
{SUBMIT_WRAP_UP}
387+
</Button>
362388
</PopoverNext>
363389
</div>
364390
)}

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ import TaskTimer from '../TaskTimer/index';
77
import CallControlConsultComponent from '../CallControl/CallControlCustom/call-control-consult';
88
import {MEDIA_CHANNEL as MediaChannelType, CallControlComponentProps} from '../task.types';
99
import {getMediaTypeInfo} from '../../../utils';
10+
import {
11+
NO_CUSTOMER_NAME,
12+
NO_CALLER_ID,
13+
NO_PHONE_NUMBER,
14+
NO_TEAM_NAME,
15+
NO_RONA,
16+
ON_HOLD,
17+
QUEUE,
18+
PHONE_NUMBER,
19+
CUSTOMER_NAME,
20+
RONA,
21+
} from '../constants';
1022

1123
const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) => {
1224
const {
@@ -65,7 +77,7 @@ const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) =>
6577

6678
<div className="customer-info">
6779
<Text className="customer-id" type="body-large-bold" tagName={'small'}>
68-
{isSocial ? customerName || 'No Customer Name' : ani || 'No Caller ID'}
80+
{isSocial ? customerName || NO_CUSTOMER_NAME : ani || NO_CALLER_ID}
6981
</Text>
7082
<div className="call-details">
7183
<Text className="call-timer" type="body-secondary" tagName={'small'}>
@@ -77,7 +89,9 @@ const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) =>
7789
<span className="dot"></span>
7890
<div className="on-hold">
7991
<Icon name="call-hold-filled" size={1} className="call-hold-filled-icon" />
80-
<span className="on-hold-chip-text">On hold - {formatTime(holdTime)}</span>
92+
<span className="on-hold-chip-text">
93+
{ON_HOLD} {formatTime(holdTime)}
94+
</span>
8195
</div>
8296
</>
8397
)}
@@ -93,16 +107,16 @@ const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) =>
93107
<CallControlComponent {...props} />
94108
<div className="cad-variables">
95109
<Text className="queue" type="body-secondary" tagName={'small'}>
96-
<strong>Queue:</strong>{' '}
97-
<span>{currentTask?.data?.interaction?.callAssociatedDetails?.virtualTeamName || 'No Team Name'}</span>
110+
<strong>{QUEUE}</strong>{' '}
111+
<span>{currentTask?.data?.interaction?.callAssociatedDetails?.virtualTeamName || NO_TEAM_NAME}</span>
98112
</Text>
99113
<Text className="phone-number" type="body-secondary" tagName={'small'}>
100-
<strong>{isSocial ? 'Customer Name' : 'Phone Number'}:</strong>{' '}
101-
<span> {isSocial ? customerName || 'No Customer Name' : ani || 'No Phone Number'}</span>
114+
<strong>{isSocial ? CUSTOMER_NAME : PHONE_NUMBER}</strong>{' '}
115+
<span> {isSocial ? customerName || NO_CUSTOMER_NAME : ani || NO_PHONE_NUMBER}</span>
102116
</Text>
103117
<Text className="rona" type="body-secondary" tagName={'small'}>
104-
<strong>RONA:</strong>{' '}
105-
<span>{currentTask?.data?.interaction?.callAssociatedDetails?.ronaTimeout || 'No RONA'}</span>
118+
<strong>{RONA}</strong>{' '}
119+
<span>{currentTask?.data?.interaction?.callAssociatedDetails?.ronaTimeout || NO_RONA}</span>
106120
</Text>
107121
</div>
108122
</div>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Shared text constants for task components
2+
export const UNTIL_AUTO_WRAPUP = 'Until auto wrap-up';
3+
export const CANCEL = 'Cancel';
4+
export const RESUME_CALL = 'Resume the call';
5+
export const HOLD_CALL = 'Hold the call';
6+
export const CONSULT_AGENT = 'Consult with another agent';
7+
export const TRANSFER = 'Transfer';
8+
export const PAUSE_RECORDING = 'Pause Recording';
9+
export const RESUME_RECORDING = 'Resume Recording';
10+
export const END = 'End';
11+
export const WRAP_UP = 'Wrap up';
12+
export const WRAP_UP_INTERACTION = 'Wrap up interaction';
13+
export const WRAP_UP_REASON = 'Wrap-up reason';
14+
export const SELECT = 'Select';
15+
export const SUBMIT_WRAP_UP = 'Submit & Wrap up';
16+
17+
// CallControlCAD constants
18+
export const NO_CUSTOMER_NAME = 'No Customer Name';
19+
export const NO_CALLER_ID = 'No Caller ID';
20+
export const NO_PHONE_NUMBER = 'No Phone Number';
21+
export const NO_TEAM_NAME = 'No Team Name';
22+
export const NO_RONA = 'No RONA';
23+
export const ON_HOLD = 'On hold -';
24+
export const QUEUE = 'Queue:';
25+
export const PHONE_NUMBER = 'Phone Number:';
26+
export const CUSTOMER_NAME = 'Customer Name';
27+
export const RONA = 'RONA:';

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,13 @@ export interface ControlProps {
384384
endConsult: boolean;
385385
recordingIndicator: boolean;
386386
};
387+
388+
secondsUntilAutoWrapup?: number;
389+
390+
/**
391+
* Function to cancel the auto wrap-up timer.
392+
*/
393+
cancelAutoWrapup: () => void;
387394
}
388395

389396
export type CallControlComponentProps = Pick<
@@ -425,6 +432,8 @@ export type CallControlComponentProps = Pick<
425432
| 'setLastTargetType'
426433
| 'controlVisibility'
427434
| 'logger'
435+
| 'secondsUntilAutoWrapup'
436+
| 'cancelAutoWrapup'
428437
>;
429438

430439
/**
@@ -515,3 +524,9 @@ export type MediaInfo = {
515524
labelName: string;
516525
isBrandVisual: boolean;
517526
};
527+
528+
export interface AutoWrapupTimerProps {
529+
secondsUntilAutoWrapup: number;
530+
allowCancelAutoWrapup?: boolean;
531+
handleCancelWrapup: () => void;
532+
}

0 commit comments

Comments
 (0)