Skip to content

Commit ab3308a

Browse files
committed
feat(plugin-cc): refactored-tasks
1 parent f304997 commit ab3308a

File tree

7 files changed

+141
-42
lines changed

7 files changed

+141
-42
lines changed

docs/samples/contact-center/app.js

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -610,8 +610,12 @@ function registerTaskListeners(task) {
610610
});
611611

612612
// Consult flows
613-
task.on('task:consultOfferCreated', (task) => {
614-
console.log('Consult offer created');
613+
task.on('task:consultCreated', (task) => {
614+
console.info('Consult created');
615+
});
616+
617+
task.on('task:offerConsult', (task) => {
618+
console.info('Received consult offer from another agent');
615619
});
616620

617621
task.on('task:consultAccepted', (task) => {
@@ -671,19 +675,6 @@ function registerTaskListeners(task) {
671675
}
672676
});
673677

674-
task.on('task:rejected', (reason) => {
675-
console.info('Task is rejected with reason:', reason);
676-
if (reason === 'RONA_TIMER_EXPIRED') {
677-
answerElm.disabled = true;
678-
declineElm.disabled = true;
679-
if(task.data.isConsulted) {
680-
updateButtonsPostEndCall();
681-
incomingDetailsElm.innerText = '';
682-
currentTask = undefined;
683-
}
684-
}
685-
});
686-
687678
task.on('task:rejected', (reason) => {
688679
console.info('Task is rejected with reason:', reason);
689680
showAgentStatePopup(reason);

packages/@webex/plugin-cc/src/cc.ts

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ import {
2121
EMPTY_STRING,
2222
AGENT_STATE_CHANGE,
2323
AGENT_MULTI_LOGIN,
24+
AGENT_STATION_LOGIN_SUCCESS,
25+
AGENT_STATION_LOGIN_FAILED,
26+
AGENT_LOGOUT_SUCCESS,
27+
AGENT_LOGOUT_FAILED,
28+
AGENT_DN_REGISTERED,
2429
OUTDIAL_DIRECTION,
2530
ATTRIBUTES,
2631
OUTDIAL_MEDIA_TYPE,
@@ -34,13 +39,7 @@ import WebexRequest from './services/core/WebexRequest';
3439
import LoggerProxy from './logger-proxy';
3540
import {StateChange, Logout, StateChangeSuccess} from './services/agent/types';
3641
import {getErrorDetails} from './services/core/Utils';
37-
import {
38-
Profile,
39-
WelcomeEvent,
40-
CC_EVENTS,
41-
CC_AGENT_EVENTS,
42-
ContactServiceQueue,
43-
} from './services/config/types';
42+
import {Profile, WelcomeEvent, CC_EVENTS, ContactServiceQueue} from './services/config/types';
4443
import {
4544
AGENT_STATE_AVAILABLE,
4645
AGENT_STATE_AVAILABLE_ID,
@@ -559,20 +558,43 @@ export default class ContactCenter extends WebexPlugin implements IContactCenter
559558

560559
private handleWebSocketMessage = (event: string) => {
561560
const eventData = JSON.parse(event);
562-
// Re-emit the events related to agent
563-
if (Object.values(CC_AGENT_EVENTS).includes(eventData.data?.type)) {
561+
// Re-emit all the events related to agent except keep-alives
562+
if (!eventData.keepalive) {
564563
// @ts-ignore
565564
this.emit(eventData.data.type, eventData.data);
566565
}
567566

568-
if (eventData.type === CC_EVENTS.AGENT_STATE_CHANGE) {
569-
// @ts-ignore
570-
this.emit(AGENT_STATE_CHANGE, eventData.data);
571-
}
572-
573-
if (eventData.type === CC_EVENTS.AGENT_MULTI_LOGIN) {
574-
// @ts-ignore
575-
this.emit(AGENT_MULTI_LOGIN, eventData.data);
567+
switch (eventData.type) {
568+
case CC_EVENTS.AGENT_STATION_LOGIN_SUCCESS:
569+
// @ts-ignore
570+
this.emit(AGENT_STATION_LOGIN_SUCCESS, eventData.data);
571+
break;
572+
case CC_EVENTS.AGENT_STATION_LOGIN_FAILED:
573+
// @ts-ignore
574+
this.emit(AGENT_STATION_LOGIN_FAILED, eventData.data);
575+
break;
576+
case CC_EVENTS.AGENT_LOGOUT_SUCCESS:
577+
// @ts-ignore
578+
this.emit(AGENT_LOGOUT_SUCCESS, eventData.data);
579+
break;
580+
case CC_EVENTS.AGENT_LOGOUT_FAILED:
581+
// @ts-ignore
582+
this.emit(AGENT_LOGOUT_FAILED, eventData.data);
583+
break;
584+
case CC_EVENTS.AGENT_STATE_CHANGE:
585+
// @ts-ignore
586+
this.emit(AGENT_STATE_CHANGE, eventData.data);
587+
break;
588+
case CC_EVENTS.AGENT_MULTI_LOGIN:
589+
// @ts-ignore
590+
this.emit(AGENT_MULTI_LOGIN, eventData.data);
591+
break;
592+
case CC_EVENTS.AGENT_DN_REGISTERED:
593+
// @ts-ignore
594+
this.emit(AGENT_DN_REGISTERED, eventData.data);
595+
break;
596+
default:
597+
break;
576598
}
577599
};
578600

packages/@webex/plugin-cc/src/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export const WEBEX_REQUEST_FILE = 'WebexRequest';
1515
export const TASK_MANAGER_FILE = 'TaskManager';
1616
export const AGENT_STATE_CHANGE = 'agent:stateChange';
1717
export const AGENT_MULTI_LOGIN = 'agent:multiLogin';
18+
export const AGENT_STATION_LOGIN_SUCCESS = 'agent:stationLoginSuccess';
19+
export const AGENT_STATION_LOGIN_FAILED = 'agent:stationLoginFailed';
20+
export const AGENT_LOGOUT_SUCCESS = 'agent:logoutSuccess';
21+
export const AGENT_LOGOUT_FAILED = 'agent:logoutFailed';
22+
export const AGENT_DN_REGISTERED = 'agent:dnRegistered';
1823
// AGENT OUTDIAL CONSTANTS
1924
export const OUTDIAL_DIRECTION = 'OUTBOUND';
2025
export const ATTRIBUTES = {};

packages/@webex/plugin-cc/src/services/task/TaskManager.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,15 @@ export default class TaskManager extends EventEmitter {
178178
...payload.data,
179179
isConsulted: false, // This ensures that the task consult status is always reset
180180
});
181-
// Do not emit anything since this be received only as a result of an API invocation(handled by a promise)
181+
task.emit(TASK_EVENTS.TASK_CONSULT_CREATED, task);
182182
break;
183183
case CC_EVENTS.AGENT_OFFER_CONSULT:
184184
// Received when other agent sends us a consult offer
185185
task = this.updateTaskData(task, {
186186
...payload.data,
187187
isConsulted: true, // This ensures that the task is marked as us being requested for a consult
188188
});
189-
189+
task.emit(TASK_EVENTS.TASK_OFFER_CONSULT, task);
190190
break;
191191
case CC_EVENTS.AGENT_CONSULTING:
192192
// Received when agent is in an active consult state
@@ -222,8 +222,25 @@ export default class TaskManager extends EventEmitter {
222222
task = this.updateTaskData(task, payload.data);
223223
break;
224224
case CC_EVENTS.AGENT_WRAPPEDUP:
225+
task.emit(TASK_EVENTS.TASK_WRAPPEDUP, task);
225226
this.removeTaskFromCollection(task);
226227
break;
228+
case CC_EVENTS.CONTACT_RECORDING_PAUSED:
229+
task = this.updateTaskData(task, payload.data);
230+
task.emit(TASK_EVENTS.TASK_RECORDING_PAUSED, task);
231+
break;
232+
case CC_EVENTS.CONTACT_RECORDING_PAUSE_FAILED:
233+
task = this.updateTaskData(task, payload.data);
234+
task.emit(TASK_EVENTS.TASK_RECORDING_PAUSE_FAILED, payload.data);
235+
break;
236+
case CC_EVENTS.CONTACT_RECORDING_RESUMED:
237+
task = this.updateTaskData(task, payload.data);
238+
task.emit(TASK_EVENTS.TASK_RECORDING_RESUMED, task);
239+
break;
240+
case CC_EVENTS.CONTACT_RECORDING_RESUME_FAILED:
241+
task = this.updateTaskData(task, payload.data);
242+
task.emit(TASK_EVENTS.TASK_RECORDING_RESUME_FAILED, payload.data);
243+
break;
227244
default:
228245
break;
229246
}

packages/@webex/plugin-cc/src/services/task/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,17 @@ export const TASK_EVENTS = {
4848
TASK_CONSULT_QUEUE_FAILED: 'task:consultQueueFailed',
4949
TASK_CONSULT_ACCEPTED: 'task:consultAccepted',
5050
TASK_CONSULTING: 'task:consulting',
51+
TASK_CONSULT_CREATED: 'task:consultCreated',
52+
TASK_OFFER_CONSULT: 'task:offerConsult',
5153
TASK_PAUSE: 'task:pause',
5254
TASK_RESUME: 'task:resume',
5355
TASK_END: 'task:end',
5456
TASK_WRAPUP: 'task:wrapup',
57+
TASK_WRAPPEDUP: 'task:wrappedup',
58+
TASK_RECORDING_PAUSED: 'task:recordingPaused',
59+
TASK_RECORDING_PAUSE_FAILED: 'task:recordingPauseFailed',
60+
TASK_RECORDING_RESUMED: 'task:recordingResumed',
61+
TASK_RECORDING_RESUME_FAILED: 'task:recordingResumeFailed',
5562
TASK_REJECT: 'task:rejected',
5663
TASK_HYDRATE: 'task:hydrate',
5764
} as const;

packages/@webex/plugin-cc/test/unit/spec/cc.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ import {
2020
CC_FILE,
2121
AGENT_STATE_CHANGE,
2222
AGENT_MULTI_LOGIN,
23+
AGENT_STATION_LOGIN_SUCCESS,
24+
AGENT_STATION_LOGIN_FAILED,
25+
AGENT_LOGOUT_SUCCESS,
26+
AGENT_LOGOUT_FAILED,
27+
AGENT_DN_REGISTERED,
2328
OUTDIAL_DIRECTION,
2429
OUTBOUND_TYPE,
2530
ATTRIBUTES,
@@ -1513,4 +1518,30 @@ describe('webex.cc', () => {
15131518
);
15141519
});
15151520
});
1521+
1522+
describe('handleWebSocketMessage events', () => {
1523+
let messageCallback;
1524+
let emitSpy;
1525+
1526+
beforeEach(() => {
1527+
emitSpy = jest.spyOn(webex.cc, 'emit');
1528+
messageCallback = mockWebSocketManager.on.mock.calls.find((c) => c[0] === 'message')[1];
1529+
});
1530+
1531+
[
1532+
{ ccEvent: CC_EVENTS.AGENT_STATION_LOGIN_SUCCESS, constant: AGENT_STATION_LOGIN_SUCCESS },
1533+
{ ccEvent: CC_EVENTS.AGENT_STATION_LOGIN_FAILED, constant: AGENT_STATION_LOGIN_FAILED },
1534+
{ ccEvent: CC_EVENTS.AGENT_LOGOUT_SUCCESS, constant: AGENT_LOGOUT_SUCCESS },
1535+
{ ccEvent: CC_EVENTS.AGENT_LOGOUT_FAILED, constant: AGENT_LOGOUT_FAILED },
1536+
{ ccEvent: CC_EVENTS.AGENT_DN_REGISTERED, constant: AGENT_DN_REGISTERED },
1537+
{ ccEvent: CC_EVENTS.AGENT_MULTI_LOGIN, constant: AGENT_MULTI_LOGIN },
1538+
{ ccEvent: CC_EVENTS.AGENT_STATE_CHANGE, constant: AGENT_STATE_CHANGE },
1539+
].forEach(({ ccEvent, constant }) => {
1540+
it(`should emit ${constant} on ${ccEvent}`, () => {
1541+
const sample = { foo: 'bar' };
1542+
messageCallback(JSON.stringify({type: ccEvent, data: sample}));
1543+
expect(emitSpy).toHaveBeenCalledWith(constant, sample);
1544+
});
1545+
});
1546+
});
15161547
});

packages/@webex/plugin-cc/test/unit/spec/services/task/TaskManager.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -489,14 +489,18 @@ describe('TaskManager', () => {
489489
};
490490

491491
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
492-
const taskUpdateTaskDataSpy = jest.spyOn(taskManager.getTask(taskId), 'updateTaskData');
492+
const task = taskManager.getTask(taskId);
493+
const taskUpdateTaskDataSpy = jest.spyOn(task, 'updateTaskData');
494+
const taskEmitSpy = jest.spyOn(task, 'emit');
495+
493496
webSocketManagerMock.emit('message', JSON.stringify(payload));
497+
494498
expect(taskUpdateTaskDataSpy).toHaveBeenCalledWith({
495499
...payload.data,
496500
isConsulted: false,
497501
});
498-
const task = taskManager.getTask(taskId);
499502
expect(task.data.isConsulted).toBe(false);
503+
expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_CONSULT_CREATED, task);
500504
});
501505

502506
it('handle AGENT_OFFER_CONTACT event', () => {
@@ -550,17 +554,21 @@ describe('TaskManager', () => {
550554
};
551555

552556
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
553-
taskManager.getTask(taskId).updateTaskData = jest.fn().mockImplementation((newData) => {
554-
taskManager.getTask(taskId).data = {...newData, isConsulted: true};
555-
return taskManager.getTask(taskId);
557+
const task = taskManager.getTask(taskId);
558+
task.updateTaskData = jest.fn().mockImplementation((newData) => {
559+
task.data = {...newData, isConsulted: true};
560+
return task;
556561
});
562+
const taskEmitSpy = jest.spyOn(task, 'emit');
557563

558564
webSocketManagerMock.emit('message', JSON.stringify(payload));
559-
expect(taskManager.getTask(taskId).updateTaskData).toHaveBeenCalledWith({
565+
566+
expect(task.updateTaskData).toHaveBeenCalledWith({
560567
...payload.data,
561568
isConsulted: true,
562569
});
563-
expect(taskManager.getTask(taskId).data.isConsulted).toBe(true);
570+
expect(task.data.isConsulted).toBe(true);
571+
expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_OFFER_CONSULT, task);
564572
});
565573

566574
it('should emit TASK_CONSULT_ACCEPTED event on AGENT_CONSULTING event', () => {
@@ -747,10 +755,13 @@ describe('TaskManager', () => {
747755
},
748756
};
749757

750-
taskManager.taskCollection[taskId] = taskManager.getTask(taskId);
758+
webSocketManagerMock.emit('message', JSON.stringify(initalPayload));
759+
const task = taskManager.getTask(taskId);
760+
const taskEmitSpy = jest.spyOn(task, 'emit');
751761

752762
webSocketManagerMock.emit('message', JSON.stringify(payload));
753763

764+
expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_WRAPPEDUP, task);
754765
expect(taskManager.getTask(taskId)).toBeUndefined();
755766
});
756767

@@ -1176,5 +1187,20 @@ describe('TaskManager', () => {
11761187
expect(unregisterSpy).not.toHaveBeenCalled();
11771188
expect(cleanUpCallSpy).not.toHaveBeenCalled();
11781189
});
1190+
1191+
// Tests for recording pause/resume events
1192+
['PAUSED', 'PAUSE_FAILED', 'RESUMED', 'RESUME_FAILED'].forEach((suffix) => {
1193+
const ccEvent = CC_EVENTS[`CONTACT_RECORDING_${suffix}`];
1194+
const taskEvent = TASK_EVENTS[`TASK_RECORDING_${suffix}`];
1195+
it(`should emit ${taskEvent} on ${ccEvent} event`, () => {
1196+
const payload = {data: {...initalPayload.data, type: ccEvent}};
1197+
webSocketManagerMock.emit('message', JSON.stringify(initalPayload)); // setup
1198+
const task = taskManager.getTask(taskId);
1199+
const spy = jest.spyOn(task, 'emit');
1200+
1201+
webSocketManagerMock.emit('message', JSON.stringify(payload));
1202+
expect(spy).toHaveBeenCalledWith(taskEvent, suffix.includes('FAILED') ? payload.data : task);
1203+
});
1204+
});
11791205
});
11801206

0 commit comments

Comments
 (0)