diff --git a/packages/contact-center/cc-components/src/components/task/CallControlCAD/call-control-cad.tsx b/packages/contact-center/cc-components/src/components/task/CallControlCAD/call-control-cad.tsx index b2f31072a..c5859ac29 100644 --- a/packages/contact-center/cc-components/src/components/task/CallControlCAD/call-control-cad.tsx +++ b/packages/contact-center/cc-components/src/components/task/CallControlCAD/call-control-cad.tsx @@ -5,7 +5,7 @@ import {Brandvisual, Icon, Tooltip, Button} from '@momentum-design/components/di import './call-control-cad.styles.scss'; import TaskTimer from '../TaskTimer/index'; import CallControlConsultComponent from '../CallControl/CallControlCustom/call-control-consult'; -import {MEDIA_CHANNEL as MediaChannelType, CallControlComponentProps} from '../task.types'; +import {MEDIA_CHANNEL as MediaChannelType, CallControlComponentProps, getCallerIdentifier} from '../task.types'; import {getMediaTypeInfo} from '../../../utils'; import { @@ -75,8 +75,14 @@ const CallControlCADComponent: React.FC = (props) => const phoneNumberTriggerId = `phone-number-trigger-${currentTask.data.interaction.interactionId}`; const phoneNumberTooltipId = `phone-number-tooltip-${currentTask.data.interaction.interactionId}`; + // For telephony calls, ani is the originating number and dn is the destination. + // Inbound: ani = caller's number, dn = entry point dialed by caller + // Outdial: ani = agent's originating number (entry point), dn = customer's dialed number + const outboundType = currentTask?.data?.interaction?.outboundType; + const callerNumber = getCallerIdentifier(ani, dn, outboundType); + const renderCustomerName = () => { - const customerText = isSocial ? customerName || NO_CUSTOMER_NAME : ani || NO_CALLER_ID; + const customerText = isSocial ? customerName || NO_CUSTOMER_NAME : callerNumber || NO_CALLER_ID; const textComponent = ( = (props) => }; const renderPhoneNumber = () => { - const phoneText = isSocial ? customerName || NO_CUSTOMER_NAME : dn || NO_PHONE_NUMBER; + const phoneText = isSocial + ? customerName || NO_CUSTOMER_NAME + : isTelephony + ? ani || NO_PHONE_NUMBER + : NO_PHONE_NUMBER; const labelText = isSocial ? CUSTOMER_NAME : PHONE_NUMBER; const textComponent = ( diff --git a/packages/contact-center/cc-components/src/components/task/IncomingTask/incoming-task.utils.tsx b/packages/contact-center/cc-components/src/components/task/IncomingTask/incoming-task.utils.tsx index 4da1f8745..903a475fd 100644 --- a/packages/contact-center/cc-components/src/components/task/IncomingTask/incoming-task.utils.tsx +++ b/packages/contact-center/cc-components/src/components/task/IncomingTask/incoming-task.utils.tsx @@ -1,4 +1,4 @@ -import {MEDIA_CHANNEL} from '../task.types'; +import {MEDIA_CHANNEL, getCallerIdentifier} from '../task.types'; import {ITask} from '@webex/cc-store'; export interface IncomingTaskData { @@ -35,6 +35,7 @@ export const extractIncomingTaskData = ( //@ts-expect-error To be fixed in SDK - https://jira-eng-sjc12.cisco.com/jira/browse/CAI-6762 const callAssociationDetails = incomingTask?.data?.interaction?.callAssociatedDetails; const ani = callAssociationDetails?.ani; + const dn = callAssociationDetails?.dn; const customerName = callAssociationDetails?.customerName; const virtualTeamName = callAssociationDetails?.virtualTeamName; const ronaTimeout = callAssociationDetails?.ronaTimeout ? Number(callAssociationDetails?.ronaTimeout) : null; @@ -56,7 +57,8 @@ export const extractIncomingTaskData = ( const declineText = !incomingTask.data.wrapUpRequired && isTelephony && isBrowser ? 'Decline' : undefined; // Compute title based on media type - const title = isSocial ? customerName : ani; + const outboundType = incomingTask?.data?.interaction?.outboundType; + const title = isSocial ? customerName : getCallerIdentifier(ani, dn, outboundType); // Compute disable state for accept button when auto-answering const isAutoAnswering = incomingTask.data.isAutoAnswering || false; diff --git a/packages/contact-center/cc-components/src/components/task/TaskList/task-list.utils.ts b/packages/contact-center/cc-components/src/components/task/TaskList/task-list.utils.ts index aa1591ffc..2b239fbe1 100644 --- a/packages/contact-center/cc-components/src/components/task/TaskList/task-list.utils.ts +++ b/packages/contact-center/cc-components/src/components/task/TaskList/task-list.utils.ts @@ -1,4 +1,4 @@ -import {MEDIA_CHANNEL, TaskListItemData} from '../task.types'; +import {MEDIA_CHANNEL, TaskListItemData, getCallerIdentifier} from '../task.types'; import store, {isIncomingTask, ILogger, ITask} from '@webex/cc-store'; /** * Extracts and processes data from a task for rendering in the task list @@ -17,6 +17,7 @@ export const extractTaskListItemData = ( //@ts-expect-error To be fixed in SDK - https://jira-eng-sjc12.cisco.com/jira/browse/CAI-6762 const callAssociationDetails = task?.data?.interaction?.callAssociatedDetails; const ani = callAssociationDetails?.ani; + const dn = callAssociationDetails?.dn; const customerName = callAssociationDetails?.customerName; const virtualTeamName = callAssociationDetails?.virtualTeamName; @@ -39,7 +40,8 @@ export const extractTaskListItemData = ( const declineText = isTaskIncoming && isTelephony && isBrowser ? 'Decline' : undefined; // Compute title based on media type - const title = isSocial ? customerName : ani; + const outboundType = task?.data?.interaction?.outboundType; + const title = isSocial ? customerName : getCallerIdentifier(ani, dn, outboundType); const isAutoAnswering = task.data.isAutoAnswering || false; diff --git a/packages/contact-center/cc-components/src/components/task/task.types.ts b/packages/contact-center/cc-components/src/components/task/task.types.ts index aac63d7ca..0b7c33765 100644 --- a/packages/contact-center/cc-components/src/components/task/task.types.ts +++ b/packages/contact-center/cc-components/src/components/task/task.types.ts @@ -771,6 +771,19 @@ export interface TaskListItemData { displayState: string; } +export enum OUTBOUND_TYPE { + OUTDIAL = 'OUTDIAL', + CALLBACK = 'CALLBACK', +} + +/** + * Returns the appropriate caller identifier based on outbound type. + * For outdial calls, the customer's number is in `dn`; for all others it's in `ani`. + */ +export const getCallerIdentifier = (ani: string, dn: string, outboundType?: string): string => { + return outboundType === OUTBOUND_TYPE.OUTDIAL ? dn || ani : ani; +}; + export enum TaskState { NEW = 'new', ACTIVE = 'active', diff --git a/packages/contact-center/cc-components/tests/components/task/CallControlCAD/__snapshots__/call-control-cad.snapshot.tsx.snap b/packages/contact-center/cc-components/tests/components/task/CallControlCAD/__snapshots__/call-control-cad.snapshot.tsx.snap index ccecd713c..dfe728504 100644 --- a/packages/contact-center/cc-components/tests/components/task/CallControlCAD/__snapshots__/call-control-cad.snapshot.tsx.snap +++ b/packages/contact-center/cc-components/tests/components/task/CallControlCAD/__snapshots__/call-control-cad.snapshot.tsx.snap @@ -198,7 +198,7 @@ exports[`CallControlCADComponent Snapshots should handle edge cases and control - No Phone Number + 555-123-4567 @@ -376,7 +376,7 @@ exports[`CallControlCADComponent Snapshots should handle edge cases and control - No Phone Number + 555-123-4567 @@ -908,7 +908,7 @@ exports[`CallControlCADComponent Snapshots should render basic call states and m - No Phone Number + chat-customer@example.com - No Phone Number + chat-customer@example.com @@ -1178,7 +1178,7 @@ exports[`CallControlCADComponent Snapshots should render basic call states and m - No Phone Number + 555-123-4567 @@ -1438,7 +1438,7 @@ exports[`CallControlCADComponent Snapshots should render basic call states and m - No Phone Number + 555-123-4567 @@ -1925,7 +1925,7 @@ exports[`CallControlCADComponent Snapshots should render consultation and wrapup - No Phone Number + 555-123-4567 @@ -2219,7 +2219,7 @@ exports[`CallControlCADComponent Snapshots should render consultation and wrapup - No Phone Number + 555-123-4567 @@ -2480,7 +2480,7 @@ exports[`CallControlCADComponent Snapshots should render consultation and wrapup - No Phone Number + 555-123-4567 @@ -2741,7 +2741,7 @@ exports[`CallControlCADComponent Snapshots should render consultation and wrapup - No Phone Number + 555-123-4567 diff --git a/packages/contact-center/cc-components/tests/components/task/CallControlCAD/call-control-cad.tsx b/packages/contact-center/cc-components/tests/components/task/CallControlCAD/call-control-cad.tsx index 4bb2c77f4..e7a321ebe 100644 --- a/packages/contact-center/cc-components/tests/components/task/CallControlCAD/call-control-cad.tsx +++ b/packages/contact-center/cc-components/tests/components/task/CallControlCAD/call-control-cad.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {render} from '@testing-library/react'; import CallControlCADComponent from '../../../../src/components/task/CallControlCAD/call-control-cad'; -import {CallControlComponentProps, TARGET_TYPE} from '../../../../src/components/task/task.types'; +import {CallControlComponentProps, TARGET_TYPE, OUTBOUND_TYPE} from '../../../../src/components/task/task.types'; import {mockTask} from '@webex/test-fixtures'; import {BuddyDetails} from '@webex/cc-store'; import '@testing-library/jest-dom'; @@ -55,6 +55,7 @@ describe('CallControlCADComponent', () => { callAssociatedDetails: { customerName: 'John Doe', ani: '555-123-4567', + dn: '555-999-0000', virtualTeamName: 'Support Team', ronaTimeout: '30', }, @@ -265,6 +266,40 @@ describe('CallControlCADComponent', () => { chatConsultScreen.unmount(); }); + it('should display correct phone number for inbound vs outdial calls', () => { + // Inbound call: caller ID = ani, phone number = ani + const inboundScreen = render(); + // ani (555-123-4567) should appear as both caller ID and phone number + const aniElements = inboundScreen.getAllByText('555-123-4567'); + expect(aniElements.length).toBe(2); // caller ID + phone number + // dn (555-999-0000) should NOT appear anywhere + expect(inboundScreen.queryByText('555-999-0000')).not.toBeInTheDocument(); + inboundScreen.unmount(); + + // Outdial call: caller ID = dn, phone number = ani + const outdialProps = { + ...defaultProps, + currentTask: { + ...defaultProps.currentTask, + data: { + ...defaultProps.currentTask.data, + interaction: { + ...defaultProps.currentTask.data.interaction, + outboundType: OUTBOUND_TYPE.OUTDIAL, + }, + }, + }, + }; + const outdialScreen = render(); + // Caller ID should show dn (555-999-0000) + expect(outdialScreen.getByText('555-999-0000')).toBeInTheDocument(); + // Phone number should show ani (555-123-4567) + const phoneLabel = outdialScreen.getByText('Phone Number:'); + const phoneValue = phoneLabel.nextElementSibling; + expect(phoneValue?.textContent).toBe('555-123-4567'); + outdialScreen.unmount(); + }); + it('should handle wrapup mode and edge cases', () => { // Test wrapup mode hides elements const wrapupProps = { diff --git a/packages/contact-center/cc-components/tests/components/task/IncomingTask/incoming-task.utils.tsx b/packages/contact-center/cc-components/tests/components/task/IncomingTask/incoming-task.utils.tsx index 0198dd810..7f8052ea0 100644 --- a/packages/contact-center/cc-components/tests/components/task/IncomingTask/incoming-task.utils.tsx +++ b/packages/contact-center/cc-components/tests/components/task/IncomingTask/incoming-task.utils.tsx @@ -1,5 +1,5 @@ import {extractIncomingTaskData} from '../../../../src/components/task/IncomingTask/incoming-task.utils'; -import {MEDIA_CHANNEL} from '../../../../src/components/task/task.types'; +import {MEDIA_CHANNEL, OUTBOUND_TYPE} from '../../../../src/components/task/task.types'; import {mockTask} from '@webex/test-fixtures'; describe('incoming-task.utils', () => { @@ -105,6 +105,202 @@ describe('incoming-task.utils', () => { }); }); + describe('Outdial tasks', () => { + it('should use dn (dialed number) as title for outdial telephony tasks', () => { + const originalMediaType = mockTask.data.interaction.mediaType; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Outdial Customer', + virtualTeamName: 'Outbound Team', + ronaTimeout: '30', + }; + + const result = extractIncomingTaskData(mockTask, true); + + expect(result.title).toBe('+14155559876'); // Should show dn, not ani + expect(result.ani).toBe('+18005551234'); + expect(result.isTelephony).toBe(true); + + // Restore + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should fall back to ani when dn is not available for outdial tasks', () => { + const originalMediaType = mockTask.data.interaction.mediaType; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + customerName: 'Outdial Customer', + virtualTeamName: 'Outbound Team', + }; + + const result = extractIncomingTaskData(mockTask, true); + + expect(result.title).toBe('+18005551234'); // Falls back to ani + + // Restore + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should use ani as title for non-outdial telephony tasks', () => { + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Inbound Customer', + virtualTeamName: 'Support Team', + }; + + const result = extractIncomingTaskData(mockTask, true); + + expect(result.title).toBe('+18005551234'); // Should show ani for inbound + + // Restore + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + }); + + it('should fall back to ani when dn is empty string for outdial tasks', () => { + const originalMediaType = mockTask.data.interaction.mediaType; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '', + customerName: 'Outdial Customer', + virtualTeamName: 'Outbound Team', + }; + + const result = extractIncomingTaskData(mockTask, true); + + expect(result.title).toBe('+18005551234'); // Empty dn falls back to ani + + // Restore + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should use ani for CALLBACK outboundType (not OUTDIAL)', () => { + const originalMediaType = mockTask.data.interaction.mediaType; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.CALLBACK; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Callback Customer', + virtualTeamName: 'Callback Team', + }; + + const result = extractIncomingTaskData(mockTask, true); + + expect(result.title).toBe('+18005551234'); // CALLBACK uses ani, not dn + + // Restore + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should still use customerName for social media outdial tasks', () => { + const originalMediaType = mockTask.data.interaction.mediaType; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.SOCIAL; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.interaction.callAssociatedDetails = { + ani: 'social-ani', + dn: 'social-dn', + customerName: 'Social Outdial Customer', + virtualTeamName: 'Social Team', + }; + + const result = extractIncomingTaskData(mockTask, true); + + expect(result.title).toBe('Social Outdial Customer'); // Social always uses customerName + + // Restore + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should extract correct button states for outdial telephony on non-browser', () => { + const originalMediaType = mockTask.data.interaction.mediaType; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalOutboundType = mockTask.data.interaction.outboundType; + const originalWrapUpRequired = mockTask.data.wrapUpRequired; + + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.wrapUpRequired = false; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Outdial Customer', + virtualTeamName: 'Outbound Team', + ronaTimeout: '30', + }; + + const result = extractIncomingTaskData(mockTask, false); + + expect(result.title).toBe('+14155559876'); + expect(result.acceptText).toBe('Ringing...'); + expect(result.declineText).toBeUndefined(); + expect(result.disableAccept).toBe(true); + + // Restore + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.outboundType = originalOutboundType; + mockTask.data.wrapUpRequired = originalWrapUpRequired; + }); + }); + + describe('Standard inbound tasks', () => { + it('should use ani for title when outboundType is undefined (standard inbound)', () => { + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.outboundType = undefined; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Inbound Customer', + virtualTeamName: 'Support Team', + }; + + const result = extractIncomingTaskData(mockTask, true); + + expect(result.title).toBe('+18005551234'); // Standard inbound uses ani + + // Restore + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + }); + describe('Edge cases', () => { it('should handle missing call association details', () => { const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; diff --git a/packages/contact-center/cc-components/tests/components/task/TaskList/task-list.utils.tsx b/packages/contact-center/cc-components/tests/components/task/TaskList/task-list.utils.tsx index ac93a7a84..0e6baa642 100644 --- a/packages/contact-center/cc-components/tests/components/task/TaskList/task-list.utils.tsx +++ b/packages/contact-center/cc-components/tests/components/task/TaskList/task-list.utils.tsx @@ -6,7 +6,7 @@ import { getTasksArray, createTaskSelectHandler, } from '../../../../src/components/task/TaskList/task-list.utils'; -import {MEDIA_CHANNEL, TaskListItemData} from '../../../../src/components/task/task.types'; +import {MEDIA_CHANNEL, TaskListItemData, OUTBOUND_TYPE} from '../../../../src/components/task/task.types'; import {mockTask} from '@webex/test-fixtures'; // Mock the store with a mockable isIncomingTask function @@ -243,6 +243,205 @@ describe('task-list.utils', () => { mockTask.data.interaction.mediaType = originalMediaType; }); }); + + describe('Outdial tasks', () => { + it('should use dn (dialed number) as title for outdial telephony tasks', () => { + const originalState = mockTask.data.interaction.state; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalMediaType = mockTask.data.interaction.mediaType; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.state = 'connected'; + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Outdial Customer', + virtualTeamName: 'Outbound Team', + }; + + const result = extractTaskListItemData(mockTask, true, mockTask.data.agentId); + + expect(result.title).toBe('+14155559876'); // Should show dn, not ani + expect(result.ani).toBe('+18005551234'); + expect(result.isTelephony).toBe(true); + + // Restore + mockTask.data.interaction.state = originalState; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should fall back to ani when dn is not available for outdial tasks', () => { + const originalState = mockTask.data.interaction.state; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalMediaType = mockTask.data.interaction.mediaType; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.state = 'connected'; + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + customerName: 'Outdial Customer', + virtualTeamName: 'Outbound Team', + }; + + const result = extractTaskListItemData(mockTask, true, mockTask.data.agentId); + + expect(result.title).toBe('+18005551234'); // Falls back to ani + + // Restore + mockTask.data.interaction.state = originalState; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should use ani as title for non-outdial telephony tasks even when dn is present', () => { + const originalState = mockTask.data.interaction.state; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalMediaType = mockTask.data.interaction.mediaType; + + mockTask.data.interaction.state = 'connected'; + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Inbound Customer', + virtualTeamName: 'Support Team', + }; + + const result = extractTaskListItemData(mockTask, true, mockTask.data.agentId); + + expect(result.title).toBe('+18005551234'); // Should show ani for inbound + + // Restore + mockTask.data.interaction.state = originalState; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.mediaType = originalMediaType; + }); + + it('should fall back to ani when dn is empty string for outdial tasks', () => { + const originalState = mockTask.data.interaction.state; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalMediaType = mockTask.data.interaction.mediaType; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.state = 'connected'; + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '', + customerName: 'Outdial Customer', + virtualTeamName: 'Outbound Team', + }; + + const result = extractTaskListItemData(mockTask, true, mockTask.data.agentId); + + expect(result.title).toBe('+18005551234'); // Empty dn falls back to ani + + // Restore + mockTask.data.interaction.state = originalState; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should use ani for CALLBACK outboundType (not OUTDIAL)', () => { + const originalState = mockTask.data.interaction.state; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalMediaType = mockTask.data.interaction.mediaType; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.state = 'connected'; + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.CALLBACK; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Callback Customer', + virtualTeamName: 'Callback Team', + }; + + const result = extractTaskListItemData(mockTask, true, mockTask.data.agentId); + + expect(result.title).toBe('+18005551234'); // CALLBACK uses ani, not dn + + // Restore + mockTask.data.interaction.state = originalState; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should still use customerName for social media outdial tasks', () => { + const originalState = mockTask.data.interaction.state; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalMediaType = mockTask.data.interaction.mediaType; + const originalOutboundType = mockTask.data.interaction.outboundType; + + mockTask.data.interaction.state = 'connected'; + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.SOCIAL; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.interaction.callAssociatedDetails = { + ani: 'social-ani', + dn: 'social-dn', + customerName: 'Social Outdial Customer', + virtualTeamName: 'Social Team', + }; + + const result = extractTaskListItemData(mockTask, true, mockTask.data.agentId); + + expect(result.title).toBe('Social Outdial Customer'); // Social always uses customerName + + // Restore + mockTask.data.interaction.state = originalState; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.outboundType = originalOutboundType; + }); + + it('should extract correct button states for incoming outdial telephony on non-browser', () => { + // Mock isIncomingTask to return true for this test + (isIncomingTask as jest.Mock).mockReturnValueOnce(true); + + const originalState = mockTask.data.interaction.state; + const originalCallAssociatedDetails = mockTask.data.interaction.callAssociatedDetails; + const originalMediaType = mockTask.data.interaction.mediaType; + const originalOutboundType = mockTask.data.interaction.outboundType; + const originalWrapUpRequired = mockTask.data.wrapUpRequired; + + mockTask.data.interaction.state = 'new'; + mockTask.data.interaction.mediaType = MEDIA_CHANNEL.TELEPHONY; + mockTask.data.interaction.outboundType = OUTBOUND_TYPE.OUTDIAL; + mockTask.data.wrapUpRequired = false; + mockTask.data.interaction.callAssociatedDetails = { + ani: '+18005551234', + dn: '+14155559876', + customerName: 'Outdial Customer', + virtualTeamName: 'Outbound Team', + ronaTimeout: '30', + }; + + const result = extractTaskListItemData(mockTask, false, mockTask.data.agentId); + + expect(result.title).toBe('+14155559876'); + expect(result.acceptText).toBe('Ringing...'); + expect(result.declineText).toBeUndefined(); + expect(result.disableAccept).toBe(true); + + // Restore + mockTask.data.interaction.state = originalState; + mockTask.data.interaction.callAssociatedDetails = originalCallAssociatedDetails; + mockTask.data.interaction.mediaType = originalMediaType; + mockTask.data.interaction.outboundType = originalOutboundType; + mockTask.data.wrapUpRequired = originalWrapUpRequired; + }); + }); }); describe('isTaskSelectable', () => {