diff --git a/docs/samples/contact-center/app.js b/docs/samples/contact-center/app.js index da4df9a40d8..9a444e3b885 100644 --- a/docs/samples/contact-center/app.js +++ b/docs/samples/contact-center/app.js @@ -164,7 +164,13 @@ function registerTaskListeners(task) { task.on('task:media', (track) => { document.getElementById('remote-audio').srcObject = new MediaStream([track]); }); - task.on('task:end', (task) => { + task.on('task:end', (wrapupData) => { + if (!wrapupData.wrapupRequired) { + answerElm.disabled = true; + declineElm.disabled = true; + console.log('Call ended without call being answered'); + } + incomingDetailsElm.innerText = ''; if (!endElm.disabled) { console.info('Call ended successfully by the external user'); updateButtonsPostEndCall(); diff --git a/packages/@webex/plugin-cc/src/services/config/types.ts b/packages/@webex/plugin-cc/src/services/config/types.ts index c3e165f3dbd..6aa477580d5 100644 --- a/packages/@webex/plugin-cc/src/services/config/types.ts +++ b/packages/@webex/plugin-cc/src/services/config/types.ts @@ -23,6 +23,7 @@ export const CC_EVENTS = { AGENT_OFFER_CONTACT: 'AgentOfferContact', AGENT_CONTACT_ASSIGNED: 'AgentContactAssigned', AGENT_CONTACT_ASSIGN_FAILED: 'AgentContactAssignFailed', + AGENT_CONTACT_OFFER_RONA: 'AgentOfferContactRona', AGENT_CONTACT_HELD: 'AgentContactHeld', AGENT_CONTACT_HOLD_FAILED: 'AgentContactHoldFailed', AGENT_CONTACT_UNHELD: 'AgentContactUnheld', diff --git a/packages/@webex/plugin-cc/src/services/task/TaskManager.ts b/packages/@webex/plugin-cc/src/services/task/TaskManager.ts index deb89ea9290..503f484d356 100644 --- a/packages/@webex/plugin-cc/src/services/task/TaskManager.ts +++ b/packages/@webex/plugin-cc/src/services/task/TaskManager.ts @@ -72,16 +72,20 @@ export default class TaskManager extends EventEmitter { this.currentTask = this.currentTask.updateTaskData(payload.data); this.currentTask.emit(TASK_EVENTS.TASK_ASSIGNED, this.currentTask); break; + case CC_EVENTS.AGENT_CONTACT_OFFER_RONA: case CC_EVENTS.CONTACT_ENDED: - this.emit(TASK_EVENTS.TASK_UNASSIGNED, this.currentTask); - if (this.webCallingService.loginOption === LoginOption.BROWSER) { - this.currentTask.unregisterWebCallListeners(); - this.webCallingService.unregisterCallListeners(); + if (this.currentTask.data.interaction.state === 'new') { + this.currentTask.emit(TASK_EVENTS.TASK_END, {wrapupRequired: false}); + if (this.webCallingService.loginOption === LoginOption.BROWSER) { + this.currentTask.unregisterWebCallListeners(); + this.webCallingService.unregisterCallListeners(); + } + this.removeCurrentTaskFromCollection(); } break; case CC_EVENTS.AGENT_WRAPUP: this.currentTask = this.currentTask.updateTaskData(payload.data); - this.currentTask.emit(TASK_EVENTS.TASK_END, this.currentTask); + this.currentTask.emit(TASK_EVENTS.TASK_END, {wrapupRequired: true}); break; case CC_EVENTS.AGENT_WRAPPEDUP: this.removeCurrentTaskFromCollection(); diff --git a/packages/@webex/plugin-cc/src/services/task/constants.ts b/packages/@webex/plugin-cc/src/services/task/constants.ts index 2d0dede27de..96d1a933b20 100644 --- a/packages/@webex/plugin-cc/src/services/task/constants.ts +++ b/packages/@webex/plugin-cc/src/services/task/constants.ts @@ -8,7 +8,7 @@ export const CONSULT_END = '/consult/end'; export const TRANSFER = '/transfer'; export const CONSULT_TRANSFER = '/consult/transfer'; export const PAUSE = '/record/pause'; -export const RESUME = 'record/resume'; +export const RESUME = '/record/resume'; export const WRAPUP = '/wrapup'; export const END = '/end'; export const TASK_MANAGER_FILE = 'taskManager'; diff --git a/packages/@webex/plugin-cc/src/services/task/contact.ts b/packages/@webex/plugin-cc/src/services/task/contact.ts index 4abd98aad34..c3b261f5118 100644 --- a/packages/@webex/plugin-cc/src/services/task/contact.ts +++ b/packages/@webex/plugin-cc/src/services/task/contact.ts @@ -10,6 +10,7 @@ import { END, HOLD, PAUSE, + RESUME, TASK_API, TASK_MESSAGE_TYPE, TRANSFER, @@ -121,7 +122,7 @@ export default function routingContact(aqm: AqmReqs) { */ resumeRecording: aqm.req( (p: {interactionId: string; data: Contact.ResumeRecordingPayload}) => ({ - url: `${TASK_API}${p.interactionId}/record/resume`, + url: `${TASK_API}${p.interactionId}${RESUME}`, data: p.data, host: WCC_API_GATEWAY, err, diff --git a/packages/@webex/plugin-cc/src/services/task/types.ts b/packages/@webex/plugin-cc/src/services/task/types.ts index ea38cc6e2c1..de251e1748c 100644 --- a/packages/@webex/plugin-cc/src/services/task/types.ts +++ b/packages/@webex/plugin-cc/src/services/task/types.ts @@ -362,10 +362,9 @@ export interface ITask extends EventEmitter { * task.decline(); * ``` */ - decline(taskId: TaskId): Promise; + decline(): Promise; /** * This is used to hold the task. - * @param taskId * @returns Promise * @example * ``` diff --git a/packages/@webex/plugin-cc/test/unit/spec/services/task/TaskManager.ts b/packages/@webex/plugin-cc/test/unit/spec/services/task/TaskManager.ts index 894e4cd965c..73aea1f380b 100644 --- a/packages/@webex/plugin-cc/test/unit/spec/services/task/TaskManager.ts +++ b/packages/@webex/plugin-cc/test/unit/spec/services/task/TaskManager.ts @@ -10,15 +10,6 @@ import { TASK_EVENTS } from '../../../../../src/services/task/types'; import WebCallingService from '../../../../../src/services/WebCallingService'; import config from '../../../../../src/config'; -jest.mock('./../../../../../src/services/task', () => { - return jest.fn().mockImplementation(() => { - return { - updateTaskData: jest.fn().mockReturnThis(), - emit: jest.fn() - }; - }); -}); - describe('TaskManager', () => { let mockCall; let webSocketManagerMock; @@ -76,13 +67,6 @@ describe('TaskManager', () => { onSpy = jest.spyOn(webCallingService, 'on'); taskManager = new TaskManager(contactMock, webCallingService, webSocketManagerMock); - taskManager.currentTask = { - accept: jest.fn(), - decline: jest.fn(), - updateTaskData: jest.fn(), - unregisterWebCallListeners: jest.fn(), - data: taskDataMock - } taskManager.call = mockCall; }); @@ -91,6 +75,7 @@ describe('TaskManager', () => { }); it('should initialize TaskManager and register listeners', () => { + webSocketManagerMock.emit('message', JSON.stringify({data: taskDataMock})); const incomingCallCb = onSpy.mock.calls[0][1]; const taskEmitSpy = jest.spyOn(taskManager, 'emit'); @@ -126,7 +111,6 @@ describe('TaskManager', () => { webSocketManagerMock.emit('message', JSON.stringify(payload)); - expect(Task).toHaveBeenCalledWith(contactMock, webCallingService , payload.data); expect(taskIncomingSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_INCOMING, taskManager.currentTask); expect(taskManager.getTask(payload.data.interactionId)).toBe(taskManager.currentTask); expect(taskManager.getAllTasks()).toHaveProperty(payload.data.interactionId); @@ -178,7 +162,6 @@ describe('TaskManager', () => { webSocketManagerMock.emit('message', JSON.stringify(payload)); - expect(Task).toHaveBeenCalledWith(contactMock, webCallingService , payload.data); expect(taskIncomingSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_INCOMING, taskManager.currentTask); expect(taskManager.getTask(payload.data.interactionId)).toBe(taskManager.currentTask); expect(taskManager.getAllTasks()).toHaveProperty(payload.data.interactionId); @@ -264,7 +247,10 @@ describe('TaskManager', () => { }); it('test call listeners being switched off on call end', () => { - const taskEmitSpy = jest.spyOn(taskManager, 'emit'); + webSocketManagerMock.emit('message', JSON.stringify({data: taskDataMock})); + + const taskEmitSpy = jest.spyOn(taskManager.currentTask, 'emit'); + const webCallListenerSpy = jest.spyOn(taskManager.currentTask, 'unregisterWebCallListeners'); const webCallingServiceOffSpy = jest.spyOn(webCallingService, 'off'); const callOffSpy = jest.spyOn(mockCall, 'off'); const payload = { @@ -273,7 +259,7 @@ describe('TaskManager', () => { agentId: "723a8ffb-a26e-496d-b14a-ff44fb83b64f", eventTime: 1733211616959, eventType: "RoutingMessage", - interaction: {}, + interaction: {"state": "new"}, interactionId: taskId, orgId: "6ecef209-9a34-4ed1-a07a-7ddd1dbe925a", trackingId: "575c0ec2-618c-42af-a61c-53aeb0a221ee", @@ -284,14 +270,15 @@ describe('TaskManager', () => { }, }; + taskManager.currentTask.data = payload.data; webSocketManagerMock.emit('message', JSON.stringify(payload)); - expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_UNASSIGNED, taskManager.currentTask); - expect(taskManager.currentTask.unregisterWebCallListeners).toHaveBeenCalledWith(); + expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, {wrapupRequired: false}); + expect(webCallListenerSpy).toHaveBeenCalledWith(); expect(callOffSpy).toHaveBeenCalledWith(CALL_EVENT_KEYS.REMOTE_MEDIA, callOffSpy.mock.calls[0][1]); taskManager.unregisterIncomingCallEvent(); - expect(webCallingServiceOffSpy).toHaveBeenCalledWith(LINE_EVENTS.INCOMING_CALL, webCallingServiceOffSpy.mock.calls[0][1]); + expect(webCallingServiceOffSpy).toHaveBeenCalledWith(LINE_EVENTS.INCOMING_CALL, webCallingServiceOffSpy.mock.calls[1][1]); }); it('should emit TASK_END event on AGENT_WRAPUP event', () => { @@ -332,11 +319,12 @@ describe('TaskManager', () => { }; const taskEmitSpy = jest.spyOn(taskManager.currentTask, 'emit'); + const updateTaskDataSpy = jest.spyOn(taskManager.currentTask, 'updateTaskData'); webSocketManagerMock.emit('message', JSON.stringify(wrapupPayload)); - expect(taskManager.currentTask.updateTaskData).toHaveBeenCalledWith(wrapupPayload.data); - expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, taskManager.currentTask); + expect(updateTaskDataSpy).toHaveBeenCalledWith(wrapupPayload.data); + expect(taskEmitSpy).toHaveBeenCalledWith(TASK_EVENTS.TASK_END, {wrapupRequired: true}); }); it('should remove currentTask from taskCollection on AGENT_WRAPPEDUP event', () => {