@webex/contact-center 3.12.0-next.95 → 3.12.0-next.97
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/services/task/TaskUtils.js +51 -3
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +50 -14
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +57 -33
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/guards.js +42 -0
- 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 +78 -28
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/services/task/voice/Voice.js +5 -3
- package/dist/services/task/voice/Voice.js.map +1 -1
- package/dist/types/services/task/TaskUtils.d.ts +2 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +72 -22
- package/dist/types/services/task/state-machine/guards.d.ts +12 -0
- package/dist/types/services/task/state-machine/types.d.ts +2 -0
- package/dist/webex.js +1 -1
- package/package.json +2 -2
- package/src/services/task/TaskUtils.ts +100 -2
- package/src/services/task/state-machine/TaskStateMachine.ts +101 -12
- package/src/services/task/state-machine/actions.ts +88 -35
- package/src/services/task/state-machine/ai-docs/task-state-machine-spec.md +73 -11
- package/src/services/task/state-machine/guards.ts +39 -0
- package/src/services/task/state-machine/types.ts +2 -0
- package/src/services/task/state-machine/uiControlsComputer.ts +135 -41
- package/src/services/task/voice/Voice.ts +6 -3
- package/test/unit/spec/services/task/TaskUtils.ts +29 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +826 -0
- package/test/unit/spec/services/task/state-machine/guards.ts +158 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +648 -5
- package/test/unit/spec/services/task/voice/Voice.ts +18 -0
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -539,6 +539,7 @@ function createVoiceContext(overrides: Partial<TaskContext> = {}): TaskContext {
|
|
|
539
539
|
consultDestinationAgentId: null,
|
|
540
540
|
consultDestinationAgentJoined: true,
|
|
541
541
|
consultCallHeld: false,
|
|
542
|
+
hideBlindTransferForEpDnPendingMerge: false,
|
|
542
543
|
recordingControlsAvailable: true,
|
|
543
544
|
recordingInProgress: true,
|
|
544
545
|
uiControlConfig: {
|
|
@@ -741,7 +742,13 @@ describe('uiControlsComputer consult initiator controls', () => {
|
|
|
741
742
|
taskData: {
|
|
742
743
|
...consultedTaskData,
|
|
743
744
|
isConsulted: true,
|
|
745
|
+
agentId: 'agent-2',
|
|
744
746
|
} as any,
|
|
747
|
+
uiControlConfig: {
|
|
748
|
+
...createVoiceContext().uiControlConfig,
|
|
749
|
+
agentId: 'agent-2',
|
|
750
|
+
isEndConsultEnabled: true,
|
|
751
|
+
},
|
|
745
752
|
});
|
|
746
753
|
|
|
747
754
|
const uiControls = computeUIControls(
|
|
@@ -751,6 +758,10 @@ describe('uiControlsComputer consult initiator controls', () => {
|
|
|
751
758
|
);
|
|
752
759
|
|
|
753
760
|
expect(uiControls.consult.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
761
|
+
expect(uiControls.consult.conference).toEqual({isVisible: false, isEnabled: false});
|
|
762
|
+
expect(uiControls.consult.mergeToConference).toEqual({isVisible: false, isEnabled: false});
|
|
763
|
+
expect(uiControls.consult.switch).toEqual({isVisible: false, isEnabled: false});
|
|
764
|
+
expect(uiControls.consult.endConsult).toEqual({isVisible: true, isEnabled: true});
|
|
754
765
|
});
|
|
755
766
|
|
|
756
767
|
it('hides main-leg controls for consulted agent when payload isConsulted is stale false', () => {
|
|
@@ -853,10 +864,124 @@ describe('uiControlsComputer consult initiator controls', () => {
|
|
|
853
864
|
|
|
854
865
|
const uiControls = computeUIControls(TaskState.CONFERENCING, context, taskData);
|
|
855
866
|
|
|
867
|
+
expect(uiControls.activeLeg).toBe('main');
|
|
856
868
|
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
857
869
|
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
858
870
|
});
|
|
859
871
|
|
|
872
|
+
it('keeps main leg active for conference owner when another agent consults (CAI-8329)', () => {
|
|
873
|
+
const taskData = createTaskData({
|
|
874
|
+
agentId: 'agent-3',
|
|
875
|
+
type: 'AgentConsultCreated' as any,
|
|
876
|
+
consultMediaResourceId: 'consult-media-1',
|
|
877
|
+
consultingAgentId: 'agent-3',
|
|
878
|
+
isConsulted: false,
|
|
879
|
+
interaction: {
|
|
880
|
+
state: 'conference',
|
|
881
|
+
interactionId: 'interaction-1',
|
|
882
|
+
mainInteractionId: 'interaction-1',
|
|
883
|
+
owner: 'agent-1',
|
|
884
|
+
callProcessingDetails: {
|
|
885
|
+
conferenceHoldParticipant: 'true',
|
|
886
|
+
recordInProgress: 'true',
|
|
887
|
+
recordingStarted: 'true',
|
|
888
|
+
},
|
|
889
|
+
participants: {
|
|
890
|
+
'agent-1': {
|
|
891
|
+
id: 'agent-1',
|
|
892
|
+
pType: 'Agent',
|
|
893
|
+
hasJoined: true,
|
|
894
|
+
hasLeft: false,
|
|
895
|
+
consultState: 'conferencing',
|
|
896
|
+
},
|
|
897
|
+
'agent-2': {
|
|
898
|
+
id: 'agent-2',
|
|
899
|
+
pType: 'Agent',
|
|
900
|
+
hasJoined: false,
|
|
901
|
+
hasLeft: false,
|
|
902
|
+
isConsulted: true,
|
|
903
|
+
},
|
|
904
|
+
'agent-3': {
|
|
905
|
+
id: 'agent-3',
|
|
906
|
+
pType: 'Agent',
|
|
907
|
+
hasJoined: true,
|
|
908
|
+
hasLeft: false,
|
|
909
|
+
consultState: 'consultInitiated',
|
|
910
|
+
},
|
|
911
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasJoined: true, hasLeft: false},
|
|
912
|
+
} as any,
|
|
913
|
+
media: {
|
|
914
|
+
'interaction-1': {
|
|
915
|
+
mediaResourceId: 'interaction-1',
|
|
916
|
+
mType: 'mainCall',
|
|
917
|
+
isHold: true,
|
|
918
|
+
participants: ['customer-1', 'agent-1', 'agent-3'],
|
|
919
|
+
},
|
|
920
|
+
'consult-media-1': {
|
|
921
|
+
mediaResourceId: 'consult-media-1',
|
|
922
|
+
mType: 'consult',
|
|
923
|
+
isHold: false,
|
|
924
|
+
participants: ['agent-2', 'agent-3'],
|
|
925
|
+
},
|
|
926
|
+
} as any,
|
|
927
|
+
} as any,
|
|
928
|
+
});
|
|
929
|
+
const baseContext = createVoiceContext();
|
|
930
|
+
const context = createVoiceContext({
|
|
931
|
+
consultInitiator: true,
|
|
932
|
+
consultFromConference: true,
|
|
933
|
+
consultDestinationAgentJoined: true,
|
|
934
|
+
recordingControlsAvailable: true,
|
|
935
|
+
recordingInProgress: true,
|
|
936
|
+
taskData,
|
|
937
|
+
uiControlConfig: {
|
|
938
|
+
...baseContext.uiControlConfig,
|
|
939
|
+
agentId: 'agent-1',
|
|
940
|
+
},
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, taskData);
|
|
944
|
+
|
|
945
|
+
expect(uiControls.activeLeg).toBe('main');
|
|
946
|
+
expect(uiControls.main.hold).toEqual({isVisible: true, isEnabled: false});
|
|
947
|
+
expect(uiControls.main.consult).toEqual({isVisible: true, isEnabled: false});
|
|
948
|
+
expect(uiControls.main.recording).toEqual({isVisible: true, isEnabled: true});
|
|
949
|
+
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
950
|
+
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
951
|
+
expect(uiControls.main.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
952
|
+
expect(uiControls.main.transferConference).toEqual({isVisible: false, isEnabled: false});
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
it('detects other-agent consult in progress with mixed-case Agent pType (CAI-8329)', () => {
|
|
956
|
+
const taskData = createConferenceWithOtherAgentConsultPendingTaskData();
|
|
957
|
+
const mixedCaseTaskData = createTaskData({
|
|
958
|
+
...taskData,
|
|
959
|
+
interaction: {
|
|
960
|
+
...taskData.interaction,
|
|
961
|
+
participants: {
|
|
962
|
+
...taskData.interaction?.participants,
|
|
963
|
+
'agent-1': {
|
|
964
|
+
...(taskData.interaction?.participants as any)['agent-1'],
|
|
965
|
+
pType: 'Agent',
|
|
966
|
+
},
|
|
967
|
+
},
|
|
968
|
+
} as any,
|
|
969
|
+
});
|
|
970
|
+
const baseContext = createVoiceContext();
|
|
971
|
+
const context = createVoiceContext({
|
|
972
|
+
consultInitiator: false,
|
|
973
|
+
taskData: mixedCaseTaskData,
|
|
974
|
+
uiControlConfig: {
|
|
975
|
+
...baseContext.uiControlConfig,
|
|
976
|
+
agentId: 'agent-2',
|
|
977
|
+
},
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, mixedCaseTaskData);
|
|
981
|
+
|
|
982
|
+
expect(uiControls.main.consult).toEqual({isVisible: true, isEnabled: false});
|
|
983
|
+
});
|
|
984
|
+
|
|
860
985
|
it('enables end and exitConference on unheld main leg for non-initiator during active conference consult', () => {
|
|
861
986
|
const taskData = createUnheldConferenceWithActiveConsultTaskData();
|
|
862
987
|
const baseContext = createVoiceContext();
|
|
@@ -1734,6 +1859,67 @@ describe('uiControlsComputer consult initiator controls', () => {
|
|
|
1734
1859
|
expect(uiControls.consult.endConsult).toEqual({isVisible: false, isEnabled: false});
|
|
1735
1860
|
});
|
|
1736
1861
|
|
|
1862
|
+
it('enables main.end after resume when stale consult media persists after RONA (AgentContactUnheld)', () => {
|
|
1863
|
+
const unheldTaskData = createTaskData({
|
|
1864
|
+
agentId: 'agent-1',
|
|
1865
|
+
mediaResourceId: 'interaction-1',
|
|
1866
|
+
consultMediaResourceId: 'consult-media',
|
|
1867
|
+
isConsulted: false,
|
|
1868
|
+
type: 'AgentContactUnheld' as any,
|
|
1869
|
+
interaction: {
|
|
1870
|
+
state: 'connected',
|
|
1871
|
+
interactionId: 'interaction-1',
|
|
1872
|
+
mainInteractionId: 'interaction-1',
|
|
1873
|
+
owner: 'agent-1',
|
|
1874
|
+
participants: {
|
|
1875
|
+
'agent-1': {
|
|
1876
|
+
id: 'agent-1',
|
|
1877
|
+
pType: 'Agent',
|
|
1878
|
+
hasLeft: false,
|
|
1879
|
+
consultState: 'consultCompleted',
|
|
1880
|
+
isConsulted: false,
|
|
1881
|
+
},
|
|
1882
|
+
'agent-2': {
|
|
1883
|
+
id: 'agent-2',
|
|
1884
|
+
pType: 'Agent',
|
|
1885
|
+
hasLeft: false,
|
|
1886
|
+
hasJoined: false,
|
|
1887
|
+
consultState: 'consultReserved',
|
|
1888
|
+
isConsulted: true,
|
|
1889
|
+
},
|
|
1890
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasLeft: false, hasJoined: true},
|
|
1891
|
+
} as any,
|
|
1892
|
+
media: {
|
|
1893
|
+
'interaction-1': {
|
|
1894
|
+
mediaResourceId: 'interaction-1',
|
|
1895
|
+
mType: 'mainCall',
|
|
1896
|
+
isHold: false,
|
|
1897
|
+
participants: ['customer-1', 'agent-1'],
|
|
1898
|
+
},
|
|
1899
|
+
'consult-media': {
|
|
1900
|
+
mediaResourceId: 'consult-media',
|
|
1901
|
+
mType: 'consult',
|
|
1902
|
+
isHold: false,
|
|
1903
|
+
participants: ['agent-1', 'agent-2'],
|
|
1904
|
+
},
|
|
1905
|
+
} as any,
|
|
1906
|
+
} as any,
|
|
1907
|
+
});
|
|
1908
|
+
const context = createVoiceContext({
|
|
1909
|
+
taskData: unheldTaskData as any,
|
|
1910
|
+
consultInitiator: false,
|
|
1911
|
+
consultDestinationAgentJoined: false,
|
|
1912
|
+
consultCallHeld: false,
|
|
1913
|
+
});
|
|
1914
|
+
|
|
1915
|
+
const uiControls = computeUIControls(TaskState.CONNECTED, context, unheldTaskData as any);
|
|
1916
|
+
|
|
1917
|
+
expect(uiControls.activeLeg).toBe('main');
|
|
1918
|
+
expect(uiControls.main.hold).toEqual({isVisible: true, isEnabled: true});
|
|
1919
|
+
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
1920
|
+
expect(uiControls.consult.endConsult).toEqual({isVisible: false, isEnabled: false});
|
|
1921
|
+
});
|
|
1922
|
+
|
|
1737
1923
|
});
|
|
1738
1924
|
|
|
1739
1925
|
describe('uiControlsComputer outdial accept/decline controls', () => {
|
|
@@ -1802,6 +1988,7 @@ describe('uiControlsComputer WebRTC call-control end button', () => {
|
|
|
1802
1988
|
consultDestinationAgentId: null,
|
|
1803
1989
|
consultDestinationAgentJoined: false,
|
|
1804
1990
|
consultCallHeld: false,
|
|
1991
|
+
hideBlindTransferForEpDnPendingMerge: false,
|
|
1805
1992
|
recordingControlsAvailable: true,
|
|
1806
1993
|
recordingInProgress: true,
|
|
1807
1994
|
uiControlConfig: {
|
|
@@ -1888,6 +2075,7 @@ describe('uiControlsComputer conference controls', () => {
|
|
|
1888
2075
|
consultDestinationAgentId: null,
|
|
1889
2076
|
consultDestinationAgentJoined: false,
|
|
1890
2077
|
consultCallHeld: false,
|
|
2078
|
+
hideBlindTransferForEpDnPendingMerge: false,
|
|
1891
2079
|
recordingControlsAvailable: true,
|
|
1892
2080
|
recordingInProgress: true,
|
|
1893
2081
|
uiControlConfig: {
|
|
@@ -1914,14 +2102,468 @@ describe('uiControlsComputer conference controls', () => {
|
|
|
1914
2102
|
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
1915
2103
|
});
|
|
1916
2104
|
|
|
1917
|
-
it('
|
|
1918
|
-
const
|
|
2105
|
+
it('hides blind transfer on main after EP-DN consult merge before destination joins (CAI-8329)', () => {
|
|
2106
|
+
const taskData = createTaskData({
|
|
2107
|
+
agentId: 'agent-1',
|
|
2108
|
+
consultingAgentId: 'agent-1',
|
|
2109
|
+
consultMediaResourceId: 'consult-media-1',
|
|
2110
|
+
isConsulted: false,
|
|
2111
|
+
destinationType: 'EP-DN',
|
|
2112
|
+
type: 'AgentConsultCreated' as any,
|
|
2113
|
+
interaction: {
|
|
2114
|
+
state: 'conference',
|
|
2115
|
+
interactionId: 'interaction-1',
|
|
2116
|
+
mainInteractionId: 'interaction-1',
|
|
2117
|
+
owner: 'agent-1',
|
|
2118
|
+
participants: {
|
|
2119
|
+
'agent-1': {
|
|
2120
|
+
id: 'agent-1',
|
|
2121
|
+
pType: 'Agent',
|
|
2122
|
+
hasJoined: true,
|
|
2123
|
+
hasLeft: false,
|
|
2124
|
+
consultState: 'consulting',
|
|
2125
|
+
},
|
|
2126
|
+
'dn-dest': {
|
|
2127
|
+
id: 'dn-dest',
|
|
2128
|
+
pType: 'DN',
|
|
2129
|
+
hasLeft: false,
|
|
2130
|
+
hasJoined: false,
|
|
2131
|
+
},
|
|
2132
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasJoined: true, hasLeft: false},
|
|
2133
|
+
} as any,
|
|
2134
|
+
media: {
|
|
2135
|
+
'interaction-1': {
|
|
2136
|
+
mediaResourceId: 'interaction-1',
|
|
2137
|
+
mType: 'mainCall',
|
|
2138
|
+
participants: ['agent-1', 'customer-1'],
|
|
2139
|
+
isHold: false,
|
|
2140
|
+
},
|
|
2141
|
+
'consult-media-1': {
|
|
2142
|
+
mediaResourceId: 'consult-media-1',
|
|
2143
|
+
mType: 'consult',
|
|
2144
|
+
participants: ['agent-1', 'dn-dest'],
|
|
2145
|
+
isHold: false,
|
|
2146
|
+
},
|
|
2147
|
+
} as any,
|
|
2148
|
+
} as any,
|
|
2149
|
+
});
|
|
2150
|
+
const context = createConferenceContext(1, {
|
|
2151
|
+
consultInitiator: false,
|
|
2152
|
+
consultFromConference: false,
|
|
2153
|
+
consultDestinationType: null,
|
|
2154
|
+
hideBlindTransferForEpDnPendingMerge: true,
|
|
2155
|
+
consultCallHeld: false,
|
|
2156
|
+
taskData,
|
|
2157
|
+
uiControlConfig: {
|
|
2158
|
+
isEndTaskEnabled: true,
|
|
2159
|
+
isEndConsultEnabled: true,
|
|
2160
|
+
channelType: TASK_CHANNEL_TYPE.VOICE,
|
|
2161
|
+
isRecordingEnabled: true,
|
|
2162
|
+
voiceVariant: VOICE_VARIANT.WEBRTC,
|
|
2163
|
+
agentId: 'agent-1',
|
|
2164
|
+
},
|
|
2165
|
+
});
|
|
1919
2166
|
|
|
1920
|
-
const uiControls = computeUIControls(TaskState.CONFERENCING, context,
|
|
2167
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, taskData);
|
|
1921
2168
|
|
|
1922
2169
|
expect(uiControls.main.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
1923
|
-
expect(uiControls.main.
|
|
1924
|
-
expect(uiControls.main.
|
|
2170
|
+
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
2171
|
+
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
2172
|
+
});
|
|
2173
|
+
|
|
2174
|
+
it('hides blind transfer on main after EP-DN consult merge when destination is hydrated as joined (CAI-8329)', () => {
|
|
2175
|
+
const taskData = createTaskData({
|
|
2176
|
+
agentId: 'agent-1',
|
|
2177
|
+
consultingAgentId: 'agent-1',
|
|
2178
|
+
consultMediaResourceId: 'consult-media-1',
|
|
2179
|
+
isConsulted: false,
|
|
2180
|
+
destinationType: 'EP-DN',
|
|
2181
|
+
type: 'AgentConsultCreated' as any,
|
|
2182
|
+
interaction: {
|
|
2183
|
+
state: 'conference',
|
|
2184
|
+
interactionId: 'interaction-1',
|
|
2185
|
+
mainInteractionId: 'interaction-1',
|
|
2186
|
+
owner: 'agent-1',
|
|
2187
|
+
callProcessingDetails: {
|
|
2188
|
+
consultDestinationAgentJoined: 'true',
|
|
2189
|
+
},
|
|
2190
|
+
participants: {
|
|
2191
|
+
'agent-1': {
|
|
2192
|
+
id: 'agent-1',
|
|
2193
|
+
pType: 'Agent',
|
|
2194
|
+
hasJoined: true,
|
|
2195
|
+
hasLeft: false,
|
|
2196
|
+
consultState: 'consulting',
|
|
2197
|
+
},
|
|
2198
|
+
'dn-dest': {
|
|
2199
|
+
id: 'dn-dest',
|
|
2200
|
+
pType: 'DN',
|
|
2201
|
+
hasLeft: false,
|
|
2202
|
+
hasJoined: false,
|
|
2203
|
+
},
|
|
2204
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasJoined: true, hasLeft: false},
|
|
2205
|
+
} as any,
|
|
2206
|
+
media: {
|
|
2207
|
+
'interaction-1': {
|
|
2208
|
+
mediaResourceId: 'interaction-1',
|
|
2209
|
+
mType: 'mainCall',
|
|
2210
|
+
participants: ['agent-1', 'customer-1'],
|
|
2211
|
+
isHold: false,
|
|
2212
|
+
},
|
|
2213
|
+
'consult-media-1': {
|
|
2214
|
+
mediaResourceId: 'consult-media-1',
|
|
2215
|
+
mType: 'consult',
|
|
2216
|
+
participants: ['agent-1', 'dn-dest'],
|
|
2217
|
+
isHold: false,
|
|
2218
|
+
},
|
|
2219
|
+
} as any,
|
|
2220
|
+
} as any,
|
|
2221
|
+
});
|
|
2222
|
+
const context = createConferenceContext(1, {
|
|
2223
|
+
consultInitiator: false,
|
|
2224
|
+
consultFromConference: false,
|
|
2225
|
+
consultDestinationType: null,
|
|
2226
|
+
hideBlindTransferForEpDnPendingMerge: true,
|
|
2227
|
+
consultCallHeld: false,
|
|
2228
|
+
taskData,
|
|
2229
|
+
uiControlConfig: {
|
|
2230
|
+
isEndTaskEnabled: true,
|
|
2231
|
+
isEndConsultEnabled: true,
|
|
2232
|
+
channelType: TASK_CHANNEL_TYPE.VOICE,
|
|
2233
|
+
isRecordingEnabled: true,
|
|
2234
|
+
voiceVariant: VOICE_VARIANT.WEBRTC,
|
|
2235
|
+
agentId: 'agent-1',
|
|
2236
|
+
},
|
|
2237
|
+
});
|
|
2238
|
+
|
|
2239
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, taskData);
|
|
2240
|
+
|
|
2241
|
+
expect(uiControls.main.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
2242
|
+
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
2243
|
+
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
2244
|
+
});
|
|
2245
|
+
|
|
2246
|
+
it('hides blind transfer on AgentConsultConferencing after clearConsultState sets flag (CAI-8329)', () => {
|
|
2247
|
+
const agentId = '4b496e73-55e4-4d74-a53c-469babdd8326';
|
|
2248
|
+
const mainInteractionId = '08f427ed-71d8-41df-8a44-43e1bb2b2074';
|
|
2249
|
+
const consultMediaId = 'e6592ab7-8f56-4132-87a9-48c4c262df3c';
|
|
2250
|
+
const taskData = createTaskData({
|
|
2251
|
+
agentId,
|
|
2252
|
+
consultMediaResourceId: consultMediaId,
|
|
2253
|
+
isConsulted: false,
|
|
2254
|
+
type: 'AgentConsultConferencing' as any,
|
|
2255
|
+
interaction: {
|
|
2256
|
+
state: 'conference',
|
|
2257
|
+
interactionId: mainInteractionId,
|
|
2258
|
+
mainInteractionId,
|
|
2259
|
+
owner: agentId,
|
|
2260
|
+
callProcessingDetails: {
|
|
2261
|
+
relationshipType: 'consult',
|
|
2262
|
+
childInteractionId: consultMediaId,
|
|
2263
|
+
},
|
|
2264
|
+
participants: {
|
|
2265
|
+
[agentId]: {
|
|
2266
|
+
id: agentId,
|
|
2267
|
+
pType: 'Agent',
|
|
2268
|
+
hasJoined: true,
|
|
2269
|
+
hasLeft: false,
|
|
2270
|
+
consultState: 'conferencing',
|
|
2271
|
+
isConsulted: false,
|
|
2272
|
+
},
|
|
2273
|
+
'+13159998087': {
|
|
2274
|
+
id: '+13159998087',
|
|
2275
|
+
pType: 'EP-DN',
|
|
2276
|
+
type: 'EpDn',
|
|
2277
|
+
hasLeft: false,
|
|
2278
|
+
},
|
|
2279
|
+
'+14696762938': {
|
|
2280
|
+
id: '+14696762938',
|
|
2281
|
+
pType: 'Customer',
|
|
2282
|
+
hasJoined: true,
|
|
2283
|
+
hasLeft: false,
|
|
2284
|
+
},
|
|
2285
|
+
} as any,
|
|
2286
|
+
media: {
|
|
2287
|
+
[mainInteractionId]: {
|
|
2288
|
+
mediaResourceId: mainInteractionId,
|
|
2289
|
+
mType: 'mainCall',
|
|
2290
|
+
participants: ['+14696762938', agentId],
|
|
2291
|
+
isHold: false,
|
|
2292
|
+
},
|
|
2293
|
+
[consultMediaId]: {
|
|
2294
|
+
mediaResourceId: consultMediaId,
|
|
2295
|
+
mType: 'consult',
|
|
2296
|
+
participants: ['+13159998087', agentId],
|
|
2297
|
+
isHold: false,
|
|
2298
|
+
},
|
|
2299
|
+
} as any,
|
|
2300
|
+
} as any,
|
|
2301
|
+
});
|
|
2302
|
+
const context = createConferenceContext(1, {
|
|
2303
|
+
consultInitiator: false,
|
|
2304
|
+
consultFromConference: false,
|
|
2305
|
+
consultDestinationType: null,
|
|
2306
|
+
hideBlindTransferForEpDnPendingMerge: true,
|
|
2307
|
+
consultCallHeld: false,
|
|
2308
|
+
taskData,
|
|
2309
|
+
uiControlConfig: {
|
|
2310
|
+
isEndTaskEnabled: true,
|
|
2311
|
+
isEndConsultEnabled: true,
|
|
2312
|
+
channelType: TASK_CHANNEL_TYPE.VOICE,
|
|
2313
|
+
isRecordingEnabled: true,
|
|
2314
|
+
voiceVariant: VOICE_VARIANT.WEBRTC,
|
|
2315
|
+
agentId,
|
|
2316
|
+
},
|
|
2317
|
+
});
|
|
2318
|
+
|
|
2319
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, taskData);
|
|
2320
|
+
|
|
2321
|
+
expect(uiControls.activeLeg).toBe('main');
|
|
2322
|
+
expect(uiControls.main.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
2323
|
+
expect(uiControls.main.mute).toEqual({isVisible: true, isEnabled: true});
|
|
2324
|
+
expect(uiControls.main.recording).toEqual({isVisible: true, isEnabled: true});
|
|
2325
|
+
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
2326
|
+
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
2327
|
+
});
|
|
2328
|
+
|
|
2329
|
+
it('shows blind transfer on pending conference when consult context is absent (CAI-8329)', () => {
|
|
2330
|
+
const context = createConferenceContext(1, {
|
|
2331
|
+
consultInitiator: false,
|
|
2332
|
+
consultFromConference: false,
|
|
2333
|
+
consultDestinationType: null,
|
|
2334
|
+
});
|
|
2335
|
+
|
|
2336
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, context.taskData);
|
|
2337
|
+
|
|
2338
|
+
expect(uiControls.main.transfer).toEqual({isVisible: true, isEnabled: true});
|
|
2339
|
+
});
|
|
2340
|
+
|
|
2341
|
+
it('real conference (participantCount > 1): transfer hidden, recording visible when controls available, consult enabled, exitConference visible', () => {
|
|
2342
|
+
const context = createConferenceContext(2);
|
|
2343
|
+
|
|
2344
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, context.taskData);
|
|
2345
|
+
|
|
2346
|
+
expect(uiControls.main.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
2347
|
+
expect(uiControls.main.recording).toEqual({isVisible: true, isEnabled: true});
|
|
2348
|
+
expect(uiControls.main.consult).toEqual({isVisible: true, isEnabled: true});
|
|
2349
|
+
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
2350
|
+
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
2351
|
+
});
|
|
2352
|
+
|
|
2353
|
+
it('real conference (participantCount > 1): recording hidden when recording controls unavailable', () => {
|
|
2354
|
+
const context = createConferenceContext(2, {
|
|
2355
|
+
recordingControlsAvailable: false,
|
|
2356
|
+
recordingInProgress: false,
|
|
2357
|
+
});
|
|
2358
|
+
|
|
2359
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, context.taskData);
|
|
2360
|
+
|
|
2361
|
+
expect(uiControls.main.recording).toEqual({isVisible: false, isEnabled: false});
|
|
2362
|
+
});
|
|
2363
|
+
|
|
2364
|
+
it('shows recording when second agent joins EP-DN merged conference (CAI-8329)', () => {
|
|
2365
|
+
const taskData = createTaskData({
|
|
2366
|
+
agentId: 'agent-1',
|
|
2367
|
+
type: 'ContactUpdated' as any,
|
|
2368
|
+
interaction: {
|
|
2369
|
+
state: 'conference',
|
|
2370
|
+
interactionId: 'interaction-1',
|
|
2371
|
+
mainInteractionId: 'interaction-1',
|
|
2372
|
+
owner: 'agent-1',
|
|
2373
|
+
callProcessingDetails: {
|
|
2374
|
+
recordInProgress: 'true',
|
|
2375
|
+
recordingStarted: 'true',
|
|
2376
|
+
epDnParticipantRemoved: '+13159998059',
|
|
2377
|
+
},
|
|
2378
|
+
participants: {
|
|
2379
|
+
'agent-1': {
|
|
2380
|
+
id: 'agent-1',
|
|
2381
|
+
pType: 'Agent',
|
|
2382
|
+
hasJoined: true,
|
|
2383
|
+
hasLeft: false,
|
|
2384
|
+
consultState: 'conferencing',
|
|
2385
|
+
},
|
|
2386
|
+
'agent-2': {
|
|
2387
|
+
id: 'agent-2',
|
|
2388
|
+
pType: 'Agent',
|
|
2389
|
+
hasJoined: true,
|
|
2390
|
+
hasLeft: false,
|
|
2391
|
+
consultState: 'conferencing',
|
|
2392
|
+
},
|
|
2393
|
+
'customer-1': {id: 'customer-1', pType: 'Customer', hasJoined: true, hasLeft: false},
|
|
2394
|
+
} as any,
|
|
2395
|
+
media: {
|
|
2396
|
+
'interaction-1': {
|
|
2397
|
+
mediaResourceId: 'interaction-1',
|
|
2398
|
+
mType: 'mainCall',
|
|
2399
|
+
participants: ['customer-1', 'agent-1', 'agent-2'],
|
|
2400
|
+
isHold: false,
|
|
2401
|
+
},
|
|
2402
|
+
} as any,
|
|
2403
|
+
} as any,
|
|
2404
|
+
});
|
|
2405
|
+
const context = createConferenceContext(2, {
|
|
2406
|
+
hideBlindTransferForEpDnPendingMerge: false,
|
|
2407
|
+
taskData,
|
|
2408
|
+
});
|
|
2409
|
+
|
|
2410
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, taskData);
|
|
2411
|
+
|
|
2412
|
+
expect(uiControls.main.recording).toEqual({isVisible: true, isEnabled: true});
|
|
2413
|
+
expect(uiControls.main.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
2414
|
+
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
2415
|
+
});
|
|
2416
|
+
|
|
2417
|
+
|
|
2418
|
+
it('post_call after customer exit: only exitConference and end enabled during EP-DN pending merge (CAI-8329)', () => {
|
|
2419
|
+
const taskData = createTaskData({
|
|
2420
|
+
agentId: 'agent-1',
|
|
2421
|
+
consultingAgentId: 'agent-1',
|
|
2422
|
+
consultMediaResourceId: 'consult-media-1',
|
|
2423
|
+
isConsulted: false,
|
|
2424
|
+
destinationType: 'EP-DN',
|
|
2425
|
+
type: 'ParticipantPostCallActivity' as any,
|
|
2426
|
+
interaction: {
|
|
2427
|
+
state: 'post_call',
|
|
2428
|
+
interactionId: 'interaction-1',
|
|
2429
|
+
mainInteractionId: 'interaction-1',
|
|
2430
|
+
owner: 'agent-1',
|
|
2431
|
+
callProcessingDetails: {
|
|
2432
|
+
hasCustomerLeft: 'true',
|
|
2433
|
+
},
|
|
2434
|
+
participants: {
|
|
2435
|
+
'agent-1': {
|
|
2436
|
+
id: 'agent-1',
|
|
2437
|
+
pType: 'Agent',
|
|
2438
|
+
hasJoined: true,
|
|
2439
|
+
hasLeft: false,
|
|
2440
|
+
consultState: 'conferencing',
|
|
2441
|
+
},
|
|
2442
|
+
'+13159998059': {
|
|
2443
|
+
id: '+13159998059',
|
|
2444
|
+
pType: 'EP-DN',
|
|
2445
|
+
hasLeft: false,
|
|
2446
|
+
hasJoined: false,
|
|
2447
|
+
},
|
|
2448
|
+
'+14696762938': {
|
|
2449
|
+
id: '+14696762938',
|
|
2450
|
+
pType: 'Customer',
|
|
2451
|
+
hasJoined: true,
|
|
2452
|
+
hasLeft: true,
|
|
2453
|
+
},
|
|
2454
|
+
} as any,
|
|
2455
|
+
media: {
|
|
2456
|
+
'interaction-1': {
|
|
2457
|
+
mediaResourceId: 'interaction-1',
|
|
2458
|
+
mType: 'mainCall',
|
|
2459
|
+
participants: ['agent-1'],
|
|
2460
|
+
isHold: false,
|
|
2461
|
+
},
|
|
2462
|
+
'consult-media-1': {
|
|
2463
|
+
mediaResourceId: 'consult-media-1',
|
|
2464
|
+
mType: 'consult',
|
|
2465
|
+
participants: ['+13159998059', 'agent-1'],
|
|
2466
|
+
isHold: false,
|
|
2467
|
+
},
|
|
2468
|
+
} as any,
|
|
2469
|
+
} as any,
|
|
2470
|
+
});
|
|
2471
|
+
const context = createConferenceContext(1, {
|
|
2472
|
+
consultInitiator: true,
|
|
2473
|
+
consultFromConference: true,
|
|
2474
|
+
hideBlindTransferForEpDnPendingMerge: true,
|
|
2475
|
+
taskData,
|
|
2476
|
+
uiControlConfig: {
|
|
2477
|
+
isEndTaskEnabled: true,
|
|
2478
|
+
isEndConsultEnabled: true,
|
|
2479
|
+
channelType: TASK_CHANNEL_TYPE.VOICE,
|
|
2480
|
+
isRecordingEnabled: true,
|
|
2481
|
+
voiceVariant: VOICE_VARIANT.WEBRTC,
|
|
2482
|
+
agentId: 'agent-1',
|
|
2483
|
+
},
|
|
2484
|
+
});
|
|
2485
|
+
|
|
2486
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, taskData);
|
|
2487
|
+
|
|
2488
|
+
expect(uiControls.main.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
2489
|
+
expect(uiControls.main.recording).toEqual({isVisible: true, isEnabled: false});
|
|
2490
|
+
expect(uiControls.main.hold).toEqual({isVisible: true, isEnabled: false});
|
|
2491
|
+
expect(uiControls.main.mute).toEqual({isVisible: true, isEnabled: false});
|
|
2492
|
+
expect(uiControls.main.consult).toEqual({isVisible: true, isEnabled: false});
|
|
2493
|
+
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
2494
|
+
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
2495
|
+
});
|
|
2496
|
+
|
|
2497
|
+
it('hides blind transfer after AgentConsultFailed ANOTHER_CONSULT_IN_PROGRESS during EP-DN pending merge (CAI-8329)', () => {
|
|
2498
|
+
const taskData = createTaskData({
|
|
2499
|
+
agentId: 'agent-1',
|
|
2500
|
+
consultingAgentId: 'agent-1',
|
|
2501
|
+
consultMediaResourceId: 'consult-media-1',
|
|
2502
|
+
isConsulted: false,
|
|
2503
|
+
destinationType: 'Agent',
|
|
2504
|
+
reason: 'ANOTHER_CONSULT_IN_PROGRESS',
|
|
2505
|
+
type: 'AgentConsultFailed' as any,
|
|
2506
|
+
interaction: {
|
|
2507
|
+
state: 'conference',
|
|
2508
|
+
interactionId: 'interaction-1',
|
|
2509
|
+
mainInteractionId: 'interaction-1',
|
|
2510
|
+
owner: 'agent-1',
|
|
2511
|
+
participants: {
|
|
2512
|
+
'agent-1': {
|
|
2513
|
+
id: 'agent-1',
|
|
2514
|
+
pType: 'Agent',
|
|
2515
|
+
hasJoined: true,
|
|
2516
|
+
hasLeft: false,
|
|
2517
|
+
consultState: 'conferencing',
|
|
2518
|
+
},
|
|
2519
|
+
'+13159998059': {
|
|
2520
|
+
id: '+13159998059',
|
|
2521
|
+
pType: 'EP-DN',
|
|
2522
|
+
hasLeft: false,
|
|
2523
|
+
hasJoined: false,
|
|
2524
|
+
},
|
|
2525
|
+
'+14696762938': {
|
|
2526
|
+
id: '+14696762938',
|
|
2527
|
+
pType: 'Customer',
|
|
2528
|
+
hasJoined: true,
|
|
2529
|
+
hasLeft: false,
|
|
2530
|
+
},
|
|
2531
|
+
} as any,
|
|
2532
|
+
media: {
|
|
2533
|
+
'interaction-1': {
|
|
2534
|
+
mediaResourceId: 'interaction-1',
|
|
2535
|
+
mType: 'mainCall',
|
|
2536
|
+
participants: ['agent-1', '+14696762938'],
|
|
2537
|
+
isHold: false,
|
|
2538
|
+
},
|
|
2539
|
+
'consult-media-1': {
|
|
2540
|
+
mediaResourceId: 'consult-media-1',
|
|
2541
|
+
mType: 'consult',
|
|
2542
|
+
participants: ['+13159998059', 'agent-1'],
|
|
2543
|
+
isHold: false,
|
|
2544
|
+
},
|
|
2545
|
+
} as any,
|
|
2546
|
+
} as any,
|
|
2547
|
+
});
|
|
2548
|
+
const context = createConferenceContext(1, {
|
|
2549
|
+
consultInitiator: true,
|
|
2550
|
+
consultFromConference: true,
|
|
2551
|
+
hideBlindTransferForEpDnPendingMerge: true,
|
|
2552
|
+
taskData,
|
|
2553
|
+
uiControlConfig: {
|
|
2554
|
+
isEndTaskEnabled: true,
|
|
2555
|
+
isEndConsultEnabled: true,
|
|
2556
|
+
channelType: TASK_CHANNEL_TYPE.VOICE,
|
|
2557
|
+
isRecordingEnabled: true,
|
|
2558
|
+
voiceVariant: VOICE_VARIANT.WEBRTC,
|
|
2559
|
+
agentId: 'agent-1',
|
|
2560
|
+
},
|
|
2561
|
+
});
|
|
2562
|
+
|
|
2563
|
+
const uiControls = computeUIControls(TaskState.CONFERENCING, context, taskData);
|
|
2564
|
+
|
|
2565
|
+
expect(uiControls.main.transfer).toEqual({isVisible: false, isEnabled: false});
|
|
2566
|
+
expect(uiControls.main.consult).toEqual({isVisible: true, isEnabled: false});
|
|
1925
2567
|
expect(uiControls.main.exitConference).toEqual({isVisible: true, isEnabled: true});
|
|
1926
2568
|
expect(uiControls.main.end).toEqual({isVisible: true, isEnabled: true});
|
|
1927
2569
|
});
|
|
@@ -1995,6 +2637,7 @@ describe('uiControlsComputer post-call consult controls (customer left)', () =>
|
|
|
1995
2637
|
consultDestinationAgentId: null,
|
|
1996
2638
|
consultDestinationAgentJoined: true,
|
|
1997
2639
|
consultCallHeld: false,
|
|
2640
|
+
hideBlindTransferForEpDnPendingMerge: false,
|
|
1998
2641
|
recordingControlsAvailable: true,
|
|
1999
2642
|
recordingInProgress: true,
|
|
2000
2643
|
uiControlConfig: {
|