@webex/contact-center 3.12.0-llmrefactor.2 → 3.12.0-llmrefactor.3
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/.sdd/manifest.json +5 -4
- package/ai-docs/ARCHITECTURE.md +1 -1
- package/ai-docs/CONTRACTS.md +5 -1
- package/ai-docs/SECURITY.md +1 -1
- package/ai-docs/contact-center-spec.md +22 -4
- package/ai-docs/features/consult-transfer-list-policy/spec/feature-spec.md +362 -0
- package/dist/cc.js +440 -10
- package/dist/cc.js.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +10 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics/behavioral-events.js +13 -0
- package/dist/metrics/behavioral-events.js.map +1 -1
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/AddressBook.js +18 -15
- package/dist/services/AddressBook.js.map +1 -1
- package/dist/services/AnswerCallOnWebexService.js +174 -0
- package/dist/services/AnswerCallOnWebexService.js.map +1 -0
- package/dist/services/EntryPoint.js +46 -68
- package/dist/services/EntryPoint.js.map +1 -1
- package/dist/services/Queue.js +27 -22
- package/dist/services/Queue.js.map +1 -1
- package/dist/services/WebexCrossClientService.js +171 -0
- package/dist/services/WebexCrossClientService.js.map +1 -0
- package/dist/services/WxAppTelephonyMercurySync.js +93 -0
- package/dist/services/WxAppTelephonyMercurySync.js.map +1 -0
- package/dist/services/config/Util.js +3 -0
- package/dist/services/config/Util.js.map +1 -1
- package/dist/services/config/constants.js +10 -6
- package/dist/services/config/constants.js.map +1 -1
- package/dist/services/config/types.js +4 -0
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/core/Err.js.map +1 -1
- package/dist/services/core/WebexRequest.js +6 -2
- package/dist/services/core/WebexRequest.js.map +1 -1
- package/dist/services/core/aqm-reqs.js +28 -14
- package/dist/services/core/aqm-reqs.js.map +1 -1
- package/dist/services/core/types.js.map +1 -1
- package/dist/services/task/Task.js +73 -7
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskFactory.js +8 -4
- package/dist/services/task/TaskFactory.js.map +1 -1
- package/dist/services/task/TaskManager.js +176 -20
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/WebexCallingUtils.js +70 -0
- package/dist/services/task/WebexCallingUtils.js.map +1 -0
- package/dist/services/task/constants.js +4 -1
- package/dist/services/task/constants.js.map +1 -1
- package/dist/services/task/contact.js +29 -0
- package/dist/services/task/contact.js.map +1 -1
- package/dist/services/task/digital/Digital.js +3 -2
- package/dist/services/task/digital/Digital.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +135 -37
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +6 -1
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +38 -11
- package/dist/services/task/state-machine/guards.js.map +1 -1
- package/dist/services/task/state-machine/types.js.map +1 -1
- package/dist/services/task/state-machine/uiControlsComputer.js +118 -18
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/services/task/types.js +16 -1
- package/dist/services/task/types.js.map +1 -1
- package/dist/services/task/voice/Voice.js +350 -14
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/services/task/voice/WebRTC.js +4 -1
- package/dist/services/task/voice/WebRTC.js.map +1 -1
- package/dist/services/task/voice/wxAppVoiceMethods.js +201 -0
- package/dist/services/task/voice/wxAppVoiceMethods.js.map +1 -0
- package/dist/services/wxAppTelephonyUtils.js +19 -0
- package/dist/services/wxAppTelephonyUtils.js.map +1 -0
- package/dist/types/cc.d.ts +77 -4
- package/dist/types/config.d.ts +7 -0
- package/dist/types/constants.d.ts +8 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/services/AddressBook.d.ts +2 -1
- package/dist/types/services/AnswerCallOnWebexService.d.ts +37 -0
- package/dist/types/services/EntryPoint.d.ts +7 -5
- package/dist/types/services/Queue.d.ts +5 -3
- package/dist/types/services/WebexCrossClientService.d.ts +28 -0
- package/dist/types/services/WxAppTelephonyMercurySync.d.ts +28 -0
- package/dist/types/services/config/constants.d.ts +8 -5
- package/dist/types/services/config/types.d.ts +17 -4
- package/dist/types/services/core/Err.d.ts +2 -0
- package/dist/types/services/core/WebexRequest.d.ts +1 -0
- package/dist/types/services/core/types.d.ts +2 -0
- package/dist/types/services/task/Task.d.ts +20 -2
- package/dist/types/services/task/TaskFactory.d.ts +2 -1
- package/dist/types/services/task/WebexCallingUtils.d.ts +11 -0
- package/dist/types/services/task/constants.d.ts +3 -0
- package/dist/types/services/task/contact.d.ts +4 -0
- package/dist/types/services/task/digital/Digital.d.ts +2 -2
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +260 -56
- package/dist/types/services/task/state-machine/guards.d.ts +6 -5
- package/dist/types/services/task/state-machine/types.d.ts +9 -1
- package/dist/types/services/task/types.d.ts +81 -4
- package/dist/types/services/task/voice/Voice.d.ts +48 -9
- package/dist/types/services/task/voice/WebRTC.d.ts +2 -2
- package/dist/types/services/task/voice/wxAppVoiceMethods.d.ts +52 -0
- package/dist/types/services/wxAppTelephonyUtils.d.ts +5 -0
- package/dist/types/types.d.ts +14 -8
- package/dist/types/utils/PageCache.d.ts +20 -3
- package/dist/types.js +7 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/PageCache.js +19 -5
- package/dist/utils/PageCache.js.map +1 -1
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/cc.ts +506 -9
- package/src/config.ts +7 -0
- package/src/constants.ts +8 -0
- package/src/index.ts +2 -0
- package/src/metrics/ai-docs/metrics-spec.md +9 -3
- package/src/metrics/behavioral-events.ts +14 -0
- package/src/metrics/constants.ts +2 -0
- package/src/services/AddressBook.ts +17 -6
- package/src/services/AnswerCallOnWebexService.ts +206 -0
- package/src/services/EntryPoint.ts +59 -60
- package/src/services/Queue.ts +29 -12
- package/src/services/WebexCrossClientService.ts +212 -0
- package/src/services/WxAppTelephonyMercurySync.ts +115 -0
- package/src/services/ai-docs/AGENTS.md +10 -10
- package/src/services/ai-docs/services-spec.md +6 -1
- package/src/services/config/Util.ts +3 -0
- package/src/services/config/ai-docs/AGENTS.md +1 -1
- package/src/services/config/ai-docs/ARCHITECTURE.md +2 -2
- package/src/services/config/ai-docs/config-spec.md +6 -0
- package/src/services/config/constants.ts +10 -6
- package/src/services/config/types.ts +16 -4
- package/src/services/core/Err.ts +1 -0
- package/src/services/core/WebexRequest.ts +3 -1
- package/src/services/core/ai-docs/core-spec.md +5 -1
- package/src/services/core/aqm-reqs.ts +30 -15
- package/src/services/core/types.ts +2 -0
- package/src/services/task/Task.ts +79 -8
- package/src/services/task/TaskFactory.ts +8 -3
- package/src/services/task/TaskManager.ts +254 -15
- package/src/services/task/WebexCallingUtils.ts +136 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +1 -0
- package/src/services/task/ai-docs/task-spec.md +117 -2
- package/src/services/task/constants.ts +3 -0
- package/src/services/task/contact.ts +30 -0
- package/src/services/task/digital/Digital.ts +4 -2
- package/src/services/task/state-machine/TaskStateMachine.ts +210 -63
- package/src/services/task/state-machine/actions.ts +5 -2
- package/src/services/task/state-machine/ai-docs/AGENTS.md +8 -4
- package/src/services/task/state-machine/ai-docs/ARCHITECTURE.md +17 -8
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +46 -22
- package/src/services/task/state-machine/guards.ts +64 -11
- package/src/services/task/state-machine/types.ts +16 -1
- package/src/services/task/state-machine/uiControlsComputer.ts +206 -32
- package/src/services/task/types.ts +114 -4
- package/src/services/task/voice/Voice.ts +462 -12
- package/src/services/task/voice/WebRTC.ts +5 -1
- package/src/services/task/voice/wxAppVoiceMethods.ts +307 -0
- package/src/services/wxAppTelephonyUtils.ts +14 -0
- package/src/types.ts +33 -9
- package/src/utils/AGENTS.md +21 -10
- package/src/utils/PageCache.ts +38 -5
- package/src/utils/ai-docs/utils-spec.md +21 -11
- package/test/unit/spec/cc.ts +1274 -0
- package/test/unit/spec/metrics/behavioral-events.ts +18 -0
- package/test/unit/spec/services/AddressBook.ts +37 -6
- package/test/unit/spec/services/AnswerCallOnWebexService.ts +223 -0
- package/test/unit/spec/services/EntryPoint.ts +87 -40
- package/test/unit/spec/services/Queue.ts +123 -12
- package/test/unit/spec/services/WebexCrossClientService.ts +261 -0
- package/test/unit/spec/services/WxAppTelephonyMercurySync.ts +113 -0
- package/test/unit/spec/services/config/Util.ts +85 -0
- package/test/unit/spec/services/core/WebexRequest.ts +3 -1
- package/test/unit/spec/services/core/aqm-reqs.ts +113 -1
- package/test/unit/spec/services/task/Task.ts +200 -0
- package/test/unit/spec/services/task/TaskFactory.ts +39 -2
- package/test/unit/spec/services/task/TaskManager.ts +653 -1
- package/test/unit/spec/services/task/WebexCallingUtils.ts +153 -0
- package/test/unit/spec/services/task/contact.ts +33 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +854 -72
- package/test/unit/spec/services/task/state-machine/guards.ts +210 -8
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +445 -7
- package/test/unit/spec/services/task/voice/Voice.ts +874 -0
- package/test/unit/spec/services/task/voice/wxAppVoiceMethods.ts +459 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CONSULT_TRANSFER_DESTINATION_TYPE,
|
|
3
|
+
TASK_CHANNEL_TYPE,
|
|
4
|
+
VOICE_VARIANT,
|
|
5
|
+
} from '../../../../../../src/services/task/types';
|
|
2
6
|
import {TaskState} from '../../../../../../src/services/task/state-machine/constants';
|
|
3
7
|
import {
|
|
4
8
|
computeUIControls,
|
|
5
9
|
getDefaultUIControls,
|
|
10
|
+
haveUIControlsChanged,
|
|
6
11
|
} from '../../../../../../src/services/task/state-machine/uiControlsComputer';
|
|
7
12
|
import {getTaskStateForUiControls} from '../../../../../../src/services/task/state-machine/actions';
|
|
8
13
|
import {TaskContext} from '../../../../../../src/services/task/state-machine/types';
|
|
@@ -554,6 +559,27 @@ function createVoiceContext(overrides: Partial<TaskContext> = {}): TaskContext {
|
|
|
554
559
|
};
|
|
555
560
|
}
|
|
556
561
|
|
|
562
|
+
function createConsultTransferContext(
|
|
563
|
+
taskData = createTaskData(),
|
|
564
|
+
overrides: Partial<NonNullable<TaskContext['uiControlConfig']['consultTransferConfig']>> = {}
|
|
565
|
+
): TaskContext {
|
|
566
|
+
const context = createVoiceContext({taskData});
|
|
567
|
+
|
|
568
|
+
return {
|
|
569
|
+
...context,
|
|
570
|
+
uiControlConfig: {
|
|
571
|
+
...context.uiControlConfig,
|
|
572
|
+
consultTransferConfig: {
|
|
573
|
+
allowConsultToQueue: true,
|
|
574
|
+
accessQueue: 'ALL',
|
|
575
|
+
accessEntryPoint: 'ALL',
|
|
576
|
+
accessBuddyTeam: 'ALL',
|
|
577
|
+
...overrides,
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
|
|
557
583
|
function createTaskData1LikeConferenceConsultTaskData() {
|
|
558
584
|
return createTaskData({
|
|
559
585
|
agentId: '058b3e7c-8fcf-45ee-b0c4-4ef546d360b9',
|
|
@@ -613,7 +639,10 @@ function createTaskData1LikeConferenceConsultTaskData() {
|
|
|
613
639
|
mediaResourceId: '66cc5edd-8ac9-4f27-8f48-286edea460b2',
|
|
614
640
|
mType: 'consult',
|
|
615
641
|
isHold: false,
|
|
616
|
-
participants: [
|
|
642
|
+
participants: [
|
|
643
|
+
'747a2138-0a24-48fc-8d69-3a336d9b7158',
|
|
644
|
+
'058b3e7c-8fcf-45ee-b0c4-4ef546d360b9',
|
|
645
|
+
],
|
|
617
646
|
},
|
|
618
647
|
} as any,
|
|
619
648
|
owner: 'e271075a-077d-42d0-9ae4-2a43cb847664',
|
|
@@ -1258,7 +1287,11 @@ describe('uiControlsComputer consult initiator controls', () => {
|
|
|
1258
1287
|
agentId: 'agent-1',
|
|
1259
1288
|
},
|
|
1260
1289
|
});
|
|
1261
|
-
const createdControls = computeUIControls(
|
|
1290
|
+
const createdControls = computeUIControls(
|
|
1291
|
+
TaskState.CONSULTING,
|
|
1292
|
+
createdContext,
|
|
1293
|
+
createdTaskData
|
|
1294
|
+
);
|
|
1262
1295
|
|
|
1263
1296
|
expect(createdControls.consult.transferConference).toEqual({isVisible: true, isEnabled: false});
|
|
1264
1297
|
|
|
@@ -1274,7 +1307,10 @@ describe('uiControlsComputer consult initiator controls', () => {
|
|
|
1274
1307
|
consultingTaskData
|
|
1275
1308
|
);
|
|
1276
1309
|
|
|
1277
|
-
expect(consultingControls.consult.transferConference).toEqual({
|
|
1310
|
+
expect(consultingControls.consult.transferConference).toEqual({
|
|
1311
|
+
isVisible: true,
|
|
1312
|
+
isEnabled: true,
|
|
1313
|
+
});
|
|
1278
1314
|
});
|
|
1279
1315
|
|
|
1280
1316
|
it('hides exitConference on main leg for consult initiator before destination joins', () => {
|
|
@@ -1919,7 +1955,6 @@ describe('uiControlsComputer consult initiator controls', () => {
|
|
|
1919
1955
|
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
1920
1956
|
expect(uiControls.consult.endConsult).toEqual({isVisible: false, isEnabled: false});
|
|
1921
1957
|
});
|
|
1922
|
-
|
|
1923
1958
|
});
|
|
1924
1959
|
|
|
1925
1960
|
describe('uiControlsComputer outdial accept/decline controls', () => {
|
|
@@ -2064,7 +2099,10 @@ describe('uiControlsComputer conference controls', () => {
|
|
|
2064
2099
|
});
|
|
2065
2100
|
}
|
|
2066
2101
|
|
|
2067
|
-
function createConferenceContext(
|
|
2102
|
+
function createConferenceContext(
|
|
2103
|
+
participantCount: number,
|
|
2104
|
+
overrides: Partial<TaskContext> = {}
|
|
2105
|
+
): TaskContext {
|
|
2068
2106
|
return {
|
|
2069
2107
|
taskData: createConferenceTaskData(participantCount),
|
|
2070
2108
|
consultInitiator: true,
|
|
@@ -2414,7 +2452,6 @@ describe('uiControlsComputer conference controls', () => {
|
|
|
2414
2452
|
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
2415
2453
|
});
|
|
2416
2454
|
|
|
2417
|
-
|
|
2418
2455
|
it('post_call after customer exit: only exitConference and end enabled during EP-DN pending merge (CAI-8329)', () => {
|
|
2419
2456
|
const taskData = createTaskData({
|
|
2420
2457
|
agentId: 'agent-1',
|
|
@@ -2577,6 +2614,115 @@ describe('uiControlsComputer conference controls', () => {
|
|
|
2577
2614
|
});
|
|
2578
2615
|
});
|
|
2579
2616
|
|
|
2617
|
+
describe('uiControlsComputer consult/transfer destinations', () => {
|
|
2618
|
+
const AGENT = CONSULT_TRANSFER_DESTINATION_TYPE.AGENT;
|
|
2619
|
+
const QUEUE = CONSULT_TRANSFER_DESTINATION_TYPE.QUEUE;
|
|
2620
|
+
const DIAL_NUMBER = CONSULT_TRANSFER_DESTINATION_TYPE.DIALNUMBER;
|
|
2621
|
+
const ENTRY_POINT = CONSULT_TRANSFER_DESTINATION_TYPE.ENTRYPOINT;
|
|
2622
|
+
|
|
2623
|
+
it('returns the default destination order and applies the action-specific inbound voice queue rule', () => {
|
|
2624
|
+
const taskData = createTaskData({
|
|
2625
|
+
interaction: {contactDirection: {type: 'INBOUND'}} as any,
|
|
2626
|
+
});
|
|
2627
|
+
const context = createConsultTransferContext(taskData, {allowConsultToQueue: false});
|
|
2628
|
+
|
|
2629
|
+
const controls = computeUIControls(TaskState.CONNECTED, context, taskData);
|
|
2630
|
+
|
|
2631
|
+
expect(controls.consultTransferDestinations.consult).toEqual([AGENT, DIAL_NUMBER, ENTRY_POINT]);
|
|
2632
|
+
expect(controls.consultTransferDestinations.transfer).toEqual([
|
|
2633
|
+
AGENT,
|
|
2634
|
+
QUEUE,
|
|
2635
|
+
DIAL_NUMBER,
|
|
2636
|
+
ENTRY_POINT,
|
|
2637
|
+
]);
|
|
2638
|
+
});
|
|
2639
|
+
|
|
2640
|
+
it('reads the outbound queue-transfer flag from callProcessingDetails', () => {
|
|
2641
|
+
const disabledTaskData = createTaskData({
|
|
2642
|
+
interaction: {
|
|
2643
|
+
contactDirection: {type: 'OUTBOUND'},
|
|
2644
|
+
callProcessingDetails: {outdialTransferToQueueEnabled: false},
|
|
2645
|
+
} as any,
|
|
2646
|
+
});
|
|
2647
|
+
const disabledContext = createConsultTransferContext(disabledTaskData);
|
|
2648
|
+
const disabledControls = computeUIControls(
|
|
2649
|
+
TaskState.CONNECTED,
|
|
2650
|
+
disabledContext,
|
|
2651
|
+
disabledTaskData
|
|
2652
|
+
);
|
|
2653
|
+
|
|
2654
|
+
expect(disabledControls.consultTransferDestinations.transfer).toEqual([
|
|
2655
|
+
AGENT,
|
|
2656
|
+
DIAL_NUMBER,
|
|
2657
|
+
ENTRY_POINT,
|
|
2658
|
+
]);
|
|
2659
|
+
|
|
2660
|
+
const enabledTaskData = createTaskData({
|
|
2661
|
+
interaction: {
|
|
2662
|
+
contactDirection: {type: 'OUTBOUND'},
|
|
2663
|
+
callProcessingDetails: {outdialTransferToQueueEnabled: true},
|
|
2664
|
+
} as any,
|
|
2665
|
+
});
|
|
2666
|
+
const enabledContext = createConsultTransferContext(enabledTaskData);
|
|
2667
|
+
const enabledControls = computeUIControls(TaskState.CONNECTED, enabledContext, enabledTaskData);
|
|
2668
|
+
|
|
2669
|
+
expect(enabledControls.consultTransferDestinations.transfer).toEqual([
|
|
2670
|
+
AGENT,
|
|
2671
|
+
QUEUE,
|
|
2672
|
+
DIAL_NUMBER,
|
|
2673
|
+
ENTRY_POINT,
|
|
2674
|
+
]);
|
|
2675
|
+
expect(haveUIControlsChanged(disabledControls, enabledControls)).toBe(true);
|
|
2676
|
+
});
|
|
2677
|
+
|
|
2678
|
+
it('hides profile-disabled destinations and does not allow queue transfer for unknown voice direction', () => {
|
|
2679
|
+
const taskData = createTaskData({
|
|
2680
|
+
interaction: {contactDirection: {type: 'UNKNOWN'}} as any,
|
|
2681
|
+
});
|
|
2682
|
+
const context = createConsultTransferContext(taskData, {
|
|
2683
|
+
accessQueue: 'NONE',
|
|
2684
|
+
accessEntryPoint: 'NONE',
|
|
2685
|
+
accessBuddyTeam: 'NONE',
|
|
2686
|
+
});
|
|
2687
|
+
|
|
2688
|
+
const controls = computeUIControls(TaskState.CONNECTED, context, taskData);
|
|
2689
|
+
|
|
2690
|
+
expect(controls.consultTransferDestinations).toEqual({
|
|
2691
|
+
consult: [DIAL_NUMBER],
|
|
2692
|
+
transfer: [DIAL_NUMBER],
|
|
2693
|
+
});
|
|
2694
|
+
});
|
|
2695
|
+
|
|
2696
|
+
it('returns only agents and queues for digital tasks', () => {
|
|
2697
|
+
const taskData = createTaskData({
|
|
2698
|
+
interaction: {mediaType: 'chat'} as any,
|
|
2699
|
+
});
|
|
2700
|
+
const voiceContext = createConsultTransferContext(taskData, {allowConsultToQueue: false});
|
|
2701
|
+
const context: TaskContext = {
|
|
2702
|
+
...voiceContext,
|
|
2703
|
+
uiControlConfig: {
|
|
2704
|
+
...voiceContext.uiControlConfig,
|
|
2705
|
+
channelType: TASK_CHANNEL_TYPE.DIGITAL,
|
|
2706
|
+
},
|
|
2707
|
+
};
|
|
2708
|
+
|
|
2709
|
+
const controls = computeUIControls(TaskState.CONNECTED, context, taskData);
|
|
2710
|
+
|
|
2711
|
+
expect(controls.consultTransferDestinations).toEqual({
|
|
2712
|
+
consult: [AGENT, QUEUE],
|
|
2713
|
+
transfer: [AGENT, QUEUE],
|
|
2714
|
+
});
|
|
2715
|
+
});
|
|
2716
|
+
|
|
2717
|
+
it('returns no destinations when no agent-profile policy was configured', () => {
|
|
2718
|
+
const context = createVoiceContext();
|
|
2719
|
+
|
|
2720
|
+
const controls = computeUIControls(TaskState.CONNECTED, context, context.taskData);
|
|
2721
|
+
|
|
2722
|
+
expect(controls.consultTransferDestinations).toEqual({consult: [], transfer: []});
|
|
2723
|
+
});
|
|
2724
|
+
});
|
|
2725
|
+
|
|
2580
2726
|
describe('uiControlsComputer post-call consult controls (customer left)', () => {
|
|
2581
2727
|
function createPostCallConsultTaskData() {
|
|
2582
2728
|
return createTaskData({
|
|
@@ -2661,3 +2807,295 @@ describe('uiControlsComputer post-call consult controls (customer left)', () =>
|
|
|
2661
2807
|
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: false});
|
|
2662
2808
|
});
|
|
2663
2809
|
});
|
|
2810
|
+
|
|
2811
|
+
// ---------------------------------------------------------------------------
|
|
2812
|
+
// WXCC-6026: wxApp thick-client answer UI controls
|
|
2813
|
+
// ---------------------------------------------------------------------------
|
|
2814
|
+
|
|
2815
|
+
const WX_APP_DEVICE = {
|
|
2816
|
+
deviceType: 'wxApp',
|
|
2817
|
+
deviceId: 'device-id-1',
|
|
2818
|
+
deviceCallId: 'call-id-1',
|
|
2819
|
+
};
|
|
2820
|
+
|
|
2821
|
+
function createWxAppContext(
|
|
2822
|
+
overrides: Partial<{
|
|
2823
|
+
enableWxBetterTogether: boolean;
|
|
2824
|
+
wxAppAnswerPending: boolean;
|
|
2825
|
+
wxAppAcceptInFlight: boolean;
|
|
2826
|
+
}> = {}
|
|
2827
|
+
): TaskContext {
|
|
2828
|
+
return {
|
|
2829
|
+
taskData: createTaskData({
|
|
2830
|
+
agentId: 'agent-1',
|
|
2831
|
+
mediaResourceId: 'interaction-1',
|
|
2832
|
+
interaction: {
|
|
2833
|
+
interactionId: 'interaction-1',
|
|
2834
|
+
participants: {
|
|
2835
|
+
'agent-1': {id: 'agent-1', pType: 'Agent', ...WX_APP_DEVICE},
|
|
2836
|
+
'customer-1': {id: 'customer-1', pType: 'Customer'},
|
|
2837
|
+
} as any,
|
|
2838
|
+
media: {
|
|
2839
|
+
'interaction-1': {mediaResourceId: 'interaction-1', isHold: false},
|
|
2840
|
+
} as any,
|
|
2841
|
+
} as any,
|
|
2842
|
+
}),
|
|
2843
|
+
consultInitiator: false,
|
|
2844
|
+
exitingConference: false,
|
|
2845
|
+
consultFromConference: false,
|
|
2846
|
+
transferConferenceRequested: false,
|
|
2847
|
+
consultDestinationType: null,
|
|
2848
|
+
consultDestinationAgentId: null,
|
|
2849
|
+
consultDestinationAgentJoined: false,
|
|
2850
|
+
consultCallHeld: false,
|
|
2851
|
+
hideBlindTransferForEpDnPendingMerge: false,
|
|
2852
|
+
recordingControlsAvailable: false,
|
|
2853
|
+
recordingInProgress: false,
|
|
2854
|
+
uiControlConfig: {
|
|
2855
|
+
isEndTaskEnabled: true,
|
|
2856
|
+
isEndConsultEnabled: false,
|
|
2857
|
+
channelType: TASK_CHANNEL_TYPE.VOICE,
|
|
2858
|
+
isRecordingEnabled: false,
|
|
2859
|
+
agentId: 'agent-1',
|
|
2860
|
+
enableWxBetterTogether: overrides.enableWxBetterTogether ?? true,
|
|
2861
|
+
wxAppAnswerPending: overrides.wxAppAnswerPending,
|
|
2862
|
+
wxAppAcceptInFlight: overrides.wxAppAcceptInFlight,
|
|
2863
|
+
},
|
|
2864
|
+
uiControls: getDefaultUIControls(),
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
describe('uiControlsComputer wxApp thick-client answer (WXCC-6026)', () => {
|
|
2869
|
+
describe('accept and decline when wxApp offer and enableWxBetterTogether=true', () => {
|
|
2870
|
+
it('accept is visible and enabled in OFFERED state with wxApp participant', () => {
|
|
2871
|
+
const ctx = createWxAppContext();
|
|
2872
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2873
|
+
|
|
2874
|
+
expect(controls.main.accept).toEqual({isVisible: true, isEnabled: true});
|
|
2875
|
+
});
|
|
2876
|
+
|
|
2877
|
+
it('decline is visible and enabled in OFFERED state with wxApp participant', () => {
|
|
2878
|
+
const ctx = createWxAppContext();
|
|
2879
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2880
|
+
|
|
2881
|
+
expect(controls.main.decline).toEqual({isVisible: true, isEnabled: true});
|
|
2882
|
+
});
|
|
2883
|
+
|
|
2884
|
+
it('accept is visible but disabled while wxAppAcceptInFlight on inbound offer', () => {
|
|
2885
|
+
const ctx = createWxAppContext({wxAppAcceptInFlight: true});
|
|
2886
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2887
|
+
|
|
2888
|
+
expect(controls.main.accept).toEqual({isVisible: true, isEnabled: false});
|
|
2889
|
+
});
|
|
2890
|
+
|
|
2891
|
+
it('accept is visible but disabled while wxAppAnswerPending on inbound offer', () => {
|
|
2892
|
+
const ctx = createWxAppContext({wxAppAnswerPending: true});
|
|
2893
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2894
|
+
|
|
2895
|
+
expect(controls.main.accept).toEqual({isVisible: true, isEnabled: false});
|
|
2896
|
+
});
|
|
2897
|
+
|
|
2898
|
+
it('decline is visible but disabled while wxAppAnswerPending on inbound offer', () => {
|
|
2899
|
+
const ctx = createWxAppContext({wxAppAnswerPending: true});
|
|
2900
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2901
|
+
|
|
2902
|
+
expect(controls.main.decline).toEqual({isVisible: true, isEnabled: false});
|
|
2903
|
+
});
|
|
2904
|
+
|
|
2905
|
+
it('decline is visible but disabled while wxAppAcceptInFlight on outdial offer', () => {
|
|
2906
|
+
const ctx = createWxAppContext({wxAppAcceptInFlight: true, wxAppAnswerPending: true});
|
|
2907
|
+
ctx.taskData.interaction.outboundType = 'OUTDIAL';
|
|
2908
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2909
|
+
|
|
2910
|
+
expect(controls.main.decline).toEqual({isVisible: true, isEnabled: false});
|
|
2911
|
+
});
|
|
2912
|
+
|
|
2913
|
+
it('decline is visible and enabled while wxAppAnswerPending on outdial offer (Calling phase)', () => {
|
|
2914
|
+
const ctx = createWxAppContext({wxAppAnswerPending: true});
|
|
2915
|
+
ctx.taskData.interaction.outboundType = 'OUTDIAL';
|
|
2916
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2917
|
+
|
|
2918
|
+
expect(controls.main.decline).toEqual({isVisible: true, isEnabled: true});
|
|
2919
|
+
});
|
|
2920
|
+
|
|
2921
|
+
it('keypad is disabled in OFFERED state (not yet engaged)', () => {
|
|
2922
|
+
const ctx = createWxAppContext();
|
|
2923
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2924
|
+
|
|
2925
|
+
expect(controls.main.keypad).toEqual({isVisible: false, isEnabled: false});
|
|
2926
|
+
});
|
|
2927
|
+
});
|
|
2928
|
+
|
|
2929
|
+
describe('mute and keypad when wxApp engaged (CONNECTED state)', () => {
|
|
2930
|
+
it('mute is visible and enabled in CONNECTED state', () => {
|
|
2931
|
+
const ctx = createWxAppContext();
|
|
2932
|
+
const controls = computeUIControls(TaskState.CONNECTED, ctx, ctx.taskData);
|
|
2933
|
+
|
|
2934
|
+
expect(controls.main.mute).toEqual({isVisible: true, isEnabled: true});
|
|
2935
|
+
});
|
|
2936
|
+
|
|
2937
|
+
it('keypad is visible and enabled in CONNECTED state', () => {
|
|
2938
|
+
const ctx = createWxAppContext();
|
|
2939
|
+
const controls = computeUIControls(TaskState.CONNECTED, ctx, ctx.taskData);
|
|
2940
|
+
|
|
2941
|
+
expect(controls.main.keypad).toEqual({isVisible: true, isEnabled: true});
|
|
2942
|
+
});
|
|
2943
|
+
|
|
2944
|
+
it('keypad is disabled in WRAPPING_UP state', () => {
|
|
2945
|
+
const ctx = createWxAppContext();
|
|
2946
|
+
const controls = computeUIControls(TaskState.WRAPPING_UP, ctx, ctx.taskData);
|
|
2947
|
+
|
|
2948
|
+
expect(controls.main.keypad).toEqual({isVisible: false, isEnabled: false});
|
|
2949
|
+
});
|
|
2950
|
+
|
|
2951
|
+
it('mute is disabled in WRAPPING_UP state', () => {
|
|
2952
|
+
const ctx = createWxAppContext();
|
|
2953
|
+
const controls = computeUIControls(TaskState.WRAPPING_UP, ctx, ctx.taskData);
|
|
2954
|
+
|
|
2955
|
+
expect(controls.main.mute).toEqual({isVisible: false, isEnabled: false});
|
|
2956
|
+
});
|
|
2957
|
+
});
|
|
2958
|
+
|
|
2959
|
+
describe('when enableWxBetterTogether=false', () => {
|
|
2960
|
+
it('accept falls back to standard WebRTC logic (disabled for non-WebRTC)', () => {
|
|
2961
|
+
const ctx = createWxAppContext({enableWxBetterTogether: false});
|
|
2962
|
+
const controls = computeUIControls(TaskState.OFFERED, ctx, ctx.taskData);
|
|
2963
|
+
|
|
2964
|
+
// Without WebRTC variant, accept should be visible but disabled per existing logic
|
|
2965
|
+
expect(controls.main.accept.isVisible).toBe(true);
|
|
2966
|
+
// isEnabled is false without webRTC variant
|
|
2967
|
+
expect(controls.main.accept.isEnabled).toBe(false);
|
|
2968
|
+
});
|
|
2969
|
+
|
|
2970
|
+
it('keypad is always disabled when enableWxBetterTogether=false', () => {
|
|
2971
|
+
const ctx = createWxAppContext({enableWxBetterTogether: false});
|
|
2972
|
+
const controls = computeUIControls(TaskState.CONNECTED, ctx, ctx.taskData);
|
|
2973
|
+
|
|
2974
|
+
expect(controls.main.keypad).toEqual({isVisible: false, isEnabled: false});
|
|
2975
|
+
});
|
|
2976
|
+
|
|
2977
|
+
it('mute is disabled for non-WebRTC when enableWxBetterTogether=false', () => {
|
|
2978
|
+
const ctx = createWxAppContext({enableWxBetterTogether: false});
|
|
2979
|
+
const controls = computeUIControls(TaskState.CONNECTED, ctx, ctx.taskData);
|
|
2980
|
+
|
|
2981
|
+
expect(controls.main.mute).toEqual({isVisible: false, isEnabled: false});
|
|
2982
|
+
});
|
|
2983
|
+
});
|
|
2984
|
+
|
|
2985
|
+
describe('default keypad state without wxApp', () => {
|
|
2986
|
+
it('keypad is disabled for standard non-wxApp tasks', () => {
|
|
2987
|
+
const ctx: TaskContext = {
|
|
2988
|
+
taskData: createTaskData(),
|
|
2989
|
+
consultInitiator: false,
|
|
2990
|
+
exitingConference: false,
|
|
2991
|
+
consultFromConference: false,
|
|
2992
|
+
transferConferenceRequested: false,
|
|
2993
|
+
consultDestinationType: null,
|
|
2994
|
+
consultDestinationAgentId: null,
|
|
2995
|
+
consultDestinationAgentJoined: false,
|
|
2996
|
+
consultCallHeld: false,
|
|
2997
|
+
hideBlindTransferForEpDnPendingMerge: false,
|
|
2998
|
+
recordingControlsAvailable: false,
|
|
2999
|
+
recordingInProgress: false,
|
|
3000
|
+
uiControlConfig: {
|
|
3001
|
+
isEndTaskEnabled: true,
|
|
3002
|
+
isEndConsultEnabled: false,
|
|
3003
|
+
channelType: TASK_CHANNEL_TYPE.VOICE,
|
|
3004
|
+
isRecordingEnabled: false,
|
|
3005
|
+
},
|
|
3006
|
+
uiControls: getDefaultUIControls(),
|
|
3007
|
+
};
|
|
3008
|
+
const controls = computeUIControls(TaskState.CONNECTED, ctx, ctx.taskData);
|
|
3009
|
+
|
|
3010
|
+
expect(controls.main.keypad).toEqual({isVisible: false, isEnabled: false});
|
|
3011
|
+
});
|
|
3012
|
+
});
|
|
3013
|
+
|
|
3014
|
+
describe('wxApp engaged through consult and hold phases', () => {
|
|
3015
|
+
it('enables main mute and keypad during consult-requested phase on main leg', () => {
|
|
3016
|
+
const ctx = createWxAppContext();
|
|
3017
|
+
ctx.taskData = createTaskData({
|
|
3018
|
+
agentId: 'agent-1',
|
|
3019
|
+
consultMediaResourceId: 'consult-media',
|
|
3020
|
+
interaction: {
|
|
3021
|
+
interactionId: 'interaction-1',
|
|
3022
|
+
mainInteractionId: 'interaction-1',
|
|
3023
|
+
participants: {
|
|
3024
|
+
'agent-1': {
|
|
3025
|
+
id: 'agent-1',
|
|
3026
|
+
pType: 'Agent',
|
|
3027
|
+
consultState: 'consultInitiated',
|
|
3028
|
+
...WX_APP_DEVICE,
|
|
3029
|
+
},
|
|
3030
|
+
'customer-1': {id: 'customer-1', pType: 'Customer'},
|
|
3031
|
+
} as any,
|
|
3032
|
+
media: {
|
|
3033
|
+
'interaction-1': {
|
|
3034
|
+
mediaResourceId: 'interaction-1',
|
|
3035
|
+
isHold: false,
|
|
3036
|
+
participants: ['agent-1', 'customer-1'],
|
|
3037
|
+
},
|
|
3038
|
+
'consult-media': {
|
|
3039
|
+
mediaResourceId: 'consult-media',
|
|
3040
|
+
mType: 'consult',
|
|
3041
|
+
participants: ['agent-1'],
|
|
3042
|
+
},
|
|
3043
|
+
} as any,
|
|
3044
|
+
} as any,
|
|
3045
|
+
});
|
|
3046
|
+
ctx.consultInitiator = true;
|
|
3047
|
+
ctx.consultDestinationAgentJoined = false;
|
|
3048
|
+
|
|
3049
|
+
const controls = computeUIControls(TaskState.CONNECTED, ctx, ctx.taskData);
|
|
3050
|
+
|
|
3051
|
+
expect(controls.main.mute).toEqual({isVisible: true, isEnabled: true});
|
|
3052
|
+
expect(controls.main.keypad).toEqual({isVisible: true, isEnabled: true});
|
|
3053
|
+
});
|
|
3054
|
+
|
|
3055
|
+
it('enables main mute and keypad while consulting with main leg held', () => {
|
|
3056
|
+
const taskData = createConsultTaskData();
|
|
3057
|
+
taskData.interaction!.participants!['agent-1'] = {
|
|
3058
|
+
id: 'agent-1',
|
|
3059
|
+
pType: 'AGENT',
|
|
3060
|
+
hasLeft: false,
|
|
3061
|
+
consultState: 'consulting',
|
|
3062
|
+
...WX_APP_DEVICE,
|
|
3063
|
+
};
|
|
3064
|
+
const ctx = createVoiceContext({
|
|
3065
|
+
taskData,
|
|
3066
|
+
uiControlConfig: {
|
|
3067
|
+
...createVoiceContext().uiControlConfig,
|
|
3068
|
+
enableWxBetterTogether: true,
|
|
3069
|
+
},
|
|
3070
|
+
});
|
|
3071
|
+
|
|
3072
|
+
const controls = computeUIControls(TaskState.CONSULTING, ctx, taskData);
|
|
3073
|
+
|
|
3074
|
+
expect(controls.main.mute).toEqual({isVisible: true, isEnabled: true});
|
|
3075
|
+
expect(controls.main.keypad).toEqual({isVisible: true, isEnabled: true});
|
|
3076
|
+
expect(controls.consult.mute).toEqual({isVisible: false, isEnabled: false});
|
|
3077
|
+
});
|
|
3078
|
+
|
|
3079
|
+
it('keeps BROWSER consult mute enabled when enableWxBetterTogether is true and wxApp is not engaged', () => {
|
|
3080
|
+
const consultedTaskData = createConsultedAgentInconsistentTaskData();
|
|
3081
|
+
const consultedContext = createVoiceContext({
|
|
3082
|
+
consultInitiator: false,
|
|
3083
|
+
taskData: consultedTaskData,
|
|
3084
|
+
uiControlConfig: {
|
|
3085
|
+
...createVoiceContext().uiControlConfig,
|
|
3086
|
+
agentId: 'agent-2',
|
|
3087
|
+
voiceVariant: VOICE_VARIANT.WEBRTC,
|
|
3088
|
+
enableWxBetterTogether: true,
|
|
3089
|
+
},
|
|
3090
|
+
});
|
|
3091
|
+
|
|
3092
|
+
const controls = computeUIControls(
|
|
3093
|
+
TaskState.CONNECTED,
|
|
3094
|
+
consultedContext,
|
|
3095
|
+
consultedTaskData
|
|
3096
|
+
);
|
|
3097
|
+
|
|
3098
|
+
expect(controls.main.mute).toEqual({isVisible: true, isEnabled: true});
|
|
3099
|
+
});
|
|
3100
|
+
});
|
|
3101
|
+
});
|