@webex/contact-center 3.12.0-task-refactor.7 → 3.12.0-task-refactor.9
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 +3 -4
- package/dist/cc.js.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/services/ApiAiAssistant.js +74 -3
- package/dist/services/ApiAiAssistant.js.map +1 -1
- package/dist/services/config/types.js +9 -1
- package/dist/services/config/types.js.map +1 -1
- package/dist/services/task/Task.js +32 -0
- package/dist/services/task/Task.js.map +1 -1
- package/dist/services/task/TaskManager.js +7 -2
- package/dist/services/task/TaskManager.js.map +1 -1
- package/dist/services/task/TaskUtils.js +3 -1
- package/dist/services/task/TaskUtils.js.map +1 -1
- package/dist/services/task/state-machine/TaskStateMachine.js +76 -0
- package/dist/services/task/state-machine/TaskStateMachine.js.map +1 -1
- package/dist/services/task/state-machine/actions.js +113 -23
- package/dist/services/task/state-machine/actions.js.map +1 -1
- package/dist/services/task/state-machine/uiControlsComputer.js +99 -21
- package/dist/services/task/state-machine/uiControlsComputer.js.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/services/ApiAiAssistant.d.ts +10 -2
- package/dist/types/services/config/types.d.ts +16 -0
- package/dist/types/services/task/Task.d.ts +10 -0
- package/dist/types/services/task/state-machine/TaskStateMachine.d.ts +110 -0
- package/dist/types/services/task/state-machine/actions.d.ts +2 -0
- package/dist/types/types.d.ts +24 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -1
- package/dist/webex.js +1 -1
- package/package.json +1 -1
- package/src/cc.ts +6 -4
- package/src/constants.ts +1 -0
- package/src/metrics/constants.ts +2 -0
- package/src/services/ApiAiAssistant.ts +102 -2
- package/src/services/config/types.ts +8 -0
- package/src/services/task/Task.ts +34 -0
- package/src/services/task/TaskManager.ts +7 -2
- package/src/services/task/TaskUtils.ts +5 -3
- package/src/services/task/ai-docs/AGENTS.md +7 -0
- package/src/services/task/ai-docs/ARCHITECTURE.md +12 -0
- package/src/services/task/state-machine/TaskStateMachine.ts +104 -0
- package/src/services/task/state-machine/actions.ts +151 -25
- package/src/services/task/state-machine/uiControlsComputer.ts +173 -30
- package/src/types.ts +25 -0
- package/test/unit/spec/cc.ts +2 -0
- package/test/unit/spec/services/ApiAiAssistant.ts +105 -17
- package/test/unit/spec/services/task/Task.ts +61 -0
- package/test/unit/spec/services/task/TaskManager.ts +42 -0
- package/test/unit/spec/services/task/TaskUtils.ts +65 -0
- package/test/unit/spec/services/task/state-machine/TaskStateMachine.ts +676 -0
- package/test/unit/spec/services/task/state-machine/uiControlsComputer.ts +597 -0
- package/test/unit/spec/services/task/voice/WebRTC.ts +99 -106
- package/umd/contact-center.min.js +2 -2
- package/umd/contact-center.min.js.map +1 -1
|
@@ -78,6 +78,15 @@ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
|
|
|
78
78
|
[TaskEvent.HYDRATE]: {
|
|
79
79
|
actions: ['updateTaskData', 'emitTaskHydrate'],
|
|
80
80
|
},
|
|
81
|
+
// AgentConsultCreated from Stable Prod while already HELD/CONNECTED (external consult).
|
|
82
|
+
// Child states do not handle CONSULT_CREATED; wire here so updateTaskData + setConsultInitiator run.
|
|
83
|
+
[TaskEvent.CONSULT_CREATED]: {
|
|
84
|
+
actions: ['updateTaskData', 'setConsultInitiator'],
|
|
85
|
+
},
|
|
86
|
+
// AgentConsultFailed (RONA) while HELD/CONNECTED without passing through CONSULT_INITIATING.
|
|
87
|
+
[TaskEvent.CONSULT_FAILED]: {
|
|
88
|
+
actions: ['updateTaskData', 'handleConsultFailed'],
|
|
89
|
+
},
|
|
81
90
|
},
|
|
82
91
|
states: {
|
|
83
92
|
[TaskState.IDLE]: {
|
|
@@ -290,6 +299,24 @@ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
|
|
|
290
299
|
[TaskEvent.TRANSFER_FAILED]: {
|
|
291
300
|
actions: ['updateTaskData'],
|
|
292
301
|
},
|
|
302
|
+
// AgentConsultEnded from Stable Prod while on connected leg (external end consult).
|
|
303
|
+
[TaskEvent.CONSULT_END]: [
|
|
304
|
+
{
|
|
305
|
+
guard: ({context, event}) => {
|
|
306
|
+
if (context.consultInitiator !== true) return false;
|
|
307
|
+
const taskData = getTaskDataFromEvent(event);
|
|
308
|
+
const mainId = taskData?.interaction?.mainInteractionId || taskData?.interactionId;
|
|
309
|
+
|
|
310
|
+
return Boolean(mainId && taskData?.interaction?.media?.[mainId]?.isHold === true);
|
|
311
|
+
},
|
|
312
|
+
target: TaskState.HELD,
|
|
313
|
+
actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd'],
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
guard: ({context}) => context.consultInitiator === true,
|
|
317
|
+
actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd'],
|
|
318
|
+
},
|
|
319
|
+
],
|
|
293
320
|
// AgentContactEnded Event
|
|
294
321
|
[TaskEvent.CONTACT_ENDED]: [
|
|
295
322
|
{
|
|
@@ -370,6 +397,18 @@ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
|
|
|
370
397
|
target: TaskState.CONSULT_INITIATING,
|
|
371
398
|
actions: ['setConsultInitiator', 'setConsultDestination'],
|
|
372
399
|
},
|
|
400
|
+
// AgentConsulting while main leg is held (Task Refactor / Stable Prod consult accept).
|
|
401
|
+
[TaskEvent.CONSULTING_ACTIVE]: {
|
|
402
|
+
target: TaskState.CONSULTING,
|
|
403
|
+
actions: [
|
|
404
|
+
'setConsultInitiator',
|
|
405
|
+
'setConsultDestination',
|
|
406
|
+
'setConsultAgentJoined',
|
|
407
|
+
'updateTaskData',
|
|
408
|
+
'emitTaskConsultAccepted',
|
|
409
|
+
'emitTaskConsulting',
|
|
410
|
+
],
|
|
411
|
+
},
|
|
373
412
|
// TODO: This may not be a valid transition, need to be removed
|
|
374
413
|
// AgentConsultTransferred / AgentVTeamTransferred / AgentBlindTransferred
|
|
375
414
|
[TaskEvent.TRANSFER_SUCCESS]: [
|
|
@@ -402,6 +441,10 @@ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
|
|
|
402
441
|
actions: ['updateTaskData', 'markEnded', 'emitTaskEnd'],
|
|
403
442
|
},
|
|
404
443
|
],
|
|
444
|
+
// AgentConsultEnded from Stable Prod while main leg is held (external end consult).
|
|
445
|
+
[TaskEvent.CONSULT_END]: {
|
|
446
|
+
actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd'],
|
|
447
|
+
},
|
|
405
448
|
// TODO: This may not be a valid transition, this needs to be checked as well
|
|
406
449
|
[TaskEvent.TASK_WRAPUP]: {
|
|
407
450
|
target: TaskState.WRAPPING_UP,
|
|
@@ -437,6 +480,18 @@ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
|
|
|
437
480
|
target: TaskState.CONSULTING,
|
|
438
481
|
actions: ['updateTaskData', 'setConsultInitiator'],
|
|
439
482
|
},
|
|
483
|
+
// AgentConsulting (Task Refactor: AgentConsulting event, not CONSULT_SUCCESS)
|
|
484
|
+
[TaskEvent.CONSULTING_ACTIVE]: {
|
|
485
|
+
target: TaskState.CONSULTING,
|
|
486
|
+
actions: [
|
|
487
|
+
'setConsultInitiator',
|
|
488
|
+
'setConsultDestination',
|
|
489
|
+
'setConsultAgentJoined',
|
|
490
|
+
'updateTaskData',
|
|
491
|
+
'emitTaskConsultAccepted',
|
|
492
|
+
'emitTaskConsulting',
|
|
493
|
+
],
|
|
494
|
+
},
|
|
440
495
|
// AgentConsultFailed, API Failures, AgentCtqFailed
|
|
441
496
|
[TaskEvent.CONSULT_FAILED]: [
|
|
442
497
|
{
|
|
@@ -467,6 +522,18 @@ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
|
|
|
467
522
|
actions: ['updateTaskData', 'clearConsultState'],
|
|
468
523
|
},
|
|
469
524
|
],
|
|
525
|
+
// AgentConsultEnded from Stable Prod during consult initiation (external end consult).
|
|
526
|
+
[TaskEvent.CONSULT_END]: [
|
|
527
|
+
{
|
|
528
|
+
guard: guards.isPrimaryMediaOnHold,
|
|
529
|
+
target: TaskState.HELD,
|
|
530
|
+
actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd'],
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
target: TaskState.CONNECTED,
|
|
534
|
+
actions: ['updateTaskData', 'clearConsultState', 'emitTaskConsultEnd'],
|
|
535
|
+
},
|
|
536
|
+
],
|
|
470
537
|
},
|
|
471
538
|
},
|
|
472
539
|
|
|
@@ -482,6 +549,29 @@ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
|
|
|
482
549
|
],
|
|
483
550
|
},
|
|
484
551
|
|
|
552
|
+
// AgentConsultFailed (RONA / consultee declined) while the initiator is already in
|
|
553
|
+
// CONSULTING (AgentConsulting arrived during ringing). Mirror CONSULT_INITIATING so the
|
|
554
|
+
// initiator returns to their own leg (HELD when main is on hold, else CONNECTED) instead
|
|
555
|
+
// of staying in CONSULTING. Without this, handleConsultFailed clears consultInitiator but
|
|
556
|
+
// the machine stays in CONSULTING, so the trailing AgentConsultEnded falls through the
|
|
557
|
+
// CONSULT_END "consulted agent" branch to TERMINATED and wrongly clears the task.
|
|
558
|
+
[TaskEvent.CONSULT_FAILED]: [
|
|
559
|
+
{
|
|
560
|
+
guard: ({context}) => context.consultFromConference === true,
|
|
561
|
+
target: TaskState.CONFERENCING,
|
|
562
|
+
actions: ['updateTaskData', 'handleConsultFailed'],
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
guard: guards.isPrimaryMediaOnHold,
|
|
566
|
+
target: TaskState.HELD,
|
|
567
|
+
actions: ['updateTaskData', 'handleConsultFailed'],
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
target: TaskState.CONNECTED,
|
|
571
|
+
actions: ['updateTaskData', 'handleConsultFailed'],
|
|
572
|
+
},
|
|
573
|
+
],
|
|
574
|
+
|
|
485
575
|
// AgentConsultEnded
|
|
486
576
|
[TaskEvent.CONSULT_END]: [
|
|
487
577
|
{
|
|
@@ -790,6 +880,20 @@ export function getTaskStateMachineConfig(uiControlConfig: UIControlConfig) {
|
|
|
790
880
|
actions: ['setConsultInitiator', 'setConsultDestination', 'setConsultFromConference'],
|
|
791
881
|
},
|
|
792
882
|
|
|
883
|
+
// AgentConsulting while still in conference (EP-DN/external ordering).
|
|
884
|
+
[TaskEvent.CONSULTING_ACTIVE]: {
|
|
885
|
+
target: TaskState.CONSULTING,
|
|
886
|
+
actions: [
|
|
887
|
+
'setConsultInitiator',
|
|
888
|
+
'setConsultDestination',
|
|
889
|
+
'setConsultFromConference',
|
|
890
|
+
'setConsultAgentJoined',
|
|
891
|
+
'updateTaskData',
|
|
892
|
+
'emitTaskConsultAccepted',
|
|
893
|
+
'emitTaskConsulting',
|
|
894
|
+
],
|
|
895
|
+
},
|
|
896
|
+
|
|
793
897
|
// Participant leaves - handle conference downgrade scenarios
|
|
794
898
|
[TaskEvent.PARTICIPANT_LEAVE]: [
|
|
795
899
|
{
|
|
@@ -88,10 +88,20 @@ const isActiveConsultState = (taskData: TaskData | undefined, selfAgentId?: stri
|
|
|
88
88
|
const hasConsultMedia = Object.values(taskData?.interaction?.media ?? {}).some(
|
|
89
89
|
(media: any) => media?.mType === MEDIA_TYPE_CONSULT
|
|
90
90
|
);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
selfParticipant?.consultState === 'consultInitiated'
|
|
94
|
-
|
|
91
|
+
// Pending consult before destination joins stays HELD, not CONSULTING.
|
|
92
|
+
if (
|
|
93
|
+
selfParticipant?.consultState === 'consultInitiated' &&
|
|
94
|
+
!hasJoinedConsultDestination(taskData, selfAgentId) &&
|
|
95
|
+
hasConsultMedia &&
|
|
96
|
+
taskData?.isConsulted === false
|
|
97
|
+
) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
if (
|
|
101
|
+
selfParticipant?.consultState === CONSULT_STATE.CONSULTING &&
|
|
102
|
+
hasConsultMedia &&
|
|
103
|
+
taskData?.isConsulted === false
|
|
104
|
+
) {
|
|
95
105
|
return true;
|
|
96
106
|
}
|
|
97
107
|
}
|
|
@@ -119,7 +129,42 @@ const isSelfConsultingOrPending = (
|
|
|
119
129
|
);
|
|
120
130
|
};
|
|
121
131
|
|
|
122
|
-
const
|
|
132
|
+
const isDnOnConsultMedia = (taskData: TaskData | undefined, selfAgentId?: string): boolean => {
|
|
133
|
+
if (!taskData?.interaction?.participants) return false;
|
|
134
|
+
|
|
135
|
+
const consultMedia: any = taskData.consultMediaResourceId
|
|
136
|
+
? taskData.interaction.media?.[taskData.consultMediaResourceId]
|
|
137
|
+
: Object.values(taskData.interaction.media ?? {}).find(
|
|
138
|
+
(m: any) => m?.mType === MEDIA_TYPE_CONSULT
|
|
139
|
+
);
|
|
140
|
+
const consultParticipantIds = new Set(consultMedia?.participants ?? []);
|
|
141
|
+
if (consultParticipantIds.size === 0) return false;
|
|
142
|
+
|
|
143
|
+
return Object.values(taskData.interaction.participants).some((p: any) => {
|
|
144
|
+
if (!p || p.hasLeft || p.id === selfAgentId) return false;
|
|
145
|
+
if (!consultParticipantIds.has(p.id)) return false;
|
|
146
|
+
const pType = String(p.pType ?? '').toUpperCase();
|
|
147
|
+
|
|
148
|
+
return pType === 'DN' || pType === 'EP-DN' || pType === 'EP_DN';
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const mapConsultDestinationType = (
|
|
153
|
+
destinationType: string | undefined
|
|
154
|
+
): DestinationType | undefined => {
|
|
155
|
+
if (!destinationType) return undefined;
|
|
156
|
+
const normalized = String(destinationType).toUpperCase();
|
|
157
|
+
if (normalized === 'DN' || normalized === 'EP-DN' || normalized === 'EP_DN') {
|
|
158
|
+
return 'entryPoint' as DestinationType;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return destinationType as DestinationType;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const hasJoinedConsultDestination = (
|
|
165
|
+
taskData: TaskData | undefined,
|
|
166
|
+
selfAgentId?: string
|
|
167
|
+
): boolean => {
|
|
123
168
|
if (!taskData?.interaction) return false;
|
|
124
169
|
const participants = taskData.interaction.participants as any;
|
|
125
170
|
const cpd = taskData.interaction.callProcessingDetails as any;
|
|
@@ -127,6 +172,20 @@ const hasJoinedConsultDestination = (taskData: TaskData | undefined): boolean =>
|
|
|
127
172
|
if (backendSaysJoined) return true;
|
|
128
173
|
if (!participants) return false;
|
|
129
174
|
|
|
175
|
+
const effectiveSelfAgentId = selfAgentId ?? taskData.agentId;
|
|
176
|
+
const selfParticipant = effectiveSelfAgentId
|
|
177
|
+
? (participants[effectiveSelfAgentId] as {consultState?: string} | undefined)
|
|
178
|
+
: undefined;
|
|
179
|
+
|
|
180
|
+
if (
|
|
181
|
+
taskData.type === 'AgentConsulting' &&
|
|
182
|
+
selfParticipant?.consultState === CONSULT_STATE.CONSULTING &&
|
|
183
|
+
taskData.isConsulted === false &&
|
|
184
|
+
isDnOnConsultMedia(taskData, effectiveSelfAgentId)
|
|
185
|
+
) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
130
189
|
return Object.values(participants).some((p: any) => {
|
|
131
190
|
if (!p || p.isConsulted !== true || p.hasLeft) return false;
|
|
132
191
|
|
|
@@ -154,7 +213,7 @@ const deriveConsultCallHeldFromTaskData = (taskData: TaskData | undefined): bool
|
|
|
154
213
|
return Boolean(consultMedia.isHold);
|
|
155
214
|
};
|
|
156
215
|
|
|
157
|
-
const getTaskStateForUiControls = (
|
|
216
|
+
export const getTaskStateForUiControls = (
|
|
158
217
|
taskData: TaskData | undefined,
|
|
159
218
|
selfAgentId: string | undefined
|
|
160
219
|
): TaskState => {
|
|
@@ -214,11 +273,25 @@ const deriveTaskDataUpdates = (context: TaskContext, taskData: TaskData | undefi
|
|
|
214
273
|
updates.consultDestinationAgentId = taskData.destAgentId;
|
|
215
274
|
}
|
|
216
275
|
}
|
|
276
|
+
|
|
277
|
+
const isConsultTerminalEvent =
|
|
278
|
+
taskData.type === 'AgentConsultEnded' || taskData.type === 'AgentConsultFailed';
|
|
279
|
+
|
|
280
|
+
if (isConsultTerminalEvent) {
|
|
281
|
+
updates.consultInitiator = false;
|
|
282
|
+
updates.consultFromConference = false;
|
|
283
|
+
updates.consultDestinationAgentJoined = false;
|
|
284
|
+
updates.consultCallHeld = false;
|
|
285
|
+
updates.consultDestinationType = null;
|
|
286
|
+
updates.consultDestinationAgentId = null;
|
|
287
|
+
updates.transferConferenceRequested = false;
|
|
288
|
+
}
|
|
289
|
+
|
|
217
290
|
if (consultingActive && taskData.destinationType) {
|
|
218
|
-
updates.consultDestinationType = taskData.destinationType
|
|
291
|
+
updates.consultDestinationType = mapConsultDestinationType(taskData.destinationType);
|
|
219
292
|
}
|
|
220
293
|
|
|
221
|
-
if (!context.consultInitiator) {
|
|
294
|
+
if (!isConsultTerminalEvent && !context.consultInitiator) {
|
|
222
295
|
const consultInitiator = determineConsultInitiator(taskData, selfAgentId);
|
|
223
296
|
if (consultInitiator !== undefined) {
|
|
224
297
|
updates.consultInitiator = consultInitiator;
|
|
@@ -232,6 +305,7 @@ const deriveTaskDataUpdates = (context: TaskContext, taskData: TaskData | undefi
|
|
|
232
305
|
|
|
233
306
|
const effectiveConsultInitiator = updates.consultInitiator ?? context.consultInitiator;
|
|
234
307
|
if (
|
|
308
|
+
!isConsultTerminalEvent &&
|
|
235
309
|
effectiveConsultInitiator &&
|
|
236
310
|
conferenceFromPayload &&
|
|
237
311
|
(consultingActive || selfConsultingOrPending || Boolean(taskData?.consultMediaResourceId))
|
|
@@ -239,16 +313,37 @@ const deriveTaskDataUpdates = (context: TaskContext, taskData: TaskData | undefi
|
|
|
239
313
|
updates.consultFromConference = true;
|
|
240
314
|
}
|
|
241
315
|
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
|
|
316
|
+
if (
|
|
317
|
+
!isConsultTerminalEvent &&
|
|
318
|
+
(consultingActive || selfConsultingOrPending) &&
|
|
319
|
+
taskData.interaction
|
|
320
|
+
) {
|
|
321
|
+
const joinedConsultee = hasJoinedConsultDestination(taskData, selfAgentId);
|
|
322
|
+
const selfParticipant = selfAgentId
|
|
323
|
+
? (taskData.interaction.participants?.[selfAgentId] as
|
|
324
|
+
| {consultState?: string}
|
|
325
|
+
| undefined)
|
|
326
|
+
: undefined;
|
|
327
|
+
const agentConsultingSelfJoined =
|
|
328
|
+
taskData.type === 'AgentConsulting' &&
|
|
329
|
+
effectiveConsultInitiator &&
|
|
330
|
+
selfParticipant?.consultState === CONSULT_STATE.CONSULTING;
|
|
331
|
+
|
|
332
|
+
if (joinedConsultee || agentConsultingSelfJoined) {
|
|
333
|
+
updates.consultDestinationAgentJoined = true;
|
|
334
|
+
} else if (selfParticipant?.consultState === 'consultInitiated') {
|
|
335
|
+
updates.consultDestinationAgentJoined = false;
|
|
336
|
+
}
|
|
245
337
|
|
|
246
338
|
if (!context.consultDestinationType && !updates.consultDestinationType) {
|
|
247
339
|
const hasEpDnParticipant = Boolean(
|
|
248
340
|
taskData.interaction.participants &&
|
|
249
|
-
Object.values(taskData.interaction.participants).some(
|
|
250
|
-
(p
|
|
251
|
-
|
|
341
|
+
Object.values(taskData.interaction.participants).some((p: any) => {
|
|
342
|
+
if (p?.hasLeft) return false;
|
|
343
|
+
const pType = String(p?.pType ?? '').toUpperCase();
|
|
344
|
+
|
|
345
|
+
return pType === 'EP-DN' || pType === 'EP_DN' || pType === 'DN';
|
|
346
|
+
})
|
|
252
347
|
);
|
|
253
348
|
if (hasEpDnParticipant) updates.consultDestinationType = 'entryPoint' as any;
|
|
254
349
|
}
|
|
@@ -303,7 +398,7 @@ export function createInitialContext(
|
|
|
303
398
|
|
|
304
399
|
export function updateUIControls(currentState: TaskState) {
|
|
305
400
|
return assign(({context}: TaskActionArgs) => ({
|
|
306
|
-
uiControls: computeUIControls(currentState, context),
|
|
401
|
+
uiControls: computeUIControls(currentState, context, context.taskData ?? undefined),
|
|
307
402
|
}));
|
|
308
403
|
}
|
|
309
404
|
|
|
@@ -349,7 +444,27 @@ export const actions: TaskActionsMap = {
|
|
|
349
444
|
return {};
|
|
350
445
|
}),
|
|
351
446
|
|
|
352
|
-
handleConsultFailed: assign({
|
|
447
|
+
handleConsultFailed: assign(({context, event}: TaskActionArgs) => {
|
|
448
|
+
const taskData = getTaskDataFromEvent(event) ?? context.taskData;
|
|
449
|
+
const cleared = {
|
|
450
|
+
consultDestinationType: null,
|
|
451
|
+
consultDestinationAgentId: null,
|
|
452
|
+
consultDestinationAgentJoined: false,
|
|
453
|
+
consultInitiator: false,
|
|
454
|
+
exitingConference: false,
|
|
455
|
+
consultCallHeld: false,
|
|
456
|
+
consultFromConference: false,
|
|
457
|
+
transferConferenceRequested: false,
|
|
458
|
+
};
|
|
459
|
+
const selfAgentId = context.uiControlConfig.agentId ?? taskData?.agentId;
|
|
460
|
+
const nextContext = {...context, ...cleared, taskData} as TaskContext;
|
|
461
|
+
const inferredState = getTaskStateForUiControls(taskData, selfAgentId);
|
|
462
|
+
|
|
463
|
+
return {
|
|
464
|
+
...cleared,
|
|
465
|
+
uiControls: computeUIControls(inferredState, nextContext, taskData),
|
|
466
|
+
};
|
|
467
|
+
}),
|
|
353
468
|
handleConferenceStarted: assign({consultInitiator: false}),
|
|
354
469
|
|
|
355
470
|
setConsultDestination: assign(({event}: TaskActionArgs) => {
|
|
@@ -423,15 +538,26 @@ export const actions: TaskActionsMap = {
|
|
|
423
538
|
return {};
|
|
424
539
|
}),
|
|
425
540
|
|
|
426
|
-
clearConsultState: assign({
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
541
|
+
clearConsultState: assign(({context, event}: TaskActionArgs) => {
|
|
542
|
+
const cleared = {
|
|
543
|
+
consultDestinationType: null,
|
|
544
|
+
consultDestinationAgentId: null,
|
|
545
|
+
consultDestinationAgentJoined: false,
|
|
546
|
+
consultInitiator: false,
|
|
547
|
+
exitingConference: false,
|
|
548
|
+
consultCallHeld: false,
|
|
549
|
+
consultFromConference: false,
|
|
550
|
+
transferConferenceRequested: false,
|
|
551
|
+
};
|
|
552
|
+
const taskData = context.taskData ?? getTaskDataFromEvent(event);
|
|
553
|
+
const selfAgentId = context.uiControlConfig.agentId ?? taskData?.agentId;
|
|
554
|
+
const nextContext = {...context, ...cleared, taskData} as TaskContext;
|
|
555
|
+
const inferredState = getTaskStateForUiControls(taskData, selfAgentId);
|
|
556
|
+
|
|
557
|
+
return {
|
|
558
|
+
...cleared,
|
|
559
|
+
uiControls: computeUIControls(inferredState, nextContext, taskData),
|
|
560
|
+
};
|
|
435
561
|
}),
|
|
436
562
|
|
|
437
563
|
setTransferConferenceRequested: assign({transferConferenceRequested: true}),
|