Skip to content
Open
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 @@ -414,12 +414,12 @@ export interface ControlProps {
/**
* Function to set the last target type
*/
lastTargetType: 'queue' | 'agent';
lastTargetType: 'queue' | 'agent' | 'entryPoint' | 'dialNumber';

/**
* Function to set the last target type
*/
setLastTargetType: (targetType: 'queue' | 'agent') => void;
setLastTargetType: (targetType: 'queue' | 'agent' | 'entryPoint' | 'dialNumber') => void;

controlVisibility: ControlVisibility;

Expand Down
118 changes: 104 additions & 14 deletions packages/contact-center/task/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ export const useCallControl = (props: useCallControlProps) => {
// Consult timer labels and timestamps
const [consultTimerLabel, setConsultTimerLabel] = useState<string>(TIMER_LABEL_CONSULTING);
const [consultTimerTimestamp, setConsultTimerTimestamp] = useState<number>(0);
const [lastTargetType, setLastTargetType] = useState<'agent' | 'queue'>('agent');
const [lastTargetType, setLastTargetType] = useState<'agent' | 'queue' | 'entryPoint' | 'dialNumber'>('agent');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please replace the inline union type
useState<'agent' | 'queue' | 'entryPoint' | 'dialNumber'>
with a shared enum or constant-based TargetType to avoid string duplication, improve type safety, and make future refactors safer.

const [conferenceParticipants, setConferenceParticipants] = useState<Participant[]>([]);

// Use custom hook for hold timer management
Expand All @@ -322,21 +322,111 @@ export const useCallControl = (props: useCallControlProps) => {
const {interaction} = currentTask.data;
const myAgentId = store.cc.agentConfig?.agentId;

// Find all agent participants except the current agent
const otherAgents = Object.values(interaction.participants || {}).filter(
(participant): participant is Participant =>
(participant as Participant).pType === 'Agent' && (participant as Participant).id !== myAgentId
);
// For Entry Point or Dial Number consults, check if destination agent has joined
if (lastTargetType === 'entryPoint' || lastTargetType === 'dialNumber') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add enum or constant-based TargetType to avoid string duplication

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const consultDestinationAgentName = (interaction as any).callProcessingDetails?.consultDestinationAgentName;

if (consultDestinationAgentName) {
// Destination agent has joined, show their name
setConsultAgentName(consultDestinationAgentName);
logger.info(`${lastTargetType} consult answered - showing agent name: ${consultDestinationAgentName}`, {
module: 'widget-cc-task#helper.ts',
method: 'useCallControl#extractConsultingAgent',
});
} else {
// Still ringing - find the EP/DN participant in the consult media
const consultMediaResourceId = findMediaResourceId(currentTask, 'consult');

if (consultMediaResourceId && interaction.media?.[consultMediaResourceId]) {
const consultMedia = interaction.media[consultMediaResourceId];
// Find the participant in consult media who is not the current agent
const consultParticipantId = consultMedia.participants?.find(
(participantId: string) => participantId !== myAgentId
);

if (consultParticipantId && interaction.participants[consultParticipantId]) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const participant = interaction.participants[consultParticipantId] as any;
const phoneNumber = participant.dn || participant.id;

if (phoneNumber && phoneNumber !== consultAgentName) {
setConsultAgentName(phoneNumber);
logger.info(`${lastTargetType} consult ringing - showing phone number: ${phoneNumber}`, {
module: 'widget-cc-task#helper.ts',
method: 'useCallControl#extractConsultingAgent',
});
}
}
}
}
return;
}

// Pick the first other agent (should only be one in a consult)
const foundAgent = otherAgents.length > 0 ? {id: otherAgents[0].id, name: otherAgents[0].name} : null;
// For regular agent consults, find the agent in the consult media
const consultMediaResourceId = findMediaResourceId(currentTask, 'consult');

if (foundAgent) {
setConsultAgentName(foundAgent.name);
logger.info(`Consulting agent detected: ${foundAgent.name} ${foundAgent.id}`, {
module: 'widget-cc-task#helper.ts',
method: 'useCallControl#extractConsultingAgent',
if (consultMediaResourceId && interaction.media?.[consultMediaResourceId]) {
const consultMedia = interaction.media[consultMediaResourceId];
// Find the agent participant in consult media who is not the current agent
const consultParticipantId = consultMedia.participants?.find((participantId: string) => {
const participant = interaction.participants[participantId];
return participant && participant.id !== myAgentId && participant.pType === 'Agent';
});

if (consultParticipantId && interaction.participants[consultParticipantId]) {
const consultAgent = interaction.participants[consultParticipantId];
setConsultAgentName(consultAgent.name || consultAgent.id);
logger.info(`Consulting agent detected: ${consultAgent.name} ${consultAgent.id}`, {
module: 'widget-cc-task#helper.ts',
method: 'useCallControl#extractConsultingAgent',
});
}
} else {
// Fallback: Use old logic if consult media not found
const otherAgents = Object.values(interaction.participants || {}).filter(
(participant): participant is Participant =>
(participant as Participant).pType === 'Agent' && (participant as Participant).id !== myAgentId
);

// In a conference with multiple agents, find the agent currently being consulted
// Priority: 1) consultState="consulting" 2) most recent consultTimestamp
let foundAgent: {id: string; name: string} | null = null;

if (otherAgents.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const consultingAgent = otherAgents.find((agent: any) => agent.consultState === 'consulting');

if (consultingAgent) {
foundAgent = {
id: consultingAgent.id,
name: consultingAgent.name,
};
} else {
// Fallback: Find agent with most recent consultTimestamp
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const agentWithMostRecentTimestamp = otherAgents.reduce((latest: any, current: any) => {
const currentTimestamp = current.consultTimestamp || current.joinTimestamp || 0;
const latestTimestamp = latest ? latest.consultTimestamp || latest.joinTimestamp || 0 : 0;
return currentTimestamp > latestTimestamp ? current : latest;
}, null);

if (agentWithMostRecentTimestamp) {
foundAgent = {
id: agentWithMostRecentTimestamp.id,
name: agentWithMostRecentTimestamp.name,
};
}
}
}

if (foundAgent) {
setConsultAgentName(foundAgent.name);
logger.info(`Consulting agent detected (fallback): ${foundAgent.name} ${foundAgent.id}`, {
module: 'widget-cc-task#helper.ts',
method: 'useCallControl#extractConsultingAgent',
});
}
}
} catch (error) {
console.log('error', error);
Expand All @@ -345,7 +435,7 @@ export const useCallControl = (props: useCallControlProps) => {
method: 'extractConsultingAgent',
});
}
}, [currentTask, logger]);
}, [currentTask, logger, lastTargetType, consultAgentName, setConsultAgentName]);

// Extract main call timestamp whenever currentTask changes
useEffect(() => {
Expand Down
Loading
Loading