Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
03b80c5
feat: multi conference
rsarika Oct 9, 2025
73a5b54
feat: multi conference tests
rsarika Oct 9, 2025
7992ef0
feat: multi conference fixed types
rsarika Oct 9, 2025
f7a6a01
fix(multy-party-conference): fix-participants design
akulakum Oct 9, 2025
19f1902
Merge branch 'conference' of github.com:rsarika/widgets into conference
akulakum Oct 9, 2025
a0fd964
feat: multi conference fixed participants list logic
rsarika Oct 9, 2025
306264c
feat: multi conference updated tests
rsarika Oct 9, 2025
82a79be
fix(multy-party-conference): fix-failed-uts
akulakum Oct 10, 2025
a26e605
fix: added multiPartyConferenceEnabled feature flag as prop
rsarika Oct 14, 2025
842726b
fix: multiPartyConferenceEnabled added
rsarika Oct 14, 2025
b65d9b9
Merge branch 'ccwidgets' of https://github.com/webex/widgets into con…
rsarika Oct 14, 2025
bb545b3
fix(multy-party-conference): added-uts-for-conference-functionality
akulakum Oct 15, 2025
f2e9df6
Merge branch 'ccwidgets' of https://github.com/webex/widgets into con…
rsarika Oct 16, 2025
1800b06
feat: added allow particpnats to talk checkbox
rsarika Oct 17, 2025
ef5804e
fix(multy-party-conference): fix-conference-uts
akulakum Oct 17, 2025
ab389ac
fix: task selection
rsarika Oct 21, 2025
c54f9ec
fix: max count
rsarika Oct 21, 2025
110b801
Merge branch 'conference'
rsarika Oct 22, 2025
6c59bc1
fix(multy-party-conference): update-cc-sdk-version
akulakum Oct 23, 2025
cdee558
fix(tests): add missing outdialANIId property to agentConfig in test …
akulakum Oct 23, 2025
a71c589
fix: refactor visibility to avoid flags incase of consult
rsarika Oct 27, 2025
8126c32
Merge branch 'ccwidgets' into conference
rsarika Oct 27, 2025
d6399d0
fix: refactored to remove isConsultButtonDisabled
rsarika Oct 28, 2025
f7bb451
fix: refactored to constants
rsarika Oct 28, 2025
5d6318a
fix: removed unused store variables
rsarika Oct 28, 2025
47ecc38
fix: fixed hold timer and refactored consult buttons visibilities
rsarika Oct 28, 2025
f0fcfc7
fix: visibility of consult when others in consult
rsarika Oct 28, 2025
0e9a006
fix: max participants
rsarika Oct 29, 2025
374917e
feat: added switch to main/consult call feature
rsarika Oct 31, 2025
ae70a3c
fix: removed commented code and added documentation
rsarika Oct 31, 2025
8cde7c4
fix: addressed comments
rsarika Oct 31, 2025
8f1746b
fix: missing visibilities
rsarika Oct 31, 2025
975e4c9
fix: visibility of consult screen when wrapupRequired
rsarika Oct 31, 2025
4eedaec
fix: added more condition for EPDN being consulted
rsarika Nov 3, 2025
418036f
fix: added new task:merged event for epdn support
rsarika Nov 4, 2025
758e94d
Merge branch 'ccwidgets' of https://github.com/webex/widgets into con…
rsarika Nov 4, 2025
404ee6f
fix: checkbox fixed
rsarika Nov 4, 2025
6e254c1
fix: updated consult button and end button visibilities
rsarika Nov 4, 2025
5a89b9f
fix: updated end button visibility
rsarika Nov 4, 2025
3728f89
fix: update exit conference visibility
rsarika Nov 4, 2025
0c53e6c
fix: fixed consult visibility
rsarika Nov 4, 2025
80ffada
fix: customerLeft
rsarika Nov 5, 2025
c96ccbf
fix: fixed customer left scenarios
rsarika Nov 5, 2025
40e7ae6
fix: updated switch to main call
rsarika Nov 5, 2025
f69531f
fix(multy-party-conference): address-style-related-issues
akulakum Nov 5, 2025
478db9a
fix: addressed comments
rsarika Nov 5, 2025
36846ef
fix(multy-party-conference): address-review-comments
akulakum Nov 6, 2025
84752ae
fix(multy-party-conference): address-review-comments-for-uts
akulakum Nov 6, 2025
822627a
fix: addressed comments
rsarika Nov 6, 2025
2320263
Merge branch 'conference' of https://github.com/rsarika/widgets into …
rsarika Nov 6, 2025
65ba13c
fix: interaction type from cc sdk
rsarika Nov 6, 2025
eed5212
fix: simplified button click methods
rsarika Nov 6, 2025
811ca91
Merge branch 'ccwidgets' into conference
rsarika Nov 6, 2025
405aedf
fix: consult completed condition
rsarika Nov 7, 2025
a37922a
fix: visibilities of mute
rsarika Nov 10, 2025
34a270e
fix(multy-party-conference): update-cc-sdk-version
akulakum Nov 11, 2025
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
@@ -1,6 +1,6 @@
import {useRef} from 'react';
import {StationLoginLabels} from './constants';
import {LoginOptions, DESKTOP, DIALNUMBER} from '@webex/cc-store';
import {LoginOptions, DESKTOP, DIAL_NUMBER} from '@webex/cc-store';

