Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,6 @@
"Resources-View-Eligibility": "Eligibility",
"Resources-CopyId": "Copy ID",
"Resources-IdCopied": "Copied!",
"Conference-AddConferenceCallParticipant": "Add Conference Call Participant",
"Conference-EnterPhoneNumber": "Enter phone number",
"Conference-DialButton": "Dial",
"HangupCallLeaveTooltip": "Leave Call",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,6 @@
"Resources-IdCopied": "Copied!",
"Forms-ResourceReferralsList-Add": "Add",
"Forms-ResourceReferralsList-Delete": "Delete",
"Conference-AddConferenceCallParticipant": "Add Conference Call Participant",
"Conference-EnterPhoneNumber": "Enter phone number",
"Conference-DialButton": "Dial",
"Conference-Actions-Leave": "Leave Call",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,24 @@ import { setCallStatusAction, setIsDialogOpenAction, setPhoneNumberAction } from
import { CallStatus, isCallStatusLoading } from '../../../states/conferencing/callStatus';
import { conferencingBase, namespace } from '../../../states/storeNamespaces';
import * as conferenceApi from '../../../services/conferenceService';
import { getHrmConfig } from '../../../hrmConfig';
import { selectQuickDialOptions } from '../../../states/configuration/selectQuickDialOptions';

type Props = TaskContextProps;
const ADD_TO_CONFERENCE_KEY = 'Conference-Actions-Add';

