Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ import {ButtonCircle, TooltipNext, Text} from '@momentum-ui/react-collaboration'
import {Avatar, Icon} from '@momentum-design/components/dist/react';
import TaskTimer from '../../TaskTimer';
import {CallControlConsultComponentsProps} from '../../task.types';
import {
createConsultButtons,
getVisibleButtons,
getConsultStatusText,
createTimerKey,
} from './call-control-custom.utils';
import {createConsultButtons, getVisibleButtons, createTimerKey} from './call-control-custom.utils';

const CallControlConsultComponent: React.FC<CallControlConsultComponentsProps> = ({
agentName,
startTimeStamp,
consultTimerLabel,
consultTimerTimestamp,
consultTransfer,
endConsultCall,
consultConference,
Expand All @@ -22,7 +18,12 @@ const CallControlConsultComponent: React.FC<CallControlConsultComponentsProps> =
controlVisibility,
toggleConsultMute,
}) => {
const timerKey = createTimerKey(startTimeStamp);
// Use the label and timestamp calculated in helper.ts
// Stable key based on timestamp to prevent timer resets
const timerKey = createTimerKey(consultTimerTimestamp);

// Use consultTimerTimestamp with fallback
const effectiveTimestamp = consultTimerTimestamp || Date.now();

const buttons = createConsultButtons(
isMuted,
Expand All @@ -47,8 +48,8 @@ const CallControlConsultComponent: React.FC<CallControlConsultComponentsProps> =
{agentName}
</Text>
<Text tagName="p" type="body-secondary" className="consult-sub-text">
{getConsultStatusText(controlVisibility.isConsultInitiated)}&nbsp;&bull;&nbsp;
<TaskTimer key={timerKey} startTimeStamp={startTimeStamp} />
{consultTimerLabel}&nbsp;&bull;&nbsp;
<TaskTimer key={timerKey} startTimeStamp={effectiveTimestamp} />
</Text>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) =>
isRecording,
holdTime,
consultAgentName,
consultStartTimeStamp,
consultTimerLabel,
consultTimerTimestamp,
endConsultCall,
consultTransfer,
consultConference,
switchToMainCall,
callControlClassName,
callControlConsultClassName,
startTimestamp,
stateTimerLabel,
stateTimerTimestamp,
controlVisibility,
logger,
isMuted,
Expand Down Expand Up @@ -166,6 +169,12 @@ const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) =>
<div className="call-details-row">
<Text className="call-timer" type="body-secondary" tagName={'small'} data-testid="cc-cad:call-timer">
{currentMediaType.labelName} - <TaskTimer startTimeStamp={startTimestamp} />
{stateTimerLabel && stateTimerTimestamp && (
<>
{' '}
• {stateTimerLabel} - <TaskTimer startTimeStamp={stateTimerTimestamp} />
</>
)}
</Text>
{controlVisibility.isConferenceInProgress && !controlVisibility.wrapup.isVisible && (
<>
Expand Down Expand Up @@ -271,7 +280,8 @@ const CallControlCADComponent: React.FC<CallControlComponentProps> = (props) =>
<div className={`call-control-consult-container ${callControlConsultClassName || ''}`}>
<CallControlConsultComponent
agentName={consultAgentName}
startTimeStamp={consultStartTimeStamp}
consultTimerLabel={consultTimerLabel}
consultTimerTimestamp={consultTimerTimestamp}
endConsultCall={endConsultCall}
consultTransfer={consultTransfer}
consultConference={consultConference}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,24 @@ export interface ControlProps {
consultTransfer: () => void;

/**
* Timestamp when the consult call started.
* Label for the state timer (e.g., "Wrap Up", "Post Call").
*/
consultStartTimeStamp?: number;
stateTimerLabel?: string | null;

/**
* Timestamp for the state timer.
*/
stateTimerTimestamp?: number;

/**
* Label for the consult timer (e.g., "Consulting", "Consult on Hold").
*/
consultTimerLabel?: string;

/**
* Timestamp for the consult timer.
*/
consultTimerTimestamp?: number;

/**
* Audio stream for the call control.
Expand Down Expand Up @@ -462,14 +477,17 @@ export type CallControlComponentProps = Pick<
| 'exitConference'
| 'endConsultCall'
| 'consultTransfer'
| 'consultStartTimeStamp'
| 'callControlAudio'
| 'consultAgentName'
| 'setConsultAgentName'
| 'holdTime'
| 'callControlClassName'
| 'callControlConsultClassName'
| 'startTimestamp'
| 'stateTimerLabel'
| 'stateTimerTimestamp'
| 'consultTimerLabel'
| 'consultTimerTimestamp'
| 'allowConsultToQueue'
| 'lastTargetType'
| 'setLastTargetType'
Expand Down Expand Up @@ -600,7 +618,8 @@ export interface ConsultTransferPopoverComponentProps {
*/
export interface CallControlConsultComponentsProps {
agentName: string;
startTimeStamp: number;
consultTimerLabel: string;
consultTimerTimestamp: number;
consultTransfer: () => void;
endConsultCall: () => void;
consultConference: () => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ describe('CallControlConsultComponent Snapshots', () => {

const defaultProps = {
agentName: 'Alice',
startTimeStamp: Date.now(),
consultTimerLabel: 'Consulting',
consultTimerTimestamp: Date.now(),
consultTransfer: mockOnTransfer,
endConsultCall: mockEndConsultCall,
toggleConsultMute: mockOnToggleConsultMute,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ describe('CallControlConsultComponent', () => {

const defaultProps = {
agentName: 'Alice',
startTimeStamp: Date.now(),
consultTimerLabel: 'Consulting',
consultTimerTimestamp: Date.now(),
consultTransfer: mockOnTransfer,
endConsultCall: mockEndConsultCall,
toggleConsultMute: mockOnToggleConsultMute,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,17 @@ describe('CallControlComponent Snapshots', () => {
consultCall: jest.fn(),
endConsultCall: jest.fn(),
consultTransfer: jest.fn(),
consultStartTimeStamp: undefined,
callControlAudio: null,
consultAgentName: '',
setConsultAgentName: jest.fn(),
holdTime: 0,
callControlClassName: '',
callControlConsultClassName: '',
startTimestamp: Date.now(),
stateTimerLabel: null,
stateTimerTimestamp: 0,
consultTimerLabel: 'Consulting',
consultTimerTimestamp: 0,
allowConsultToQueue: mockProfile.allowConsultToQueue,
lastTargetType: 'agent',
setLastTargetType: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,17 @@ describe('CallControlComponent', () => {
consultCall: jest.fn(),
endConsultCall: jest.fn(),
consultTransfer: jest.fn(),
consultStartTimeStamp: Date.now(),
callControlAudio: null as unknown as MediaStream,
consultAgentName: '',
setConsultAgentName: jest.fn(),
holdTime: 0,
callControlClassName: '',
callControlConsultClassName: '',
startTimestamp: Date.now(),
stateTimerLabel: null,
stateTimerTimestamp: 0,
consultTimerLabel: 'Consulting',
consultTimerTimestamp: 0,
allowConsultToQueue: true,
lastTargetType: 'agent',
setLastTargetType: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,17 @@ describe('CallControlCADComponent Snapshots', () => {
consultCall: jest.fn(),
endConsultCall: jest.fn(),
consultTransfer: jest.fn(),
consultStartTimeStamp: 1234567890000,
callControlAudio: null,
consultAgentName: '',
setConsultAgentName: jest.fn(),
holdTime: 0,
callControlClassName: '',
callControlConsultClassName: '',
startTimestamp: 1234567890000,
stateTimerLabel: null,
stateTimerTimestamp: 0,
consultTimerLabel: 'Consulting',
consultTimerTimestamp: 0,
allowConsultToQueue: true,
lastTargetType: 'agent',
setLastTargetType: jest.fn(),
Expand Down Expand Up @@ -272,7 +275,6 @@ describe('CallControlCADComponent Snapshots', () => {
isConsultInitiatedOrAccepted: true,
},
consultAgentName: 'Consult Agent',
consultStartTimeStamp: 1234567890000,
};
screen = render(<CallControlCADComponent {...consultAcceptedProps} />);
mainContainer = screen.container.querySelector('.call-control-container');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,17 @@ describe('CallControlCADComponent', () => {
consultCall: jest.fn(),
endConsultCall: jest.fn(),
consultTransfer: jest.fn(),
consultStartTimeStamp: Date.now(),
callControlAudio: null as unknown as MediaStream,
consultAgentName: '',
setConsultAgentName: jest.fn(),
holdTime: 0,
callControlClassName: '',
callControlConsultClassName: '',
startTimestamp: Date.now(),
stateTimerLabel: null,
stateTimerTimestamp: 0,
consultTimerLabel: 'Consulting',
consultTimerTimestamp: 0,
allowConsultToQueue: true,
lastTargetType: 'agent',
setLastTargetType: jest.fn(),
Expand Down Expand Up @@ -232,7 +235,6 @@ describe('CallControlCADComponent', () => {
const consultProps = {
...defaultProps,
consultAgentName: 'Consult Agent',
consultStartTimeStamp: Date.now(),
controlVisibility: {
...mockControlVisibility,
isConsultInitiatedOrAccepted: true,
Expand Down
29 changes: 29 additions & 0 deletions packages/contact-center/store/src/task-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,32 @@ export const findHoldStatus = (task: ITask, mType: string, agentId: string): boo
: false
: (interaction.media[mediaId] && interaction.media[mediaId].isHold) || false; // For all the other agent for main whatever is the status of main call hold
};

/**
* Finds the hold timestamp for a specific media type (mainCall, consult, etc.)
* Used for timer alignment in Consult & Conference scenarios to match Agent Desktop behavior.
*
* @param task - The task object containing interaction data
* @param mType - The media type to search for ('mainCall', 'consult', 'conference')
* @returns The hold timestamp in milliseconds or null if not on hold
*/
export const findHoldTimestamp = (task: ITask, mType: string): number | null => {
const interaction = task?.data?.interaction;

if (!interaction || !interaction.media) {
return null;
}

// Adjust mType if agent is secondary EPDN agent
mType = setmTypeForEPDN(task, mType);

// Find media ID for the specified type (mainCall, consult, etc.)
const mediaId = findMediaResourceId(task, mType);

// Return the holdTimestamp if media exists and has a hold timestamp
if (mediaId && interaction.media[mediaId]?.holdTimestamp !== undefined) {
return interaction.media[mediaId].holdTimestamp;
}

return null;
};
Loading
Loading