@webex/contact-center 3.10.0-next.7 → 3.10.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cc.js +11 -0
- package/dist/cc.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/config/types.js +2 -2
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Utils.js +90 -71
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/constants.js +17 -1
- package/dist/services/core/constants.js.map +1 -1
- package/dist/services/task/TaskManager.js +61 -36
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +33 -5
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/index.js +49 -58
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +2 -4
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +6 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/services/config/types.d.ts +4 -4
- package/dist/types/services/core/Utils.d.ts +32 -17
- package/dist/types/services/core/constants.d.ts +14 -0
- package/dist/types/services/task/TaskUtils.d.ts +17 -3
- package/dist/types/services/task/types.d.ts +25 -13
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/cc.ts +11 -0
- package/src/index.ts +1 -0
- package/src/services/config/types.ts +2 -2
- package/src/services/core/Utils.ts +101 -85
- package/src/services/core/constants.ts +16 -0
- package/src/services/task/TaskManager.ts +75 -28
- package/src/services/task/TaskUtils.ts +37 -5
- package/src/services/task/index.ts +54 -89
- package/src/services/task/types.ts +26 -13
- package/test/unit/spec/services/core/Utils.ts +262 -31
- package/test/unit/spec/services/task/TaskManager.ts +224 -1
- package/test/unit/spec/services/task/TaskUtils.ts +6 -6
- package/test/unit/spec/services/task/index.ts +283 -86
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -6,11 +6,10 @@ import WebexRequest from './WebexRequest';
|
|
|
6
6
|
import {
|
|
7
7
|
TaskData,
|
|
8
8
|
ConsultTransferPayLoad,
|
|
9
|
-
ConsultConferenceData,
|
|
10
|
-
consultConferencePayloadData,
|
|
11
9
|
CONSULT_TRANSFER_DESTINATION_TYPE,
|
|
12
10
|
Interaction,
|
|
13
11
|
} from '../task/types';
|
|
12
|
+
import {PARTICIPANT_TYPES, STATE_CONSULT} from './constants';
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Extracts common error details from a Webex request payload.
|
|
@@ -218,59 +217,118 @@ export const createErrDetailsObject = (errObj: WebexRequestPayload) => {
|
|
|
218
217
|
};
|
|
219
218
|
|
|
220
219
|
/**
|
|
221
|
-
*
|
|
220
|
+
* Gets the consulted agent ID from the media object by finding the agent
|
|
221
|
+
* in the consult media participants (excluding the current agent).
|
|
222
222
|
*
|
|
223
|
-
*
|
|
224
|
-
* -
|
|
225
|
-
*
|
|
226
|
-
|
|
227
|
-
|
|
223
|
+
* @param media - The media object from the interaction
|
|
224
|
+
* @param agentId - The current agent's ID to exclude from the search
|
|
225
|
+
* @returns The consulted agent ID, or empty string if none found
|
|
226
|
+
*/
|
|
227
|
+
export const getConsultedAgentId = (media: Interaction['media'], agentId: string): string => {
|
|
228
|
+
let consultParticipants: string[] = [];
|
|
229
|
+
let consultedParticipantId = '';
|
|
230
|
+
|
|
231
|
+
Object.keys(media).forEach((key) => {
|
|
232
|
+
if (media[key].mType === STATE_CONSULT) {
|
|
233
|
+
consultParticipants = media[key].participants;
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
if (consultParticipants.includes(agentId)) {
|
|
238
|
+
const id = consultParticipants.find((participant) => participant !== agentId);
|
|
239
|
+
consultedParticipantId = id || consultedParticipantId;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return consultedParticipantId;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Gets the destination agent ID for CBT (Capacity Based Team) scenarios.
|
|
247
|
+
* CBT refers to teams created in Control Hub with capacity-based routing
|
|
248
|
+
* (as opposed to agent-based routing). This handles cases where the consulted
|
|
249
|
+
* participant is not directly in participants but can be found by matching
|
|
250
|
+
* the dial number (dn).
|
|
228
251
|
*
|
|
229
|
-
* @param
|
|
230
|
-
* @
|
|
252
|
+
* @param interaction - The interaction object
|
|
253
|
+
* @param consultingAgent - The consulting agent identifier
|
|
254
|
+
* @returns The destination agent ID for CBT scenarios, or empty string if none found
|
|
231
255
|
*/
|
|
256
|
+
export const getDestAgentIdForCBT = (interaction: Interaction, consultingAgent: string): string => {
|
|
257
|
+
const participants = interaction.participants;
|
|
258
|
+
let destAgentIdForCBT = '';
|
|
259
|
+
|
|
260
|
+
// Check if this is a CBT scenario (consultingAgent exists but not directly in participants)
|
|
261
|
+
if (consultingAgent && !participants[consultingAgent]) {
|
|
262
|
+
const foundEntry = Object.entries(participants).find(
|
|
263
|
+
([, participant]: [string, Interaction['participants'][string]]) => {
|
|
264
|
+
return (
|
|
265
|
+
participant.pType.toLowerCase() === PARTICIPANT_TYPES.DN &&
|
|
266
|
+
participant.type === PARTICIPANT_TYPES.AGENT &&
|
|
267
|
+
participant.dn === consultingAgent
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
if (foundEntry) {
|
|
273
|
+
destAgentIdForCBT = foundEntry[0];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return destAgentIdForCBT;
|
|
278
|
+
};
|
|
279
|
+
|
|
232
280
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
281
|
+
* Calculates the destination agent ID for consult operations.
|
|
282
|
+
*
|
|
283
|
+
* @param interaction - The interaction object
|
|
284
|
+
* @param agentId - The current agent's ID
|
|
285
|
+
* @returns The destination agent ID
|
|
236
286
|
*/
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
)
|
|
287
|
+
export const calculateDestAgentId = (interaction: Interaction, agentId: string): string => {
|
|
288
|
+
const consultingAgent = getConsultedAgentId(interaction.media, agentId);
|
|
289
|
+
|
|
290
|
+
// Check if this is a CBT (Capacity Based Team) scenario
|
|
291
|
+
// If not CBT, the function will return empty string and we'll use the normal flow
|
|
292
|
+
const destAgentIdCBT = getDestAgentIdForCBT(interaction, consultingAgent);
|
|
293
|
+
if (destAgentIdCBT) {
|
|
294
|
+
return destAgentIdCBT;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return interaction.participants[consultingAgent]?.type === PARTICIPANT_TYPES.EP_DN
|
|
298
|
+
? interaction.participants[consultingAgent]?.epId
|
|
299
|
+
: interaction.participants[consultingAgent]?.id;
|
|
244
300
|
};
|
|
245
301
|
|
|
246
302
|
/**
|
|
247
|
-
*
|
|
248
|
-
* non-customer participant that is not the current agent and is not in wrap-up state.
|
|
303
|
+
* Calculates the destination agent ID for fetching destination type.
|
|
249
304
|
*
|
|
250
|
-
* @param
|
|
251
|
-
* @param agentId - The current agent's ID
|
|
252
|
-
* @returns The destination agent ID
|
|
305
|
+
* @param interaction - The interaction object
|
|
306
|
+
* @param agentId - The current agent's ID
|
|
307
|
+
* @returns The destination agent ID for determining destination type
|
|
253
308
|
*/
|
|
254
|
-
export const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
309
|
+
export const calculateDestType = (interaction: Interaction, agentId: string): string => {
|
|
310
|
+
const consultingAgent = getConsultedAgentId(interaction.media, agentId);
|
|
311
|
+
|
|
312
|
+
// Check if this is a CBT (Capacity Based Team) scenario, otherwise use consultingAgent
|
|
313
|
+
const destAgentIdCBT = getDestAgentIdForCBT(interaction, consultingAgent);
|
|
314
|
+
const destinationaegntId = destAgentIdCBT || consultingAgent;
|
|
315
|
+
const destAgentType = destinationaegntId
|
|
316
|
+
? interaction.participants[destinationaegntId]?.pType
|
|
317
|
+
: undefined;
|
|
318
|
+
if (destAgentType) {
|
|
319
|
+
if (destAgentType === 'DN') {
|
|
320
|
+
return CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER;
|
|
321
|
+
}
|
|
322
|
+
if (destAgentType === 'EP-DN') {
|
|
323
|
+
return CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT;
|
|
324
|
+
}
|
|
325
|
+
// Keep the existing destinationType if it's something else (like "agent" or "Agent")
|
|
326
|
+
// Convert "Agent" to lowercase for consistency
|
|
327
|
+
|
|
328
|
+
return destAgentType.toLowerCase();
|
|
271
329
|
}
|
|
272
330
|
|
|
273
|
-
return
|
|
331
|
+
return CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
|
|
274
332
|
};
|
|
275
333
|
|
|
276
334
|
export const deriveConsultTransferDestinationType = (
|
|
@@ -286,45 +344,3 @@ export const deriveConsultTransferDestinationType = (
|
|
|
286
344
|
|
|
287
345
|
return CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
|
|
288
346
|
};
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Builds consult conference parameter data using EXACT Agent Desktop logic.
|
|
292
|
-
* This matches the Agent Desktop's consultConference implementation exactly.
|
|
293
|
-
*
|
|
294
|
-
* @param dataPassed - Original consultation data from Agent Desktop format
|
|
295
|
-
* @param interactionIdPassed - The interaction ID for the task
|
|
296
|
-
* @returns Object with interactionId and ConsultConferenceData matching Agent Desktop format
|
|
297
|
-
* @public
|
|
298
|
-
*/
|
|
299
|
-
export const buildConsultConferenceParamData = (
|
|
300
|
-
dataPassed: consultConferencePayloadData,
|
|
301
|
-
interactionIdPassed: string
|
|
302
|
-
): {interactionId: string; data: ConsultConferenceData} => {
|
|
303
|
-
const data: ConsultConferenceData = {
|
|
304
|
-
// Include agentId if present in input data
|
|
305
|
-
...('agentId' in dataPassed && {agentId: dataPassed.agentId}),
|
|
306
|
-
// Handle destAgentId from consultation data
|
|
307
|
-
to: dataPassed.destAgentId,
|
|
308
|
-
destinationType: '',
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
// Agent Desktop destination type logic
|
|
312
|
-
if ('destinationType' in dataPassed) {
|
|
313
|
-
if (dataPassed.destinationType === 'DN') {
|
|
314
|
-
data.destinationType = CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER;
|
|
315
|
-
} else if (dataPassed.destinationType === 'EP_DN') {
|
|
316
|
-
data.destinationType = CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT;
|
|
317
|
-
} else {
|
|
318
|
-
// Keep the existing destinationType if it's something else (like "agent" or "Agent")
|
|
319
|
-
// Convert "Agent" to lowercase for consistency
|
|
320
|
-
data.destinationType = dataPassed.destinationType.toLowerCase();
|
|
321
|
-
}
|
|
322
|
-
} else {
|
|
323
|
-
data.destinationType = CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return {
|
|
327
|
-
interactionId: interactionIdPassed,
|
|
328
|
-
data,
|
|
329
|
-
};
|
|
330
|
-
};
|
|
@@ -64,6 +64,22 @@ export const CONNECTIVITY_CHECK_INTERVAL = 5000;
|
|
|
64
64
|
*/
|
|
65
65
|
export const CLOSE_SOCKET_TIMEOUT = 16000;
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Constants for participant types, destination types, and interaction states
|
|
69
|
+
* @ignore
|
|
70
|
+
*/
|
|
71
|
+
export const PARTICIPANT_TYPES = {
|
|
72
|
+
/** Participant type for Entry Point Dial Number */
|
|
73
|
+
EP_DN: 'EpDn',
|
|
74
|
+
/** Participant type for dial number */
|
|
75
|
+
DN: 'dn',
|
|
76
|
+
/** Participant type for Agent */
|
|
77
|
+
AGENT: 'Agent',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** Interaction state for consultation */
|
|
81
|
+
export const STATE_CONSULT = 'consult';
|
|
82
|
+
|
|
67
83
|
// Method names for core services
|
|
68
84
|
export const METHODS = {
|
|
69
85
|
// WebexRequest methods
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
getIsConferenceInProgress,
|
|
18
18
|
isParticipantInMainInteraction,
|
|
19
19
|
isPrimary,
|
|
20
|
+
isSecondaryEpDnAgent,
|
|
20
21
|
} from './TaskUtils';
|
|
21
22
|
|
|
22
23
|
/** @internal */
|
|
@@ -129,11 +130,6 @@ export default class TaskManager extends EventEmitter {
|
|
|
129
130
|
interactionId: payload.data.interactionId,
|
|
130
131
|
});
|
|
131
132
|
|
|
132
|
-
// Pre-calculate isConferenceInProgress for the initial task data
|
|
133
|
-
const simulatedTaskForAgentContact = {
|
|
134
|
-
data: {...payload.data},
|
|
135
|
-
} as ITask;
|
|
136
|
-
|
|
137
133
|
task = new Task(
|
|
138
134
|
this.contact,
|
|
139
135
|
this.webCallingService,
|
|
@@ -141,7 +137,7 @@ export default class TaskManager extends EventEmitter {
|
|
|
141
137
|
...payload.data,
|
|
142
138
|
wrapUpRequired:
|
|
143
139
|
payload.data.interaction?.participants?.[this.agentId]?.isWrapUp || false,
|
|
144
|
-
isConferenceInProgress: getIsConferenceInProgress(
|
|
140
|
+
isConferenceInProgress: getIsConferenceInProgress(payload.data),
|
|
145
141
|
},
|
|
146
142
|
this.wrapupData,
|
|
147
143
|
this.agentId
|
|
@@ -252,13 +248,22 @@ export default class TaskManager extends EventEmitter {
|
|
|
252
248
|
break;
|
|
253
249
|
}
|
|
254
250
|
case CC_EVENTS.CONTACT_ENDED:
|
|
251
|
+
// Update task data
|
|
255
252
|
task = this.updateTaskData(task, {
|
|
256
253
|
...payload.data,
|
|
257
|
-
wrapUpRequired:
|
|
254
|
+
wrapUpRequired:
|
|
255
|
+
payload.data.interaction.state !== 'new' &&
|
|
256
|
+
!isSecondaryEpDnAgent(payload.data.interaction),
|
|
258
257
|
});
|
|
258
|
+
|
|
259
|
+
// Handle cleanup based on whether task should be deleted
|
|
259
260
|
this.handleTaskCleanup(task);
|
|
260
|
-
|
|
261
|
+
|
|
262
|
+
task?.emit(TASK_EVENTS.TASK_END, task);
|
|
261
263
|
|
|
264
|
+
break;
|
|
265
|
+
case CC_EVENTS.CONTACT_MERGED:
|
|
266
|
+
task = this.handleContactMerged(task, payload.data);
|
|
262
267
|
break;
|
|
263
268
|
case CC_EVENTS.AGENT_CONTACT_HELD:
|
|
264
269
|
// As soon as the main interaction is held, we need to emit TASK_HOLD
|
|
@@ -380,32 +385,22 @@ export default class TaskManager extends EventEmitter {
|
|
|
380
385
|
} else {
|
|
381
386
|
this.removeTaskFromCollection(task);
|
|
382
387
|
}
|
|
383
|
-
task
|
|
388
|
+
task.emit(TASK_EVENTS.TASK_CONFERENCE_ENDED, task);
|
|
384
389
|
break;
|
|
385
390
|
case CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE: {
|
|
386
|
-
// Participant joined conference - update task state with participant information and emit event
|
|
387
|
-
// Pre-calculate isConferenceInProgress with updated data to avoid double update
|
|
388
|
-
const simulatedTaskForJoin = {
|
|
389
|
-
...task,
|
|
390
|
-
data: {...task.data, ...payload.data},
|
|
391
|
-
};
|
|
392
391
|
task = this.updateTaskData(task, {
|
|
393
392
|
...payload.data,
|
|
394
|
-
isConferenceInProgress: getIsConferenceInProgress(
|
|
393
|
+
isConferenceInProgress: getIsConferenceInProgress(payload.data),
|
|
395
394
|
});
|
|
396
395
|
task.emit(TASK_EVENTS.TASK_PARTICIPANT_JOINED, task);
|
|
397
396
|
break;
|
|
398
397
|
}
|
|
399
398
|
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE: {
|
|
400
399
|
// Conference ended - update task state and emit event
|
|
401
|
-
|
|
402
|
-
const simulatedTaskForLeft = {
|
|
403
|
-
...task,
|
|
404
|
-
data: {...task.data, ...payload.data},
|
|
405
|
-
};
|
|
400
|
+
|
|
406
401
|
task = this.updateTaskData(task, {
|
|
407
402
|
...payload.data,
|
|
408
|
-
isConferenceInProgress: getIsConferenceInProgress(
|
|
403
|
+
isConferenceInProgress: getIsConferenceInProgress(payload.data),
|
|
409
404
|
});
|
|
410
405
|
if (checkParticipantNotInInteraction(task, this.agentId)) {
|
|
411
406
|
if (
|
|
@@ -441,13 +436,10 @@ export default class TaskManager extends EventEmitter {
|
|
|
441
436
|
task = this.updateTaskData(task, payload.data);
|
|
442
437
|
task.emit(TASK_EVENTS.TASK_CONFERENCE_TRANSFER_FAILED, task);
|
|
443
438
|
break;
|
|
444
|
-
case CC_EVENTS.CONSULTED_PARTICIPANT_MOVING:
|
|
445
|
-
// Participant is being moved/transferred - update task state with movement info
|
|
446
|
-
task = this.updateTaskData(task, payload.data);
|
|
447
|
-
break;
|
|
448
439
|
case CC_EVENTS.PARTICIPANT_POST_CALL_ACTIVITY:
|
|
449
440
|
// Post-call activity for participant - update task state with activity details
|
|
450
441
|
task = this.updateTaskData(task, payload.data);
|
|
442
|
+
task.emit(TASK_EVENTS.TASK_POST_CALL_ACTIVITY, task);
|
|
451
443
|
break;
|
|
452
444
|
default:
|
|
453
445
|
break;
|
|
@@ -487,6 +479,54 @@ export default class TaskManager extends EventEmitter {
|
|
|
487
479
|
}
|
|
488
480
|
}
|
|
489
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Handles CONTACT_MERGED event logic
|
|
484
|
+
* @param task - The task to process
|
|
485
|
+
* @param taskData - The task data from the event payload
|
|
486
|
+
* @returns Updated or newly created task
|
|
487
|
+
* @private
|
|
488
|
+
*/
|
|
489
|
+
private handleContactMerged(task: ITask, taskData: TaskData): ITask {
|
|
490
|
+
if (taskData.childInteractionId) {
|
|
491
|
+
// remove the child task from collection
|
|
492
|
+
this.removeTaskFromCollection(this.taskCollection[taskData.childInteractionId]);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (this.taskCollection[taskData.interactionId]) {
|
|
496
|
+
LoggerProxy.log(`Got CONTACT_MERGED: Task already exists in collection`, {
|
|
497
|
+
module: TASK_MANAGER_FILE,
|
|
498
|
+
method: METHODS.REGISTER_TASK_LISTENERS,
|
|
499
|
+
interactionId: taskData.interactionId,
|
|
500
|
+
});
|
|
501
|
+
// update the task data
|
|
502
|
+
task = this.updateTaskData(task, taskData);
|
|
503
|
+
} else {
|
|
504
|
+
// Case2 : Task is not present in taskCollection
|
|
505
|
+
LoggerProxy.log(`Got CONTACT_MERGED : Creating new task in taskManager`, {
|
|
506
|
+
module: TASK_MANAGER_FILE,
|
|
507
|
+
method: METHODS.REGISTER_TASK_LISTENERS,
|
|
508
|
+
interactionId: taskData.interactionId,
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
task = new Task(
|
|
512
|
+
this.contact,
|
|
513
|
+
this.webCallingService,
|
|
514
|
+
{
|
|
515
|
+
...taskData,
|
|
516
|
+
wrapUpRequired: taskData.interaction?.participants?.[this.agentId]?.isWrapUp || false,
|
|
517
|
+
isConferenceInProgress: getIsConferenceInProgress(taskData),
|
|
518
|
+
},
|
|
519
|
+
this.wrapupData,
|
|
520
|
+
this.agentId
|
|
521
|
+
);
|
|
522
|
+
this.taskCollection[taskData.interactionId] = task;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
this.emit(TASK_EVENTS.TASK_MERGED, task);
|
|
526
|
+
|
|
527
|
+
return task;
|
|
528
|
+
}
|
|
529
|
+
|
|
490
530
|
private removeTaskFromCollection(task: ITask) {
|
|
491
531
|
if (task?.data?.interactionId) {
|
|
492
532
|
delete this.taskCollection[task.data.interactionId];
|
|
@@ -498,7 +538,13 @@ export default class TaskManager extends EventEmitter {
|
|
|
498
538
|
}
|
|
499
539
|
}
|
|
500
540
|
|
|
541
|
+
/**
|
|
542
|
+
* Handles cleanup of task resources including Desktop/WebRTC call cleanup and task removal
|
|
543
|
+
* @param task - The task to clean up
|
|
544
|
+
* @private
|
|
545
|
+
*/
|
|
501
546
|
private handleTaskCleanup(task: ITask) {
|
|
547
|
+
// Clean up Desktop/WebRTC calling resources for browser-based telephony tasks
|
|
502
548
|
if (
|
|
503
549
|
this.webCallingService.loginOption === LoginOption.BROWSER &&
|
|
504
550
|
task.data.interaction.mediaType === 'telephony'
|
|
@@ -506,8 +552,9 @@ export default class TaskManager extends EventEmitter {
|
|
|
506
552
|
task.unregisterWebCallListeners();
|
|
507
553
|
this.webCallingService.cleanUpCall();
|
|
508
554
|
}
|
|
509
|
-
|
|
510
|
-
|
|
555
|
+
|
|
556
|
+
if (task.data.interaction.state === 'new' || isSecondaryEpDnAgent(task.data.interaction)) {
|
|
557
|
+
// Only remove tasks in 'new' state or isSecondaryEpDnAgent immediately. For other states,
|
|
511
558
|
// retain tasks until they complete wrap-up, unless the task disconnected before being answered.
|
|
512
559
|
this.removeTaskFromCollection(task);
|
|
513
560
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable import/prefer-default-export */
|
|
2
|
-
import {ITask} from './types';
|
|
2
|
+
import {Interaction, ITask, TaskData} from './types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Determines if the given agent is the primary agent (owner) of the task
|
|
@@ -53,13 +53,13 @@ export const checkParticipantNotInInteraction = (task: ITask, agentId: string):
|
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Determines if a conference is currently in progress based on the number of active agent participants
|
|
56
|
-
* @param
|
|
56
|
+
* @param TaskData - The payLoad data to check for conference status
|
|
57
57
|
* @returns true if there are 2 or more active agent participants in the main call, false otherwise
|
|
58
58
|
*/
|
|
59
|
-
export const getIsConferenceInProgress = (
|
|
60
|
-
const mediaMainCall =
|
|
59
|
+
export const getIsConferenceInProgress = (data: TaskData): boolean => {
|
|
60
|
+
const mediaMainCall = data.interaction.media?.[data?.interactionId];
|
|
61
61
|
const participantsInMainCall = new Set(mediaMainCall?.participants);
|
|
62
|
-
const participants =
|
|
62
|
+
const participants = data.interaction.participants;
|
|
63
63
|
|
|
64
64
|
const agentParticipants = new Set();
|
|
65
65
|
if (participantsInMainCall.size > 0) {
|
|
@@ -79,3 +79,35 @@ export const getIsConferenceInProgress = (task: ITask): boolean => {
|
|
|
79
79
|
|
|
80
80
|
return agentParticipants.size >= 2;
|
|
81
81
|
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Checks if the current agent is a secondary agent in a consultation scenario.
|
|
85
|
+
* Secondary agents are those who were consulted (not the original call owner).
|
|
86
|
+
* @param task - The task object containing interaction details
|
|
87
|
+
* @returns true if this is a secondary agent (consulted party), false otherwise
|
|
88
|
+
*/
|
|
89
|
+
export const isSecondaryAgent = (interaction: Interaction): boolean => {
|
|
90
|
+
if (!interaction.callProcessingDetails) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
interaction.callProcessingDetails.relationshipType === 'consult' &&
|
|
96
|
+
!!interaction.callProcessingDetails.parentInteractionId &&
|
|
97
|
+
interaction.callProcessingDetails.parentInteractionId !== interaction.interactionId
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Checks if the current agent is a secondary EP-DN (Entry Point Dial Number) agent.
|
|
103
|
+
* This is specifically for telephony consultations to external numbers/entry points.
|
|
104
|
+
* @param task - The task object containing interaction details
|
|
105
|
+
* @returns true if this is a secondary EP-DN agent in telephony consultation, false otherwise
|
|
106
|
+
*/
|
|
107
|
+
export const isSecondaryEpDnAgent = (interaction: Interaction): boolean => {
|
|
108
|
+
if (!interaction) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return interaction.mediaType === 'telephony' && isSecondaryAgent(interaction);
|
|
113
|
+
};
|