const ConferencePanel: React.FC<Props> = ({ task, conference }) => {
const taskFromRedux = useSelector((state: RootState) => state[namespace][conferencingBase].tasks[task.taskSid]);

const conferencingQuickDialOptions = useSelector(selectQuickDialOptions);
const { isDialogOpen, callStatus, phoneNumber } = taskFromRedux ?? {};
const dispatch = useDispatch();

const setIsDialogOpen = (isOpen: boolean) => dispatch(setIsDialogOpenAction(task.taskSid, isOpen));
const setCallStatus = (callStatus: CallStatus) => dispatch(setCallStatusAction(task.taskSid, callStatus));
const setPhoneNumber = (number: string) => dispatch(setPhoneNumberAction(task.taskSid, number));

const { conferencingEnableManualDial } = getHrmConfig();

const toggleDialog = () => {
setIsDialogOpen(!isDialogOpen);
};
Expand All @@ -50,6 +54,10 @@ const ConferencePanel: React.FC<Props> = ({ task, conference }) => {
if (callStatus === 'busy' || callStatus === 'failed') {
Notifications.showNotificationSingle(ConferenceNotifications.ErrorAddingParticipantNotification);
}
if (callStatus === 'in-progress') {
setIsDialogOpen(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [callStatus]);

const conferenceSid = conference?.source?.conferenceSid;
Expand All @@ -59,7 +67,7 @@ const ConferencePanel: React.FC<Props> = ({ task, conference }) => {
return null;
}

const handleClick = (phoneNumberGetter: () => string) => async () => {
const handleClick = async () => {
try {
const { status, callStatusSyncDocument } = await createCallStatusSyncDocument(({ data }) => {
setCallStatus(data.CallStatus);
Expand All @@ -70,7 +78,7 @@ const ConferencePanel: React.FC<Props> = ({ task, conference }) => {
}

const from = Manager.getInstance().serviceConfiguration.outbound_call_flows.default.caller_id;
const to = phoneNumberGetter();
const to = phoneNumber;
const label = `External party ${to}`;

await Promise.all(
Expand Down Expand Up @@ -117,10 +125,11 @@ const ConferencePanel: React.FC<Props> = ({ task, conference }) => {
<PhoneInputDialog
targetNumber={phoneNumber}
setTargetNumber={setPhoneNumber}
handleManualDialClick={handleClick(() => phoneNumber)}
handleQuickDialClick={(numberToDial: string) => handleClick(() => numberToDial)()}
handleClick={handleClick}
setIsDialogOpen={setIsDialogOpen}
isLoading={isCallStatusLoading(callStatus)}
quickDialOptions={conferencingQuickDialOptions}
enableManualDial={conferencingEnableManualDial}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,98 +14,150 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import React from 'react';
import { Template, Manager } from '@twilio/flex-ui';
import { CallEnd as CallEndIcon } from '@material-ui/icons';
import { Template, Manager, Tab as TwilioTab } from '@twilio/flex-ui';
import { Phone as PhoneIcon } from '@material-ui/icons';
import { CircularProgress } from '@material-ui/core';
import { useSelector } from 'react-redux';

import { Row, Bold, CloseButton, SecondaryButton } from '../../../styles';
import { PhoneDialogWrapper, DialogArrow } from './styles';
import { selectQuickDialOptions } from '../../../states/configuration/selectQuickDialOptions';
import { getHrmConfig } from '../../../hrmConfig';
import { Row, Bold, CloseButton, PrimaryButton } from '../../../styles';
import {
PhoneDialogWrapper,
PhoneDialogFooter,
PhoneDialogContent,
PhoneNumberInput,
QuickDialSelect,
HelpText,
} from './styles';
import type { QuickDialOption } from '../../../states/configuration/reducer';
import { lookupTranslation } from '../../../translations';
import { StyledTabs } from '../../search/styles';

type PhoneDialogProps = {
targetNumber: string;
setTargetNumber: (targetNumber: string) => void;
handleManualDialClick: () => void;
handleQuickDialClick: (phoneNumber: string) => void;
handleClick: () => void;
setIsDialogOpen: (isDialogOpen: boolean) => void;
isLoading: boolean;
quickDialOptions: QuickDialOption[];
enableManualDial: boolean;
};

type TabValue = 'quickDial' | 'enterNumber';

const ENTER_NUMBER_KEY = 'Conference-EnterPhoneNumber';
const QUICK_DIAL_TAB_KEY = 'Conference-QuickDialTab';
const ENTER_NUMBER_TAB_KEY = 'Conference-EnterNumberTab';
const PHONE_NUMBER_EXAMPLE_KEY = 'Conference-PhoneNumberExample';
const QUICK_DIAL_SELECT_LABEL_KEY = 'Conference-QuickDialSelectLabel';

const PhoneInputDialog: React.FC<PhoneDialogProps> = ({
targetNumber,
setTargetNumber,
handleQuickDialClick,
handleManualDialClick,
handleClick,
setIsDialogOpen,
isLoading,
quickDialOptions,
enableManualDial,
}) => {
const quickDialOptions = useSelector(selectQuickDialOptions);
const { allowManualDialOutForConferencing } = getHrmConfig();
const hasQuickDial = quickDialOptions && quickDialOptions.length > 0;
const showTabs = hasQuickDial && enableManualDial;

const defaultTab: TabValue = hasQuickDial ? 'quickDial' : 'enterNumber';
const [activeTab, setActiveTab] = React.useState<TabValue>(defaultTab);

React.useEffect(() => {
if (hasQuickDial) {
setTargetNumber(quickDialOptions[0].phoneNumber);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const dialButton = (handleClick: () => void) => {
return (
<SecondaryButton autoFocus onClick={handleClick} disabled={isLoading}>
{isLoading ? (
<CircularProgress size={30} style={{ color: '#fff' }} />
) : (
<>
<CallEndIcon fontSize="medium" /> &nbsp; &nbsp;
<Template code="Conference-DialButton" />
</>
)}
</SecondaryButton>
);
const handleTabChange = (value: TabValue) => {
setActiveTab(value);
if (value === 'quickDial' && quickDialOptions.length > 0) {
setTargetNumber(quickDialOptions[0].phoneNumber);
} else if (value === 'enterNumber') {
setTargetNumber('');
}
};

const handleNumberChange: React.ChangeEventHandler<HTMLInputElement> = e => {
setTargetNumber(e.target.value);
};

const handleQuickDialChange: React.ChangeEventHandler<HTMLSelectElement> = e => {
setTargetNumber(e.target.value);
};

const isDialButtonDisabled = isLoading || (activeTab === 'enterNumber' && !targetNumber?.trim());
const renderQuickDial = () => (
<PhoneDialogContent>
<QuickDialSelect
value={targetNumber}
onChange={handleQuickDialChange}
disabled={isLoading}
aria-label={Manager.getInstance().strings[QUICK_DIAL_SELECT_LABEL_KEY]}
>
{quickDialOptions.map(option => (
<option key={option.phoneNumber} value={option.phoneNumber}>
{lookupTranslation(option.labelKey)}
</option>
))}
</QuickDialSelect>
</PhoneDialogContent>
);
const renderManualDial = () => (
<PhoneDialogContent>
<PhoneNumberInput
type="text"
id="number-input"
value={targetNumber}
onChange={handleNumberChange}
disabled={isLoading}
aria-label={Manager.getInstance().strings[ENTER_NUMBER_KEY]}
/>
<HelpText>{lookupTranslation(PHONE_NUMBER_EXAMPLE_KEY)}</HelpText>
</PhoneDialogContent>
);
return (
<PhoneDialogWrapper>
<DialogArrow />
<Row>
<Bold>
<Template code="Conference-AddConferenceCallParticipant" />
</Bold>
<CloseButton onClick={() => setIsDialogOpen(false)} aria-label="CloseButton" style={{ marginLeft: 'auto' }} />
</Row>
{Boolean(quickDialOptions.length) && (
<Row>
<Template code="Conference-PhoneInputDialog-QuickDialTitle" />
</Row>
)}
{quickDialOptions.map(({ phoneNumber, labelKey }) => (
<Row key={labelKey}>
<Template code={labelKey} /> {dialButton(() => handleQuickDialClick(phoneNumber))}
</Row>
))}
<Row key="or">
{Boolean(quickDialOptions.length) && allowManualDialOutForConferencing && (
<Template code="Conference-PhoneInputDialog-Or" />
)}
</Row>
{allowManualDialOutForConferencing && (
{showTabs ? (
<StyledTabs
selectedTabName={activeTab}
onTabSelected={handleTabChange}
alignment="center"
keepTabsMounted={false}
>
<TwilioTab uniqueName="quickDial" label={<Template code={QUICK_DIAL_TAB_KEY} />} key="quickDial">
{hasQuickDial && renderQuickDial()}
</TwilioTab>
<TwilioTab uniqueName="enterNumber" label={<Template code={ENTER_NUMBER_TAB_KEY} key="enterNumber" />}>
{enableManualDial && renderManualDial()}
</TwilioTab>
</StyledTabs>
) : (
<>
<Template code={ENTER_NUMBER_KEY} />
<Row>
<input
type="text"
id="number-input"
placeholder="+1 234-567-8910"
value={targetNumber}
onChange={handleNumberChange}
style={{ width: '60%', padding: '5px' }}
disabled={isLoading}
aria-label={Manager.getInstance().strings[ENTER_NUMBER_KEY]}
/>
{dialButton(handleManualDialClick)}
</Row>
{hasQuickDial && renderQuickDial()}
{enableManualDial && renderManualDial()}
Comment on lines +145 to +146

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be rendered based on which tab is selected? 🤔

</>
)}
<PhoneDialogFooter>
<PrimaryButton autoFocus onClick={handleClick} disabled={isDialButtonDisabled}>
{isLoading ? (
<CircularProgress size={16} style={{ color: '#fff' }} />
) : (
<>
<PhoneIcon fontSize="small" style={{ marginRight: '6px' }} />
<Template code="Conference-DialButton" />
</>
)}
</PrimaryButton>
</PhoneDialogFooter>
</PhoneDialogWrapper>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

import { styled } from '@twilio/flex-ui';

import { Flex } from '../../../styles';

export const ConferenceButtonWrapper = styled('div')`
margin-left: 8px;
margin-right: 8px;
Expand Down Expand Up @@ -46,44 +44,61 @@ export const PhoneDialogWrapper = styled('div')<PhoneDialogWrapperProps>`
`;
PhoneDialogWrapper.displayName = 'PhoneDialogWrapper';

type DialogArrowProps = {
left?: string;
};
export const PhoneDialogContent = styled('div')`
margin: 12px 0;
`;
PhoneDialogContent.displayName = 'PhoneDialogContent';

export const DialogArrow = styled(Flex)<DialogArrowProps>`
position: absolute;
bottom: 0;
left: 125px;
background: #ffffff;
border: 0px solid #d3d3d3;
export const PhoneDialogFooter = styled('div')`
display: flex;
justify-content: flex-end;
margin-top: 8px;
`;
PhoneDialogFooter.displayName = 'PhoneDialogFooter';

&:after,
&:before {
top: 100%;
left: 50%;
border: solid transparent;
content: '';
height: 0;
width: 0;
position: absolute;
pointer-events: none;
export const PhoneNumberInput = styled('input')`
width: 100%;
padding: 8px;
box-sizing: border-box;
border: 1px solid #d1d5db;
border-radius: 4px;
font-size: 14px;
background-color: #f3f4f6;

&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
`;
PhoneNumberInput.displayName = 'PhoneNumberInput';

&:after {
border-color: rgba(255, 255, 255, 0);
border-top-color: #ffffff;
border-width: 10px;
margin-left: -10px;
export const QuickDialSelect = styled('select')`
width: 100%;
padding: 8px;
box-sizing: border-box;
border: 1px solid #d1d5db;
border-radius: 4px;
font-size: 14px;
background-color: #f3f4f6;
cursor: pointer;
appearance: auto;

&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
`;
QuickDialSelect.displayName = 'QuickDialSelect';

&:before {
border-color: rgba(211, 211, 211, 0);
border-top-color: rgba(211, 211, 211, 0.7);
border-width: 13px;
margin-left: -13px;
export const HelpText = styled('p')`
&& {
margin: 6px 0 0;
font-size: 13px;
font-weight: normal;
color: #606b85;
}
`;
DialogArrow.displayName = 'DialogArrow';
HelpText.displayName = 'HelpText';

export const ConferenceButton = styled('button')`
border-style: none;
Expand Down
Loading
Loading