const handleModals = (
modalRef,
Expand Down Expand Up @@ -270,7 +270,7 @@ const handleDNInputChanged = (
// show error for empty string
setDNErrorText(`${LoginOptions[selectedDeviceType]} ${StationLoginLabels.IS_REQUIRED}`);
setShowDNError(true);
} else if (selectedDeviceType === DIALNUMBER) {
} else if (selectedDeviceType === DIAL_NUMBER) {
setShowDNError(validateDialNumber(input, dialNumberRegex, setDNErrorText, logger));
} else {
setShowDNError(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,57 +1,38 @@
import React, {useState} from 'react';
import React from 'react';
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,
handleTransferPress,
handleEndConsultPress,
handleMuteToggle,
getConsultStatusText,
createTimerKey,
} from './call-control-custom.utils';

const CallControlConsultComponent: React.FC<CallControlConsultComponentsProps> = ({
agentName,
startTimeStamp,
onTransfer,
consultTransfer,
endConsultCall,
consultCompleted,
isAgentBeingConsulted,
isEndConsultEnabled,
consultConference,
switchToMainCall,
logger,
muteUnmute,
isMuted,
onToggleConsultMute,
controlVisibility,
toggleConsultMute,
}) => {
const [isMuteDisabled, setIsMuteDisabled] = useState(false);

const timerKey = createTimerKey(startTimeStamp);

const handleTransfer = () => {
handleTransferPress(onTransfer, logger);
};

const handleEndConsult = () => {
handleEndConsultPress(endConsultCall, logger);
};

const handleConsultMuteToggle = () => {
handleMuteToggle(onToggleConsultMute, setIsMuteDisabled, logger);
};

const buttons = createConsultButtons(
isMuted,
isMuteDisabled,
consultCompleted,
isAgentBeingConsulted,
isEndConsultEnabled,
muteUnmute,
onTransfer ? handleTransfer : undefined,
handleConsultMuteToggle,
handleEndConsult
controlVisibility,
consultTransfer,
toggleConsultMute,
endConsultCall,
consultConference,
switchToMainCall,
logger
);

// Filter buttons that should be shown, then map them
Expand All @@ -66,7 +47,7 @@ const CallControlConsultComponent: React.FC<CallControlConsultComponentsProps> =
{agentName}
</Text>
<Text tagName="p" type="body-secondary" className="consult-sub-text">
{getConsultStatusText(consultCompleted)}&nbsp;&bull;&nbsp;
{getConsultStatusText(controlVisibility.isConsultInitiated)}&nbsp;&bull;&nbsp;
<TaskTimer key={timerKey} startTimeStamp={startTimeStamp} />
</Text>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
import {BuddyDetails, ContactServiceQueue, ILogger} from '@webex/cc-store';
import {MUTE_CALL, UNMUTE_CALL} from '../../constants';

/**
* Interface for button configuration
*/
export interface ButtonConfig {
key: string;
icon: string;
onClick: () => void;
tooltip: string;
className: string;
disabled?: boolean;
shouldShow: boolean;
}
import {ButtonConfig, ControlVisibility} from '../../task.types';

/**
* Interface for list item data
Expand All @@ -27,43 +15,59 @@ export interface ListItemData {
*/
export const createConsultButtons = (
isMuted: boolean,
isMuteDisabled: boolean,
consultCompleted: boolean,
isAgentBeingConsulted: boolean,
isEndConsultEnabled: boolean,
muteUnmute: boolean,
onTransfer?: () => void,
handleConsultMuteToggle?: () => void,
handleEndConsult?: () => void,
controlVisibility: ControlVisibility,
consultTransfer: () => void,
toggleConsultMute: () => void,
endConsultCall: () => void,
consultConference: () => void,
switchToMainCall: () => void,
logger?
): ButtonConfig[] => {
try {
return [
{
key: 'mute',
icon: isMuted ? 'microphone-muted-bold' : 'microphone-bold',
onClick: handleConsultMuteToggle || (() => {}),
onClick: toggleConsultMute,
tooltip: isMuted ? UNMUTE_CALL : MUTE_CALL,
className: `${isMuted ? 'call-control-button-muted' : 'call-control-button'}`,
disabled: isMuteDisabled,
shouldShow: muteUnmute,
disabled: !controlVisibility.muteUnmuteConsult.isEnabled,
isVisible: controlVisibility.muteUnmuteConsult.isVisible,
},
{
key: 'switchToMainCall',
icon: 'call-swap-bold',
tooltip: controlVisibility.isConferenceInProgress ? 'Switch to Conference Call' : 'Switch to Call',
onClick: switchToMainCall,
className: 'call-control-button',
disabled: !controlVisibility.switchToMainCall.isEnabled,
isVisible: controlVisibility.switchToMainCall.isVisible,
},
{
key: 'transfer',
icon: 'next-bold',
tooltip: 'Transfer Consult',
onClick: onTransfer || (() => {}),
tooltip: controlVisibility.isConferenceInProgress ? 'Transfer Conference' : 'Transfer',
onClick: consultTransfer,
className: 'call-control-button',
disabled: !consultCompleted,
shouldShow: isAgentBeingConsulted && !!onTransfer,
disabled: !controlVisibility.consultTransferConsult.isEnabled,
isVisible: controlVisibility.consultTransferConsult.isVisible,
},
{
key: 'conference',
icon: 'call-merge-bold',
tooltip: 'Merge',
onClick: consultConference,
className: 'call-control-button',
disabled: !controlVisibility.mergeConferenceConsult.isEnabled,
isVisible: controlVisibility.mergeConferenceConsult.isVisible,
},
{
key: 'cancel',
icon: 'headset-muted-bold',
tooltip: 'End Consult',
onClick: handleEndConsult || (() => {}),
onClick: endConsultCall,
className: 'call-control-consult-button-cancel',
shouldShow: isEndConsultEnabled || isAgentBeingConsulted,
isVisible: controlVisibility.endConsult.isVisible,
},
];
} catch (error) {
Expand All @@ -82,7 +86,7 @@ export const createConsultButtons = (
*/
export const getVisibleButtons = (buttons: ButtonConfig[], logger?): ButtonConfig[] => {
try {
return buttons.filter((button) => button.shouldShow);
return buttons.filter((button) => button.isVisible);
} catch (error) {
logger?.error('CC-Widgets: CallControlCustom: Error in getVisibleButtons', {
module: 'cc-components#call-control-custom.utils.ts',
Expand Down Expand Up @@ -116,83 +120,12 @@ export const createInitials = (name: string, logger?): string => {
}
};

/**
* Handles transfer button press with logging
*/
export const handleTransferPress = (onTransfer: (() => void) | undefined, logger: ILogger): void => {
logger.info('CC-Widgets: CallControlConsult: transfer button clicked', {
module: 'call-control-consult.tsx',
method: 'handleTransfer',
});

try {
if (onTransfer) {
onTransfer();
logger.log('CC-Widgets: CallControlConsult: transfer completed', {
module: 'call-control-consult.tsx',
method: 'handleTransfer',
});
}
} catch (error) {
throw new Error(`Error transferring call: ${error}`);
}
};

/**
* Handles end consult button press with logging
*/
export const handleEndConsultPress = (endConsultCall: (() => void) | undefined, logger: ILogger): void => {
logger.info('CC-Widgets: CallControlConsult: end consult clicked', {
module: 'call-control-consult.tsx',
method: 'handleEndConsult',
});

try {
if (endConsultCall) {
endConsultCall();
logger.log('CC-Widgets: CallControlConsult: end consult completed', {
module: 'call-control-consult.tsx',
method: 'handleEndConsult',
});
}
} catch (error) {
throw new Error(`Error ending consult call: ${error}`);
}
};

/**
* Handles mute toggle with disabled state management
*/
export const handleMuteToggle = (
onToggleConsultMute: (() => void) | undefined,
setIsMuteDisabled: (disabled: boolean) => void,
logger: ILogger
): void => {
setIsMuteDisabled(true);

try {
if (onToggleConsultMute) {
onToggleConsultMute();
}
} catch (error) {
logger.error(`Mute toggle failed: ${error}`, {
module: 'call-control-consult.tsx',
method: 'handleConsultMuteToggle',
});
} finally {
// Re-enable button after operation
setTimeout(() => {
setIsMuteDisabled(false);
}, 500);
}
};

/**
* Gets the consult status text based on completion state
*/
export const getConsultStatusText = (consultCompleted: boolean, logger?): string => {
export const getConsultStatusText = (consultInitiated: boolean, logger?): string => {
try {
return consultCompleted ? 'Consulting' : 'Consult requested';
return consultInitiated ? 'Consult requested' : 'Consulting';
} catch (error) {
logger?.error('CC-Widgets: CallControlCustom: Error in getConsultStatusText', {
module: 'cc-components#call-control-custom.utils.ts',
Expand Down Expand Up @@ -292,7 +225,8 @@ export const handleTabSelection = (key: string, setSelectedTab: (tab: string) =>
export const handleAgentSelection = (
agentId: string,
agentName: string,
onAgentSelect: ((agentId: string, agentName: string) => void) | undefined,
allowParticipantsToInteract: boolean,
onAgentSelect: ((agentId: string, agentName: string, allowParticipantsToInteract: boolean) => void) | undefined,
logger: ILogger
): void => {
try {
Expand All @@ -301,7 +235,7 @@ export const handleAgentSelection = (
method: 'onAgentSelect',
});
if (onAgentSelect) {
onAgentSelect(agentId, agentName);
onAgentSelect(agentId, agentName, allowParticipantsToInteract);
}
} catch (error) {
logger.error(`CC-Widgets: CallControlCustom: Error in handleAgentSelection: ${error.message}`, {
Expand All @@ -317,7 +251,8 @@ export const handleAgentSelection = (
export const handleQueueSelection = (
queueId: string,
queueName: string,
onQueueSelect: ((queueId: string, queueName: string) => void) | undefined,
allowParticipantsToInteract: boolean,
onQueueSelect: ((queueId: string, queueName: string, allowParticipantsToInteract: boolean) => void) | undefined,
logger: ILogger
): void => {
try {
Expand All @@ -326,7 +261,7 @@ export const handleQueueSelection = (
method: 'onQueueSelect',
});
if (onQueueSelect) {
onQueueSelect(queueId, queueName);
onQueueSelect(queueId, queueName, allowParticipantsToInteract);
Comment thread
rsarika marked this conversation as resolved.
}
} catch (error) {
logger.error(`CC-Widgets: CallControlCustom: Error in handleQueueSelection: ${error.message}`, {
Expand Down Expand Up @@ -684,10 +619,11 @@ export const debounce = <T extends (...args: unknown[]) => unknown>(
export const shouldAddConsultTransferAction = (
selectedCategory: string,
isEntryPointTabVisible: boolean,
allowParticipantsToInteract: boolean,
query: string,
entryPoints: {id: string; name: string}[],
onDialNumberSelect: ((dialNumber: string) => void) | undefined,
onEntryPointSelect: ((entryPointId: string, entryPointName: string) => void) | undefined
onDialNumberSelect: (dialNumber: string, allowParticipantsToInteract: boolean) => void,
onEntryPointSelect: (entryPointId: string, entryPointName: string, allowParticipantsToInteract: boolean) => void
): {visible: boolean; onClick?: () => void; title?: string} => {
const DN_REGEX = new RegExp('^[+1][0-9]{3,18}$|^[*#:][+1][0-9*#:]{3,18}$|^[0-9*#:]{3,18}$');

Expand All @@ -697,14 +633,18 @@ export const shouldAddConsultTransferAction = (

if (isDial) {
return valid && onDialNumberSelect
? {visible: true, onClick: () => onDialNumberSelect(query), title: query}
? {visible: true, onClick: () => onDialNumberSelect(query, allowParticipantsToInteract), title: query}
: {visible: false};
}

if (isEntry) {
const match = query ? entryPoints?.find((e) => e.name === query || e.id === query) : null;
return valid && match && onEntryPointSelect
? {visible: true, onClick: () => onEntryPointSelect(match.id, match.name), title: match.name}
? {
visible: true,
onClick: () => onEntryPointSelect(match.id, match.name, allowParticipantsToInteract),
title: match.name,
}
: {visible: false};
}

Expand Down
Loading
Loading