@webex/contact-center 3.10.0-next.9 → 3.10.0-webex-services-ready.2

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.
Files changed (89) hide show
  1. package/dist/cc.js +2 -1
  2. package/dist/cc.js.map +1 -1
  3. package/dist/config.js.map +1 -1
  4. package/dist/constants.js.map +1 -1
  5. package/dist/index.js +17 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/logger-proxy.js.map +1 -1
  8. package/dist/metrics/MetricsManager.js +2 -1
  9. package/dist/metrics/MetricsManager.js.map +1 -1
  10. package/dist/metrics/behavioral-events.js +12 -0
  11. package/dist/metrics/behavioral-events.js.map +1 -1
  12. package/dist/metrics/constants.js +4 -0
  13. package/dist/metrics/constants.js.map +1 -1
  14. package/dist/services/AddressBook.js +2 -3
  15. package/dist/services/AddressBook.js.map +1 -1
  16. package/dist/services/EntryPoint.js +2 -3
  17. package/dist/services/EntryPoint.js.map +1 -1
  18. package/dist/services/Queue.js +2 -3
  19. package/dist/services/Queue.js.map +1 -1
  20. package/dist/services/WebCallingService.js +1 -1
  21. package/dist/services/WebCallingService.js.map +1 -1
  22. package/dist/services/agent/index.js +1 -2
  23. package/dist/services/agent/index.js.map +1 -1
  24. package/dist/services/agent/types.js +10 -0
  25. package/dist/services/agent/types.js.map +1 -1
  26. package/dist/services/config/Util.js.map +1 -1
  27. package/dist/services/config/constants.js.map +1 -1
  28. package/dist/services/config/index.js +1 -1
  29. package/dist/services/config/index.js.map +1 -1
  30. package/dist/services/config/types.js.map +1 -1
  31. package/dist/services/constants.js.map +1 -1
  32. package/dist/services/core/Err.js.map +1 -1
  33. package/dist/services/core/GlobalTypes.js.map +1 -1
  34. package/dist/services/core/Utils.js +2 -3
  35. package/dist/services/core/Utils.js.map +1 -1
  36. package/dist/services/core/WebexRequest.js +1 -2
  37. package/dist/services/core/WebexRequest.js.map +1 -1
  38. package/dist/services/core/aqm-reqs.js +2 -3
  39. package/dist/services/core/aqm-reqs.js.map +1 -1
  40. package/dist/services/core/constants.js.map +1 -1
  41. package/dist/services/core/types.js.map +1 -1
  42. package/dist/services/core/websocket/WebSocketManager.js +1 -2
  43. package/dist/services/core/websocket/WebSocketManager.js.map +1 -1
  44. package/dist/services/core/websocket/connection-service.js +1 -1
  45. package/dist/services/core/websocket/connection-service.js.map +1 -1
  46. package/dist/services/core/websocket/keepalive.worker.js.map +1 -1
  47. package/dist/services/core/websocket/types.js.map +1 -1
  48. package/dist/services/index.js +1 -1
  49. package/dist/services/index.js.map +1 -1
  50. package/dist/services/task/AutoWrapup.js +1 -1
  51. package/dist/services/task/AutoWrapup.js.map +1 -1
  52. package/dist/services/task/TaskManager.js +121 -33
  53. package/dist/services/task/TaskManager.js.map +1 -1
  54. package/dist/services/task/TaskUtils.js +90 -1
  55. package/dist/services/task/TaskUtils.js.map +1 -1
  56. package/dist/services/task/constants.js +3 -1
  57. package/dist/services/task/constants.js.map +1 -1
  58. package/dist/services/task/contact.js +0 -2
  59. package/dist/services/task/contact.js.map +1 -1
  60. package/dist/services/task/dialer.js.map +1 -1
  61. package/dist/services/task/index.js +1 -1
  62. package/dist/services/task/index.js.map +1 -1
  63. package/dist/services/task/types.js +375 -0
  64. package/dist/services/task/types.js.map +1 -1
  65. package/dist/types/metrics/constants.d.ts +4 -0
  66. package/dist/types/services/task/TaskUtils.d.ts +42 -0
  67. package/dist/types/services/task/constants.d.ts +2 -0
  68. package/dist/types/services/task/types.d.ts +32 -0
  69. package/dist/types.js +5 -0
  70. package/dist/types.js.map +1 -1
  71. package/dist/utils/PageCache.js +1 -1
  72. package/dist/utils/PageCache.js.map +1 -1
  73. package/dist/webex-config.js.map +1 -1
  74. package/dist/webex.js +2 -2
  75. package/dist/webex.js.map +1 -1
  76. package/package.json +9 -9
  77. package/src/cc.ts +1 -0
  78. package/src/metrics/behavioral-events.ts +12 -0
  79. package/src/metrics/constants.ts +4 -0
  80. package/src/services/task/TaskManager.ts +135 -22
  81. package/src/services/task/TaskUtils.ts +109 -1
  82. package/src/services/task/constants.ts +2 -0
  83. package/src/services/task/types.ts +34 -0
  84. package/test/unit/spec/cc.ts +1 -0
  85. package/test/unit/spec/metrics/behavioral-events.ts +14 -0
  86. package/test/unit/spec/services/task/TaskManager.ts +378 -4
  87. package/test/unit/spec/services/task/TaskUtils.ts +305 -3
  88. package/umd/contact-center.min.js +2 -2
  89. package/umd/contact-center.min.js.map +1 -1
