@webex/contact-center 3.10.0-next.9 → 3.10.0-wxc-disconnect.1
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 +1 -12
- 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 +71 -90
- package/dist/services/core/Utils.js.map +1 -1
- package/dist/services/core/constants.js +1 -17
- package/dist/services/core/constants.js.map +1 -1
- package/dist/services/task/TaskManager.js +17 -89
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/constants.js +1 -20
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/index.js +98 -123
- package/dist/services/task/index.js.map +1 -1
- package/dist/services/task/types.js +4 -2
- package/dist/services/task/types.js.map +1 -1
- package/dist/types/cc.d.ts +0 -6
- 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 +17 -32
- package/dist/types/services/core/constants.d.ts +0 -14
- package/dist/types/services/task/constants.d.ts +0 -17
- package/dist/types/services/task/index.d.ts +2 -41
- package/dist/types/services/task/types.d.ts +33 -133
- package/dist/webex.js +1 -1
- package/package.json +9 -9
- package/src/cc.ts +1 -12
- package/src/index.ts +0 -1
- package/src/services/config/types.ts +2 -2
- package/src/services/core/Utils.ts +85 -101
- package/src/services/core/constants.ts +0 -16
- package/src/services/task/TaskManager.ts +15 -112
- package/src/services/task/constants.ts +0 -19
- package/src/services/task/index.ts +82 -108
- package/src/services/task/types.ts +33 -142
- package/test/unit/spec/services/core/Utils.ts +31 -262
- package/test/unit/spec/services/task/TaskManager.ts +6 -620
- package/test/unit/spec/services/task/index.ts +79 -502
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
- package/dist/services/task/TaskUtils.js +0 -104
- package/dist/services/task/TaskUtils.js.map +0 -1
- package/dist/types/services/task/TaskUtils.d.ts +0 -42
- package/src/services/task/TaskUtils.ts +0 -113
- package/test/unit/spec/services/task/TaskUtils.ts +0 -131
|
@@ -12,13 +12,6 @@ import LoggerProxy from '../../logger-proxy';
|
|
|
12
12
|
import Task from '.';
|
|
13
13
|
import MetricsManager from '../../metrics/MetricsManager';
|
|
14
14
|
import {METRIC_EVENT_NAMES} from '../../metrics/constants';
|
|
15
|
-
import {
|
|
16
|
-
checkParticipantNotInInteraction,
|
|
17
|
-
getIsConferenceInProgress,
|
|
18
|
-
isParticipantInMainInteraction,
|
|
19
|
-
isPrimary,
|
|
20
|
-
isSecondaryEpDnAgent,
|
|
21
|
-
} from './TaskUtils';
|
|
22
15
|
|
|
23
16
|
/** @internal */
|
|
24
17
|
export default class TaskManager extends EventEmitter {
|
|
@@ -129,15 +122,14 @@ export default class TaskManager extends EventEmitter {
|
|
|
129
122
|
method: METHODS.REGISTER_TASK_LISTENERS,
|
|
130
123
|
interactionId: payload.data.interactionId,
|
|
131
124
|
});
|
|
132
|
-
|
|
133
125
|
task = new Task(
|
|
134
126
|
this.contact,
|
|
135
127
|
this.webCallingService,
|
|
136
128
|
{
|
|
137
129
|
...payload.data,
|
|
138
130
|
wrapUpRequired:
|
|
139
|
-
payload.data.interaction?.participants?.[
|
|
140
|
-
|
|
131
|
+
payload.data.interaction?.participants?.[payload.data.agentId]?.isWrapUp ||
|
|
132
|
+
false,
|
|
141
133
|
},
|
|
142
134
|
this.wrapupData,
|
|
143
135
|
this.agentId
|
|
@@ -168,7 +160,6 @@ export default class TaskManager extends EventEmitter {
|
|
|
168
160
|
}
|
|
169
161
|
}
|
|
170
162
|
break;
|
|
171
|
-
|
|
172
163
|
case CC_EVENTS.AGENT_CONTACT_RESERVED:
|
|
173
164
|
task = new Task(
|
|
174
165
|
this.contact,
|
|
@@ -248,22 +239,13 @@ export default class TaskManager extends EventEmitter {
|
|
|
248
239
|
break;
|
|
249
240
|
}
|
|
250
241
|
case CC_EVENTS.CONTACT_ENDED:
|
|
251
|
-
// Update task data
|
|
252
242
|
task = this.updateTaskData(task, {
|
|
253
243
|
...payload.data,
|
|
254
|
-
wrapUpRequired:
|
|
255
|
-
payload.data.interaction.state !== 'new' &&
|
|
256
|
-
!isSecondaryEpDnAgent(payload.data.interaction),
|
|
244
|
+
wrapUpRequired: payload.data.interaction.state !== 'new',
|
|
257
245
|
});
|
|
258
|
-
|
|
259
|
-
// Handle cleanup based on whether task should be deleted
|
|
260
246
|
this.handleTaskCleanup(task);
|
|
247
|
+
task.emit(TASK_EVENTS.TASK_END, task);
|
|
261
248
|
|
|
262
|
-
task?.emit(TASK_EVENTS.TASK_END, task);
|
|
263
|
-
|
|
264
|
-
break;
|
|
265
|
-
case CC_EVENTS.CONTACT_MERGED:
|
|
266
|
-
task = this.handleContactMerged(task, payload.data);
|
|
267
249
|
break;
|
|
268
250
|
case CC_EVENTS.AGENT_CONTACT_HELD:
|
|
269
251
|
// As soon as the main interaction is held, we need to emit TASK_HOLD
|
|
@@ -376,45 +358,18 @@ export default class TaskManager extends EventEmitter {
|
|
|
376
358
|
case CC_EVENTS.AGENT_CONSULT_CONFERENCE_ENDED:
|
|
377
359
|
// Conference ended - update task state and emit event
|
|
378
360
|
task = this.updateTaskData(task, payload.data);
|
|
379
|
-
if (
|
|
380
|
-
!task ||
|
|
381
|
-
isPrimary(task, this.agentId) ||
|
|
382
|
-
isParticipantInMainInteraction(task, this.agentId)
|
|
383
|
-
) {
|
|
384
|
-
LoggerProxy.log('Primary or main interaction participant leaving conference');
|
|
385
|
-
} else {
|
|
386
|
-
this.removeTaskFromCollection(task);
|
|
387
|
-
}
|
|
388
361
|
task.emit(TASK_EVENTS.TASK_CONFERENCE_ENDED, task);
|
|
389
362
|
break;
|
|
390
|
-
case CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE:
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
isConferenceInProgress: getIsConferenceInProgress(payload.data),
|
|
394
|
-
});
|
|
363
|
+
case CC_EVENTS.PARTICIPANT_JOINED_CONFERENCE:
|
|
364
|
+
// Participant joined conference - update task state with participant information and emit event
|
|
365
|
+
task = this.updateTaskData(task, payload.data);
|
|
395
366
|
task.emit(TASK_EVENTS.TASK_PARTICIPANT_JOINED, task);
|
|
396
367
|
break;
|
|
397
|
-
|
|
398
|
-
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE: {
|
|
368
|
+
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE:
|
|
399
369
|
// Conference ended - update task state and emit event
|
|
400
|
-
|
|
401
|
-
task = this.updateTaskData(task, {
|
|
402
|
-
...payload.data,
|
|
403
|
-
isConferenceInProgress: getIsConferenceInProgress(payload.data),
|
|
404
|
-
});
|
|
405
|
-
if (checkParticipantNotInInteraction(task, this.agentId)) {
|
|
406
|
-
if (
|
|
407
|
-
isParticipantInMainInteraction(task, this.agentId) ||
|
|
408
|
-
isPrimary(task, this.agentId)
|
|
409
|
-
) {
|
|
410
|
-
LoggerProxy.log('Primary or main interaction participant leaving conference');
|
|
411
|
-
} else {
|
|
412
|
-
this.removeTaskFromCollection(task);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
370
|
+
task = this.updateTaskData(task, payload.data);
|
|
415
371
|
task.emit(TASK_EVENTS.TASK_PARTICIPANT_LEFT, task);
|
|
416
372
|
break;
|
|
417
|
-
}
|
|
418
373
|
case CC_EVENTS.PARTICIPANT_LEFT_CONFERENCE_FAILED:
|
|
419
374
|
// Conference exit failed - update task state and emit failure event
|
|
420
375
|
task = this.updateTaskData(task, payload.data);
|
|
@@ -436,10 +391,13 @@ export default class TaskManager extends EventEmitter {
|
|
|
436
391
|
task = this.updateTaskData(task, payload.data);
|
|
437
392
|
task.emit(TASK_EVENTS.TASK_CONFERENCE_TRANSFER_FAILED, task);
|
|
438
393
|
break;
|
|
394
|
+
case CC_EVENTS.CONSULTED_PARTICIPANT_MOVING:
|
|
395
|
+
// Participant is being moved/transferred - update task state with movement info
|
|
396
|
+
task = this.updateTaskData(task, payload.data);
|
|
397
|
+
break;
|
|
439
398
|
case CC_EVENTS.PARTICIPANT_POST_CALL_ACTIVITY:
|
|
440
399
|
// Post-call activity for participant - update task state with activity details
|
|
441
400
|
task = this.updateTaskData(task, payload.data);
|
|
442
|
-
task.emit(TASK_EVENTS.TASK_POST_CALL_ACTIVITY, task);
|
|
443
401
|
break;
|
|
444
402
|
default:
|
|
445
403
|
break;
|
|
@@ -479,54 +437,6 @@ export default class TaskManager extends EventEmitter {
|
|
|
479
437
|
}
|
|
480
438
|
}
|
|
481
439
|
|
|
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
|
-
|
|
530
440
|
private removeTaskFromCollection(task: ITask) {
|
|
531
441
|
if (task?.data?.interactionId) {
|
|
532
442
|
delete this.taskCollection[task.data.interactionId];
|
|
@@ -538,13 +448,7 @@ export default class TaskManager extends EventEmitter {
|
|
|
538
448
|
}
|
|
539
449
|
}
|
|
540
450
|
|
|
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
|
-
*/
|
|
546
451
|
private handleTaskCleanup(task: ITask) {
|
|
547
|
-
// Clean up Desktop/WebRTC calling resources for browser-based telephony tasks
|
|
548
452
|
if (
|
|
549
453
|
this.webCallingService.loginOption === LoginOption.BROWSER &&
|
|
550
454
|
task.data.interaction.mediaType === 'telephony'
|
|
@@ -552,9 +456,8 @@ export default class TaskManager extends EventEmitter {
|
|
|
552
456
|
task.unregisterWebCallListeners();
|
|
553
457
|
this.webCallingService.cleanUpCall();
|
|
554
458
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
// Only remove tasks in 'new' state or isSecondaryEpDnAgent immediately. For other states,
|
|
459
|
+
if (task.data.interaction.state === 'new') {
|
|
460
|
+
// Only remove tasks in 'new' state immediately. For other states,
|
|
558
461
|
// retain tasks until they complete wrap-up, unless the task disconnected before being answered.
|
|
559
462
|
this.removeTaskFromCollection(task);
|
|
560
463
|
}
|
|
@@ -23,25 +23,6 @@ export const CONFERENCE_TRANSFER = '/conference/transfer';
|
|
|
23
23
|
export const TASK_MANAGER_FILE = 'taskManager';
|
|
24
24
|
export const TASK_FILE = 'task';
|
|
25
25
|
|
|
26
|
-
/**
|
|
27
|
-
* Task data field names that should be preserved during reconciliation
|
|
28
|
-
* These fields are retained even if not present in new data during updates
|
|
29
|
-
*/
|
|
30
|
-
export const PRESERVED_TASK_DATA_FIELDS = {
|
|
31
|
-
/** Indicates if the task is in consultation state */
|
|
32
|
-
IS_CONSULTED: 'isConsulted',
|
|
33
|
-
/** Indicates if wrap-up is required for this task */
|
|
34
|
-
WRAP_UP_REQUIRED: 'wrapUpRequired',
|
|
35
|
-
/** Indicates if a conference is currently in progress (2+ active agents) */
|
|
36
|
-
IS_CONFERENCE_IN_PROGRESS: 'isConferenceInProgress',
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Array of task data field names that should not be deleted during reconciliation
|
|
41
|
-
* Used by reconcileData method to preserve important task state fields
|
|
42
|
-
*/
|
|
43
|
-
export const KEYS_TO_NOT_DELETE: string[] = Object.values(PRESERVED_TASK_DATA_FIELDS);
|
|
44
|
-
|
|
45
26
|
// METHOD NAMES
|
|
46
27
|
export const METHODS = {
|
|
47
28
|
// Task class methods
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
import {CALL_EVENT_KEYS, LocalMicrophoneStream} from '@webex/calling';
|
|
3
3
|
import {CallId} from '@webex/calling/dist/types/common/types';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
generateTaskErrorObject,
|
|
6
|
+
deriveConsultTransferDestinationType,
|
|
7
|
+
getDestinationAgentId,
|
|
8
|
+
buildConsultConferenceParamData,
|
|
9
|
+
} from '../core/Utils';
|
|
5
10
|
import {Failure} from '../core/GlobalTypes';
|
|
6
11
|
import {LoginOption} from '../../types';
|
|
7
12
|
import {TASK_FILE} from '../../constants';
|
|
8
|
-
import {METHODS
|
|
13
|
+
import {METHODS} from './constants';
|
|
9
14
|
import routingContact from './contact';
|
|
10
15
|
import LoggerProxy from '../../logger-proxy';
|
|
11
16
|
import {
|
|
@@ -276,24 +281,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
276
281
|
* @private
|
|
277
282
|
*/
|
|
278
283
|
private reconcileData(oldData: TaskData, newData: TaskData): TaskData {
|
|
279
|
-
// Remove keys from oldData that are not in newData
|
|
280
|
-
Object.keys(oldData).forEach((key) => {
|
|
281
|
-
if (!(key in newData) && !KEYS_TO_NOT_DELETE.includes(key as string)) {
|
|
282
|
-
delete oldData[key];
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
// Merge or update keys from newData
|
|
287
284
|
Object.keys(newData).forEach((key) => {
|
|
288
|
-
if (
|
|
289
|
-
newData[key]
|
|
290
|
-
typeof newData[key] === 'object' &&
|
|
291
|
-
!Array.isArray(newData[key]) &&
|
|
292
|
-
oldData[key] &&
|
|
293
|
-
typeof oldData[key] === 'object' &&
|
|
294
|
-
!Array.isArray(oldData[key])
|
|
295
|
-
) {
|
|
296
|
-
this.reconcileData(oldData[key], newData[key]);
|
|
285
|
+
if (newData[key] && typeof newData[key] === 'object' && !Array.isArray(newData[key])) {
|
|
286
|
+
oldData[key] = this.reconcileData({...oldData[key]}, newData[key]);
|
|
297
287
|
} else {
|
|
298
288
|
oldData[key] = newData[key];
|
|
299
289
|
}
|
|
@@ -521,7 +511,6 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
521
511
|
* Puts the current task/interaction on hold.
|
|
522
512
|
* Emits task:hold event when successful. For voice tasks, this mutes the audio.
|
|
523
513
|
*
|
|
524
|
-
* @param mediaResourceId - Optional media resource ID to use for the hold operation. If not provided, uses the task's current mediaResourceId
|
|
525
514
|
* @returns Promise<TaskResponse>
|
|
526
515
|
* @throws Error if hold operation fails
|
|
527
516
|
* @example
|
|
@@ -542,17 +531,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
542
531
|
* console.error('Failed to place task on hold:', error);
|
|
543
532
|
* // Handle error (e.g., show error message, reset UI state)
|
|
544
533
|
* }
|
|
545
|
-
*
|
|
546
|
-
* // Place task on hold with custom mediaResourceId
|
|
547
|
-
* try {
|
|
548
|
-
* await task.hold('custom-media-resource-id');
|
|
549
|
-
* console.log('Successfully placed task on hold with custom mediaResourceId');
|
|
550
|
-
* } catch (error) {
|
|
551
|
-
* console.error('Failed to place task on hold:', error);
|
|
552
|
-
* }
|
|
553
534
|
* ```
|
|
554
535
|
*/
|
|
555
|
-
public async hold(
|
|
536
|
+
public async hold(): Promise<TaskResponse> {
|
|
556
537
|
try {
|
|
557
538
|
LoggerProxy.info(`Holding task`, {
|
|
558
539
|
module: TASK_FILE,
|
|
@@ -565,11 +546,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
565
546
|
METRIC_EVENT_NAMES.TASK_HOLD_FAILED,
|
|
566
547
|
]);
|
|
567
548
|
|
|
568
|
-
const effectiveMediaResourceId = mediaResourceId ?? this.data.mediaResourceId;
|
|
569
|
-
|
|
570
549
|
const response = await this.contact.hold({
|
|
571
550
|
interactionId: this.data.interactionId,
|
|
572
|
-
data: {mediaResourceId:
|
|
551
|
+
data: {mediaResourceId: this.data.mediaResourceId},
|
|
573
552
|
});
|
|
574
553
|
|
|
575
554
|
this.metricsManager.trackEvent(
|
|
@@ -577,7 +556,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
577
556
|
{
|
|
578
557
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
579
558
|
taskId: this.data.interactionId,
|
|
580
|
-
mediaResourceId:
|
|
559
|
+
mediaResourceId: this.data.mediaResourceId,
|
|
581
560
|
},
|
|
582
561
|
['operational', 'behavioral']
|
|
583
562
|
);
|
|
@@ -599,13 +578,11 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
599
578
|
errorData: err.data?.errorData,
|
|
600
579
|
reasonCode: err.data?.reasonCode,
|
|
601
580
|
};
|
|
602
|
-
const effectiveMediaResourceId = mediaResourceId ?? this.data.mediaResourceId;
|
|
603
|
-
|
|
604
581
|
this.metricsManager.trackEvent(
|
|
605
582
|
METRIC_EVENT_NAMES.TASK_HOLD_FAILED,
|
|
606
583
|
{
|
|
607
584
|
taskId: this.data.interactionId,
|
|
608
|
-
mediaResourceId:
|
|
585
|
+
mediaResourceId: this.data.mediaResourceId,
|
|
609
586
|
error: error.toString(),
|
|
610
587
|
...taskErrorProps,
|
|
611
588
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
@@ -620,7 +597,6 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
620
597
|
* Resumes the task/interaction that was previously put on hold.
|
|
621
598
|
* Emits task:resume event when successful. For voice tasks, this restores the audio.
|
|
622
599
|
*
|
|
623
|
-
* @param mediaResourceId - Optional media resource ID to use for the resume operation. If not provided, uses the task's current mediaResourceId from interaction media
|
|
624
600
|
* @returns Promise<TaskResponse>
|
|
625
601
|
* @throws Error if resume operation fails
|
|
626
602
|
* @example
|
|
@@ -641,17 +617,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
641
617
|
* console.error('Failed to resume task:', error);
|
|
642
618
|
* // Handle error (e.g., show error message)
|
|
643
619
|
* }
|
|
644
|
-
*
|
|
645
|
-
* // Resume task from hold with custom mediaResourceId
|
|
646
|
-
* try {
|
|
647
|
-
* await task.resume('custom-media-resource-id');
|
|
648
|
-
* console.log('Successfully resumed task from hold with custom mediaResourceId');
|
|
649
|
-
* } catch (error) {
|
|
650
|
-
* console.error('Failed to resume task:', error);
|
|
651
|
-
* }
|
|
652
620
|
* ```
|
|
653
621
|
*/
|
|
654
|
-
public async resume(
|
|
622
|
+
public async resume(): Promise<TaskResponse> {
|
|
655
623
|
try {
|
|
656
624
|
LoggerProxy.info(`Resuming task`, {
|
|
657
625
|
module: TASK_FILE,
|
|
@@ -659,9 +627,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
659
627
|
interactionId: this.data.interactionId,
|
|
660
628
|
});
|
|
661
629
|
const {mainInteractionId} = this.data.interaction;
|
|
662
|
-
const
|
|
663
|
-
this.data.interaction.media[mainInteractionId]?.mediaResourceId;
|
|
664
|
-
const effectiveMediaResourceId = mediaResourceId ?? defaultMediaResourceId;
|
|
630
|
+
const {mediaResourceId} = this.data.interaction.media[mainInteractionId];
|
|
665
631
|
|
|
666
632
|
this.metricsManager.timeEvent([
|
|
667
633
|
METRIC_EVENT_NAMES.TASK_RESUME_SUCCESS,
|
|
@@ -670,7 +636,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
670
636
|
|
|
671
637
|
const response = await this.contact.unHold({
|
|
672
638
|
interactionId: this.data.interactionId,
|
|
673
|
-
data: {mediaResourceId
|
|
639
|
+
data: {mediaResourceId},
|
|
674
640
|
});
|
|
675
641
|
|
|
676
642
|
this.metricsManager.trackEvent(
|
|
@@ -678,7 +644,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
678
644
|
{
|
|
679
645
|
taskId: this.data.interactionId,
|
|
680
646
|
mainInteractionId,
|
|
681
|
-
mediaResourceId
|
|
647
|
+
mediaResourceId,
|
|
682
648
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
683
649
|
},
|
|
684
650
|
['operational', 'behavioral']
|
|
@@ -695,11 +661,6 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
695
661
|
} catch (error) {
|
|
696
662
|
const err = generateTaskErrorObject(error, METHODS.RESUME, TASK_FILE);
|
|
697
663
|
const mainInteractionId = this.data.interaction?.mainInteractionId;
|
|
698
|
-
const defaultMediaResourceId = mainInteractionId
|
|
699
|
-
? this.data.interaction.media[mainInteractionId]?.mediaResourceId
|
|
700
|
-
: '';
|
|
701
|
-
const effectiveMediaResourceId = mediaResourceId ?? defaultMediaResourceId;
|
|
702
|
-
|
|
703
664
|
const taskErrorProps = {
|
|
704
665
|
trackingId: err.data?.trackingId,
|
|
705
666
|
errorMessage: err.data?.message,
|
|
@@ -712,7 +673,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
712
673
|
{
|
|
713
674
|
taskId: this.data.interactionId,
|
|
714
675
|
mainInteractionId,
|
|
715
|
-
mediaResourceId:
|
|
676
|
+
mediaResourceId: mainInteractionId
|
|
677
|
+
? this.data.interaction.media[mainInteractionId].mediaResourceId
|
|
678
|
+
: '',
|
|
716
679
|
...taskErrorProps,
|
|
717
680
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
718
681
|
},
|
|
@@ -1442,31 +1405,35 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1442
1405
|
public async consultTransfer(
|
|
1443
1406
|
consultTransferPayload?: ConsultTransferPayLoad
|
|
1444
1407
|
): Promise<TaskResponse> {
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
}
|
|
1408
|
+
try {
|
|
1409
|
+
// Get the destination agent ID using custom logic from participants data
|
|
1410
|
+
const destAgentId = getDestinationAgentId(
|
|
1411
|
+
this.data.interaction?.participants,
|
|
1412
|
+
this.data.agentId
|
|
1413
|
+
);
|
|
1452
1414
|
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
module: TASK_FILE,
|
|
1457
|
-
method: METHODS.CONSULT_TRANSFER,
|
|
1458
|
-
interactionId: this.data.interactionId,
|
|
1415
|
+
// Resolve the target id (queue consult transfers go to the accepted agent)
|
|
1416
|
+
if (!destAgentId) {
|
|
1417
|
+
throw new Error('No agent has accepted this queue consult yet');
|
|
1459
1418
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1419
|
+
|
|
1420
|
+
LoggerProxy.info(
|
|
1421
|
+
`Initiating consult transfer to ${consultTransferPayload?.to || destAgentId}`,
|
|
1422
|
+
{
|
|
1423
|
+
module: TASK_FILE,
|
|
1424
|
+
method: METHODS.CONSULT_TRANSFER,
|
|
1425
|
+
interactionId: this.data.interactionId,
|
|
1426
|
+
}
|
|
1427
|
+
);
|
|
1428
|
+
// Obtain payload based on desktop logic using TaskData
|
|
1429
|
+
const finalDestinationType = deriveConsultTransferDestinationType(this.data);
|
|
1430
|
+
|
|
1431
|
+
// By default we always use the computed destAgentId as the target id
|
|
1432
|
+
const consultTransferRequest: ConsultTransferPayLoad = {
|
|
1433
|
+
to: destAgentId,
|
|
1434
|
+
destinationType: finalDestinationType,
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1470
1437
|
const result = await this.contact.consultTransfer({
|
|
1471
1438
|
interactionId: this.data.interactionId,
|
|
1472
1439
|
data: consultTransferRequest,
|
|
@@ -1504,12 +1471,17 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1504
1471
|
errorData: err.data?.errorData,
|
|
1505
1472
|
reasonCode: err.data?.reasonCode,
|
|
1506
1473
|
};
|
|
1474
|
+
const failedDestinationType = deriveConsultTransferDestinationType(this.data);
|
|
1475
|
+
const failedDestAgentId = getDestinationAgentId(
|
|
1476
|
+
this.data.interaction?.participants,
|
|
1477
|
+
this.data.agentId
|
|
1478
|
+
);
|
|
1507
1479
|
this.metricsManager.trackEvent(
|
|
1508
1480
|
METRIC_EVENT_NAMES.TASK_TRANSFER_FAILED,
|
|
1509
1481
|
{
|
|
1510
1482
|
taskId: this.data.interactionId,
|
|
1511
|
-
destination:
|
|
1512
|
-
destinationType:
|
|
1483
|
+
destination: failedDestAgentId || '',
|
|
1484
|
+
destinationType: failedDestinationType,
|
|
1513
1485
|
isConsultTransfer: true,
|
|
1514
1486
|
error: error.toString(),
|
|
1515
1487
|
...taskErrorProps,
|
|
@@ -1542,36 +1514,28 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1542
1514
|
* ```
|
|
1543
1515
|
*/
|
|
1544
1516
|
public async consultConference(): Promise<TaskResponse> {
|
|
1545
|
-
// Get the destination agent ID dynamically from participants
|
|
1546
|
-
// This handles multi-party conference scenarios, CBT (Capacity Based Team), and EP-DN cases
|
|
1547
|
-
const destAgentId = calculateDestAgentId(this.data.interaction, this.agentId);
|
|
1548
|
-
|
|
1549
|
-
// Validate that we have a destination agent (for queue consult scenarios)
|
|
1550
|
-
if (!destAgentId) {
|
|
1551
|
-
throw new Error('No agent has accepted this queue consult yet');
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
// Get the destination agent ID for fetching destination type
|
|
1555
|
-
// This helps determine the correct participant type for CBT (Capacity Based Team) and EP-DN scenarios
|
|
1556
|
-
const destAgentType = calculateDestType(this.data.interaction, this.agentId);
|
|
1557
|
-
|
|
1558
1517
|
// Extract consultation conference data from task data (used in both try and catch)
|
|
1559
1518
|
const consultationData = {
|
|
1560
1519
|
agentId: this.agentId,
|
|
1561
|
-
|
|
1562
|
-
destinationType:
|
|
1520
|
+
destAgentId: this.data.destAgentId,
|
|
1521
|
+
destinationType: this.data.destinationType || 'agent',
|
|
1563
1522
|
};
|
|
1564
1523
|
|
|
1565
1524
|
try {
|
|
1566
|
-
LoggerProxy.info(`Initiating consult conference to ${destAgentId}`, {
|
|
1525
|
+
LoggerProxy.info(`Initiating consult conference to ${consultationData.destAgentId}`, {
|
|
1567
1526
|
module: TASK_FILE,
|
|
1568
1527
|
method: METHODS.CONSULT_CONFERENCE,
|
|
1569
1528
|
interactionId: this.data.interactionId,
|
|
1570
1529
|
});
|
|
1571
1530
|
|
|
1531
|
+
const paramsDataForConferenceV2 = buildConsultConferenceParamData(
|
|
1532
|
+
consultationData,
|
|
1533
|
+
this.data.interactionId
|
|
1534
|
+
);
|
|
1535
|
+
|
|
1572
1536
|
const response = await this.contact.consultConference({
|
|
1573
|
-
interactionId:
|
|
1574
|
-
data:
|
|
1537
|
+
interactionId: paramsDataForConferenceV2.interactionId,
|
|
1538
|
+
data: paramsDataForConferenceV2.data,
|
|
1575
1539
|
});
|
|
1576
1540
|
|
|
1577
1541
|
// Track success metrics (following consultTransfer pattern)
|
|
@@ -1579,9 +1543,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1579
1543
|
METRIC_EVENT_NAMES.TASK_CONFERENCE_START_SUCCESS,
|
|
1580
1544
|
{
|
|
1581
1545
|
taskId: this.data.interactionId,
|
|
1582
|
-
destination:
|
|
1583
|
-
destinationType:
|
|
1584
|
-
agentId:
|
|
1546
|
+
destination: paramsDataForConferenceV2.data.to,
|
|
1547
|
+
destinationType: paramsDataForConferenceV2.data.destinationType,
|
|
1548
|
+
agentId: paramsDataForConferenceV2.data.agentId,
|
|
1585
1549
|
...MetricsManager.getCommonTrackingFieldForAQMResponse(response),
|
|
1586
1550
|
},
|
|
1587
1551
|
['operational', 'behavioral', 'business']
|
|
@@ -1604,13 +1568,20 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1604
1568
|
reasonCode: err.data?.reasonCode,
|
|
1605
1569
|
};
|
|
1606
1570
|
|
|
1571
|
+
// Track failure metrics (following consultTransfer pattern)
|
|
1572
|
+
// Build conference data for error tracking using extracted data
|
|
1573
|
+
const failedParamsData = buildConsultConferenceParamData(
|
|
1574
|
+
consultationData,
|
|
1575
|
+
this.data.interactionId
|
|
1576
|
+
);
|
|
1577
|
+
|
|
1607
1578
|
this.metricsManager.trackEvent(
|
|
1608
1579
|
METRIC_EVENT_NAMES.TASK_CONFERENCE_START_FAILED,
|
|
1609
1580
|
{
|
|
1610
1581
|
taskId: this.data.interactionId,
|
|
1611
|
-
destination:
|
|
1612
|
-
destinationType:
|
|
1613
|
-
agentId:
|
|
1582
|
+
destination: failedParamsData.data.to,
|
|
1583
|
+
destinationType: failedParamsData.data.destinationType,
|
|
1584
|
+
agentId: failedParamsData.data.agentId,
|
|
1614
1585
|
error: error.toString(),
|
|
1615
1586
|
...taskErrorProps,
|
|
1616
1587
|
...MetricsManager.getCommonTrackingFieldForAQMResponseFailed(error.details || {}),
|
|
@@ -1713,6 +1684,9 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1713
1684
|
}
|
|
1714
1685
|
}
|
|
1715
1686
|
|
|
1687
|
+
// TODO: Uncomment this method in future PR for Multi-Party Conference support (>3 participants)
|
|
1688
|
+
// Conference transfer will be supported when implementing enhanced multi-party conference functionality
|
|
1689
|
+
/*
|
|
1716
1690
|
/**
|
|
1717
1691
|
* Transfers the current conference to another agent
|
|
1718
1692
|
*
|
|
@@ -1733,7 +1707,7 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1733
1707
|
* }
|
|
1734
1708
|
* ```
|
|
1735
1709
|
*/
|
|
1736
|
-
public async transferConference(): Promise<TaskResponse> {
|
|
1710
|
+
/* public async transferConference(): Promise<TaskResponse> {
|
|
1737
1711
|
try {
|
|
1738
1712
|
LoggerProxy.info(`Transferring conference`, {
|
|
1739
1713
|
module: TASK_FILE,
|
|
@@ -1797,5 +1771,5 @@ export default class Task extends EventEmitter implements ITask {
|
|
|
1797
1771
|
|
|
1798
1772
|
throw err;
|
|
1799
1773
|
}
|
|
1800
|
-
}
|
|
1774
|
+
} */
|
|
1801
1775
|
}
|