@@ -1,8 +1,16 @@
1
- import { checkParticipantNotInInteraction,
1
+ import {
2
+ checkParticipantNotInInteraction,
2
3
  getIsConferenceInProgress,
3
4
  isParticipantInMainInteraction,
4
- isPrimary,} from '../../../../../src/services/task/TaskUtils';
5
- import {ITask} from '../../../../../src/services/task/types';
5
+ isPrimary,
6
+ isAutoAnswerEnabled,
7
+ isWebRTCCall,
8
+ isDigitalOutbound,
9
+ hasAgentInitiatedOutdial,
10
+ shouldAutoAnswerTask,
11
+ } from '../../../../../src/services/task/TaskUtils';
12
+ import {ITask, Interaction, TaskData} from '../../../../../src/services/task/types';
13
+ import {LoginOption} from '../../../../../src/types';
6
14
 
7
15
  describe('TaskUtils', () => {
8
16
  let mockTask: ITask;
@@ -128,4 +136,298 @@ describe('TaskUtils', () => {
128
136
  expect(getIsConferenceInProgress(mockTask.data)).toBe(false);
129
137
  });
130
138
  });
139
+
140
+ describe('Auto-Answer Helper Functions', () => {
141
+ let mockInteraction: Interaction;
142
+
143
+ beforeEach(() => {
144
+ mockInteraction = {
145
+ interactionId: 'interaction-123',
146
+ mediaType: 'telephony',
147
+ mediaChannel: 'telephony',
148
+ participants: {
149
+ [mockAgentId]: {
150
+ id: mockAgentId,
151
+ pType: 'Agent',
152
+ autoAnswerEnabled: false,
153
+ hasJoined: false,
154
+ hasLeft: false,
155
+ },
156
+ },
157
+ owner: mockAgentId,
158
+ contactDirection: {type: 'INBOUND'},
159
+ outboundType: null,
160
+ callProcessingDetails: {
161
+ QMgrName: 'aqm',
162
+ taskToBeSelfServiced: 'false',
163
+ ani: '+1234567890',
164
+ displayAni: '+1234567890',
165
+ dnis: '+0987654321',
166
+ tenantId: 'tenant-123',
167
+ QueueId: 'queue-123',
168
+ vteamId: 'vteam-123',
169
+ customerName: 'Test Customer',
170
+ virtualTeamName: 'Test Team',
171
+ ronaTimeout: '30',
172
+ category: 'Support',
173
+ reason: 'General',
174
+ sourceNumber: '+1234567890',
175
+ sourcePage: 'web',
176
+ appUser: 'test-app',
177
+ customerNumber: '+1234567890',
178
+ reasonCode: '100',
179
+ IvrPath: '/ivr/path',
180
+ pathId: 'path-123',
181
+ fromAddress: 'customer@example.com',
182
+ },
183
+ previousVTeams: [],
184
+ state: 'new',
185
+ currentVTeam: 'vteam-123',
186
+ isFcManaged: false,
187
+ isTerminated: false,
188
+ orgId: 'org-123',
189
+ createdTimestamp: Date.now(),
190
+ media: {},
191
+ } as any;
192
+ });
193
+
194
+ describe('isAutoAnswerEnabled', () => {
195
+ it('should return true when autoAnswerEnabled is true', () => {
196
+ mockInteraction.participants[mockAgentId].autoAnswerEnabled = true;
197
+ expect(isAutoAnswerEnabled(mockInteraction, mockAgentId)).toBe(true);
198
+ });
199
+
200
+ it('should return false when autoAnswerEnabled is false', () => {
201
+ mockInteraction.participants[mockAgentId].autoAnswerEnabled = false;
202
+ expect(isAutoAnswerEnabled(mockInteraction, mockAgentId)).toBe(false);
203
+ });
204
+
205
+ it('should return false when autoAnswerEnabled is not set', () => {
206
+ delete mockInteraction.participants[mockAgentId].autoAnswerEnabled;
207
+ expect(isAutoAnswerEnabled(mockInteraction, mockAgentId)).toBe(false);
208
+ });
209
+
210
+ it('should return false when participant does not exist', () => {
211
+ expect(isAutoAnswerEnabled(mockInteraction, 'non-existent-agent')).toBe(false);
212
+ });
213
+ });
214
+
215
+ describe('isWebRTCCall', () => {
216
+ it('should return true for BROWSER login with telephony media type and webRTC enabled', () => {
217
+ expect(isWebRTCCall(mockInteraction, LoginOption.BROWSER, true)).toBe(true);
218
+ });
219
+
220
+ it('should return false when webRTC is disabled', () => {
221
+ expect(isWebRTCCall(mockInteraction, LoginOption.BROWSER, false)).toBe(false);
222
+ });
223
+
224
+ it('should return false for AGENT_DN login', () => {
225
+ expect(isWebRTCCall(mockInteraction, LoginOption.AGENT_DN, true)).toBe(false);
226
+ });
227
+
228
+ it('should return false for EXTENSION login', () => {
229
+ expect(isWebRTCCall(mockInteraction, LoginOption.EXTENSION, true)).toBe(false);
230
+ });
231
+
232
+ it('should return false for BROWSER login with non-telephony media type', () => {
233
+ mockInteraction.mediaType = 'email';
234
+ expect(isWebRTCCall(mockInteraction, LoginOption.BROWSER, true)).toBe(false);
235
+ });
236
+ });
237
+
238
+ describe('isDigitalOutbound', () => {
239
+ it('should return true for email outdial', () => {
240
+ mockInteraction.contactDirection = {type: 'OUTBOUND'};
241
+ mockInteraction.outboundType = 'OUTDIAL';
242
+ mockInteraction.mediaChannel = 'email';
243
+ expect(isDigitalOutbound(mockInteraction)).toBe(true);
244
+ });
245
+
246
+ it('should return true for SMS outdial', () => {
247
+ mockInteraction.contactDirection = {type: 'OUTBOUND'};
248
+ mockInteraction.outboundType = 'OUTDIAL';
249
+ mockInteraction.mediaChannel = 'sms';
250
+ expect(isDigitalOutbound(mockInteraction)).toBe(true);
251
+ });
252
+
253
+ it('should return false for telephony outdial', () => {
254
+ mockInteraction.contactDirection = {type: 'OUTBOUND'};
255
+ mockInteraction.outboundType = 'OUTDIAL';
256
+ mockInteraction.mediaChannel = 'telephony';
257
+ expect(isDigitalOutbound(mockInteraction)).toBe(false);
258
+ });
259
+
260
+ it('should return false for inbound email', () => {
261
+ mockInteraction.contactDirection = {type: 'INBOUND'};
262
+ mockInteraction.mediaChannel = 'email';
263
+ expect(isDigitalOutbound(mockInteraction)).toBe(false);
264
+ });
265
+
266
+ it('should return false when outboundType is not OUTDIAL', () => {
267
+ mockInteraction.contactDirection = {type: 'OUTBOUND'};
268
+ mockInteraction.outboundType = 'CALLBACK';
269
+ mockInteraction.mediaChannel = 'email';
270
+ expect(isDigitalOutbound(mockInteraction)).toBe(false);
271
+ });
272
+ });
273
+
274
+ describe('hasAgentInitiatedOutdial', () => {
275
+ beforeEach(() => {
276
+ mockInteraction.contactDirection = {type: 'OUTBOUND'};
277
+ mockInteraction.outboundType = 'OUTDIAL';
278
+ mockInteraction.owner = mockAgentId;
279
+ mockInteraction.callProcessingDetails.outdialAgentId = mockAgentId;
280
+ mockInteraction.callProcessingDetails.BLIND_TRANSFER_IN_PROGRESS = false;
281
+ });
282
+
283
+ it('should return true for agent-initiated outdial', () => {
284
+ expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(true);
285
+ });
286
+
287
+ it('should return false when not outbound', () => {
288
+ mockInteraction.contactDirection = {type: 'INBOUND'};
289
+ expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
290
+ });
291
+
292
+ it('should return false when not OUTDIAL type', () => {
293
+ mockInteraction.outboundType = 'CALLBACK';
294
+ expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
295
+ });
296
+
297
+ it('should return false when outdialAgentId does not match', () => {
298
+ mockInteraction.callProcessingDetails.outdialAgentId = mockOtherAgentId;
299
+ expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
300
+ });
301
+
302
+ it('should return false when owner does not match', () => {
303
+ mockInteraction.owner = mockOtherAgentId;
304
+ expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
305
+ });
306
+
307
+ it('should return false when blind transfer is in progress', () => {
308
+ mockInteraction.callProcessingDetails.BLIND_TRANSFER_IN_PROGRESS = true;
309
+ expect(hasAgentInitiatedOutdial(mockInteraction, mockAgentId)).toBe(false);
310
+ });
311
+ });
312
+
313
+ describe('shouldAutoAnswerTask', () => {
314
+ let mockTaskData: TaskData;
315
+
316
+ beforeEach(() => {
317
+ mockTaskData = {
318
+ interactionId: 'interaction-123',
319
+ agentId: mockAgentId,
320
+ interaction: mockInteraction,
321
+ } as any;
322
+ });
323
+
324
+ describe('WebRTC scenarios', () => {
325
+ beforeEach(() => {
326
+ mockInteraction.mediaType = 'telephony';
327
+ });
328
+
329
+ it('should return true when auto-answer is enabled for WebRTC call', () => {
330
+ mockInteraction.participants[mockAgentId].autoAnswerEnabled = true;
331
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
332
+ true
333
+ );
334
+ });
335
+
336
+ it('should return true for agent-initiated WebRTC outdial', () => {
337
+ mockInteraction.contactDirection = {type: 'OUTBOUND'};
338
+ mockInteraction.outboundType = 'OUTDIAL';
339
+ mockInteraction.owner = mockAgentId;
340
+ mockInteraction.callProcessingDetails.outdialAgentId = mockAgentId;
341
+ mockInteraction.callProcessingDetails.BLIND_TRANSFER_IN_PROGRESS = false;
342
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
343
+ true
344
+ );
345
+ });
346
+
347
+ it('should return false for WebRTC call without auto-answer or outdial', () => {
348
+ mockInteraction.participants[mockAgentId].autoAnswerEnabled = false;
349
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
350
+ false
351
+ );
352
+ });
353
+
354
+ it('should return false when webRTC is disabled', () => {
355
+ mockInteraction.participants[mockAgentId].autoAnswerEnabled = true;
356
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, false)).toBe(
357
+ false
358
+ );
359
+ });
360
+
361
+ it('should return false for non-BROWSER login', () => {
362
+ mockInteraction.participants[mockAgentId].autoAnswerEnabled = true;
363
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.AGENT_DN, true)).toBe(
364
+ false
365
+ );
366
+ });
367
+ });
368
+
369
+ describe('Digital outbound scenarios', () => {
370
+ beforeEach(() => {
371
+ mockInteraction.contactDirection = {type: 'OUTBOUND'};
372
+ mockInteraction.outboundType = 'OUTDIAL';
373
+ mockInteraction.owner = mockAgentId;
374
+ mockInteraction.callProcessingDetails.outdialAgentId = mockAgentId;
375
+ mockInteraction.previousVTeams = [];
376
+ });
377
+
378
+ it('should return true for agent-initiated email outdial', () => {
379
+ mockInteraction.mediaType = 'email';
380
+ mockInteraction.mediaChannel = 'email';
381
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
382
+ true
383
+ );
384
+ });
385
+
386
+ it('should return true for agent-initiated SMS outdial', () => {
387
+ mockInteraction.mediaType = 'sms';
388
+ mockInteraction.mediaChannel = 'sms';
389
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
390
+ true
391
+ );
392
+ });
393
+
394
+ it('should return false when digital outbound has previous vteams', () => {
395
+ mockInteraction.mediaType = 'email';
396
+ mockInteraction.mediaChannel = 'email';
397
+ mockInteraction.previousVTeams = ['vteam-1'];
398
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
399
+ false
400
+ );
401
+ });
402
+
403
+ it('should return false when digital outbound is not agent-initiated', () => {
404
+ mockInteraction.mediaType = 'email';
405
+ mockInteraction.mediaChannel = 'email';
406
+ mockInteraction.owner = mockOtherAgentId;
407
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
408
+ false
409
+ );
410
+ });
411
+ });
412
+
413
+ describe('Edge cases', () => {
414
+ it('should return false when interaction is null', () => {
415
+ mockTaskData.interaction = null as any;
416
+ expect(shouldAutoAnswerTask(mockTaskData, mockAgentId, LoginOption.BROWSER, true)).toBe(
417
+ false
418
+ );
419
+ });
420
+
421
+ it('should return false when agentId is null', () => {
422
+ expect(shouldAutoAnswerTask(mockTaskData, null as any, LoginOption.BROWSER, true)).toBe(
423
+ false
424
+ );
425
+ });
426
+
427
+ it('should return false when agentId is empty string', () => {
428
+ expect(shouldAutoAnswerTask(mockTaskData, '', LoginOption.BROWSER, true)).toBe(false);
429
+ });
430
+ });
431
+ });
432
+ });
131
433
  });