Skip to content

Switchboarding POC #2693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions plugin-hrm-form/src/HrmFormPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { getAseloFeatureFlags, getHrmConfig, initializeConfig, subscribeToConfig
import { setUpSharedStateClient } from './utils/sharedState';
import { FeatureFlags } from './types/types';
import { setUpReferrableResources } from './components/resources/setUpReferrableResources';
import QueuesView from './components/queuesView';
import TeamsView from './components/teamsView';
import { setUpCounselorToolkits } from './components/toolkits/setUpCounselorToolkits';
import { setUpTransferComponents } from './components/transfer/setUpTransferComponents';
Expand Down Expand Up @@ -131,6 +132,8 @@ const setUpComponents = (
TeamsView.setUpTeamsViewFilters();
TeamsView.setUpWorkerDirectoryFilters();

QueuesView.setUpSwitchboarding();

if (featureFlags.enable_conferencing) setupConferenceComponents();
};

Expand Down
6 changes: 3 additions & 3 deletions plugin-hrm-form/src/___tests__/mockStyled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,12 @@ jest.mock('../components/callTypeButtons/styles', () => ({
Label: 'Label',
DataCallTypeButton: 'DataCallTypeButton',
NonDataCallTypeButton: 'NonDataCallTypeButton',
CloseTaskDialog: 'CloseTaskDialog',
CloseTaskDialogText: 'CloseTaskDialogText',
DialogStyled: 'DialogStyled',
DialogStyledText: 'DialogStyledText',
ConfirmButton: 'ConfirmButton',
CancelButton: 'CancelButton',
CloseButton: 'CloseButton',
NonDataCallTypeDialogContainer: 'NonDataCallTypeDialogContainer',
DialogContainer: 'DialogContainer',
}));

jest.mock('../components/queuesStatus/styles', () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
import { Template } from '@twilio/flex-ui';

import { Box, Row, HiddenText } from '../../styles';
import {

Check failure on line 21 in plugin-hrm-form/src/components/callTypeButtons/SaveContactCallTypeDialog.tsx

View workflow job for this annotation

GitHub Actions / flex-ci / lint

Replace `⏎··DialogStyled,⏎··DialogStyledText,⏎··DialogContainer,⏎··ConfirmButton,⏎··CancelButton,⏎··CloseButton,⏎` with `·DialogStyled,·DialogStyledText,·DialogContainer,·ConfirmButton,·CancelButton,·CloseButton·`
CloseTaskDialog,
CloseTaskDialogText,
NonDataCallTypeDialogContainer,
DialogStyled,
DialogStyledText,
DialogContainer,
ConfirmButton,
CancelButton,
CloseButton,
Expand All @@ -47,18 +47,18 @@
handleConfirm,
handleCancel,
}) => (
<CloseTaskDialog onClose={handleCancel} open={isOpen}>
<DialogStyled onClose={handleCancel} open={isOpen}>
<TabPressWrapper>
<NonDataCallTypeDialogContainer>
<DialogContainer>
<Box marginLeft="auto">
<HiddenText id="CloseButton">
<Template code="CloseButton" />
</HiddenText>
<CloseButton tabIndex={3} aria-label="CloseButton" onClick={handleCancel} />
</Box>
<CloseTaskDialogText>
<DialogStyledText>
<Template code="NonDataCallTypeDialog-CloseConfirm" />
</CloseTaskDialogText>
</DialogStyledText>
<Box marginBottom="32px">
<Row>
<ConfirmButton
Expand All @@ -80,9 +80,9 @@
</CancelButton>
</Row>
</Box>
</NonDataCallTypeDialogContainer>
</DialogContainer>
</TabPressWrapper>
</CloseTaskDialog>
</DialogStyled>
);

SaveContactCallTypeDialog.displayName = 'SaveContactCallTypeDialog';
Expand Down
6 changes: 3 additions & 3 deletions plugin-hrm-form/src/components/callTypeButtons/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,20 @@ export const NonDataCallTypeButton = styled(Button)<NonDataCallTypeButtonProps>`
}
`;

export const CloseTaskDialog = styled(props => <Dialog {...props} classes={{ paper: 'paper' }} />)`
export const DialogStyled = styled(props => <Dialog {...props} classes={{ paper: 'paper' }} />)`
&& .paper {
width: 360px;
}
`;

export const NonDataCallTypeDialogContainer = styled('div')`
export const DialogContainer = styled('div')`
display: flex;
flex-direction: column;
align-items: center;
padding: 5px;
`;

export const CloseTaskDialogText = styled('p')`
export const DialogStyledText = styled('p')`
font-size: 14px;
font-weight: 700;
margin-bottom: 36px;
Expand Down
6 changes: 3 additions & 3 deletions plugin-hrm-form/src/components/case/CloseCaseDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import WarningIcon from '@material-ui/icons/Warning';

import TabPressWrapper from '../TabPressWrapper';
import { Box, Row, HiddenText, StyledNextStepButton } from '../../styles';
import { CloseButton, CloseTaskDialog } from '../callTypeButtons/styles';
import { CloseButton, DialogStyled } from '../callTypeButtons/styles';
import { CloseDialogText } from './styles';

type OwnProps = {
Expand All @@ -34,7 +34,7 @@ type Props = OwnProps;
const CloseCaseDialog: React.FC<Props> = ({ setDialog, handleDontSaveClose, handleSaveUpdate, openDialog }) => {
return (
<>
<CloseTaskDialog open={openDialog} onClose={setDialog}>
<DialogStyled open={openDialog} onClose={setDialog}>
<TabPressWrapper>
<Box textAlign="end" onClick={setDialog} tabIndex={3}>
<HiddenText id="CloseButton">
Expand Down Expand Up @@ -62,7 +62,7 @@ const CloseCaseDialog: React.FC<Props> = ({ setDialog, handleDontSaveClose, hand
</Row>
<Box marginBottom="25px" />
</TabPressWrapper>
</CloseTaskDialog>
</DialogStyled>
</>
);
};
Expand Down
134 changes: 134 additions & 0 deletions plugin-hrm-form/src/components/queuesView/SwitchboardingCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/

import React, { useState } from 'react';
import { QueuesStats, Template, Manager } from '@twilio/flex-ui';
import {
FormLabel,
FormGroup,
FormControlLabel,
FormControl,
FormHelperText,
Switch,
Modal,
Tab,
IconButton,
} from '@material-ui/core';

import { getAseloFeatureFlags } from '../../hrmConfig';
import TabPressWrapper from '../TabPressWrapper';
import { Box } from '../../styles';
import { CloseButton, DialogContainer, DialogStyled } from '../callTypeButtons/styles';
import { switchboardingQueue } from '../../services/SwitchboardingService';

// eslint-disable-next-line import/no-unused-modules
export const setUpSwitchboarding = () => {
// if (!getAseloFeatureFlags().enable_switchboarding) return;

QueuesStats.AggregatedQueuesDataTiles.Content.add(<SwitchboardingTile key="switchboarding" />, {
sortOrder: -1,
});
};

const SwitchboardingTile = () => {
const [isSwitchboarding, setIsSwitchboarding] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedQueue, setSelectedQueue] = useState<string | null>(null);

const handleOpenModal = () => {
setIsModalOpen(true);
};

const handleCloseModal = () => {
setIsModalOpen(false);
};

const handleSwitchboarding = async queue => {
console.log('>>>>> handleSwitchboarding input', { queue });
const result = await switchboardingQueue(queue);
console.log('>>>>> handleSwitchboarding result', result);
setIsSwitchboarding(!isSwitchboarding);
setSelectedQueue(queue); // Update state after the operation if needed
};

const renderSwitch = () => (
<FormControl component="fieldset">
<FormGroup>
<FormControlLabel
labelPlacement="start"
control={<Switch checked={isSwitchboarding} color="primary" onChange={handleOpenModal} />}
label="Switchboarding"
/>
</FormGroup>
</FormControl>
);

const queues = Manager.getInstance()?.store.getState()?.flex?.realtimeQueues?.queuesList;

const filteredQueues = queues
? Object.values(queues).filter(
(queue: any) => queue.friendly_name !== 'Survey' && queue.friendly_name !== 'Switchboard Queue',
)
: [];

return (
<>
<Box>{renderSwitch()}</Box>
{isModalOpen && (
<DialogStyled open={isModalOpen} onClose={handleCloseModal}>
<TabPressWrapper>
<DialogContainer>
<Box marginLeft="auto">
<Template code="CloseButton" />
<CloseButton tabIndex={3} aria-label="CloseButton" onClick={handleCloseModal} />
</Box>

<div>
<h1>Queues</h1>
<form>
{filteredQueues &&
filteredQueues.map(queue => {
console.log('>>> Queue:', queue);
return (
<div key={queue.key}>
<input
type="radio"
id={queue.key}
name="queue"
value={queue.key}
checked={selectedQueue === queue.key}
onChange={e => setSelectedQueue(e.target.value)}
/>
<label htmlFor={queue.key}>{queue.friendly_name}</label>
</div>
);
})}
<button
type="button"
onClick={() => handleSwitchboarding('WQ55df346e2986acff362141c83f5cdf29')}
// disabled={!selectedQueue}
>
Assign Switchboard
</button>
</form>
</div>
</DialogContainer>
</TabPressWrapper>
</DialogStyled>
)}
</>
);
};
22 changes: 22 additions & 0 deletions plugin-hrm-form/src/components/queuesView/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import { setUpSwitchboarding } from './SwitchboardingCard';

const QueuesView = {
setUpSwitchboarding,
};

export default QueuesView;
2 changes: 1 addition & 1 deletion plugin-hrm-form/src/components/teamsView/SkillsColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const setUpSkillsColumn = () => {
key="skills"
header="Skills"
sortingFn={sortSkills}
style={{ width: 'auto !important' }}
style={{ width: 'auto !important', minWidth: '13%' }}
content={item => <SkillsCell item={item} />}
/>,
{ sortOrder: 0 },
Expand Down
48 changes: 48 additions & 0 deletions plugin-hrm-form/src/services/SwitchboardingService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Copyright (C) 2021-2023 Technology Matters
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/

import { getHrmConfig } from '../hrmConfig';
import fetchProtectedApi from './fetchProtectedApi';
import { TaskSID } from '../types/twilio';
import { ApiError } from './fetchApi';

/**
* Switchboarding service
*/

// eslint-disable-next-line import/no-unused-modules
export const switchboardingQueue = async (queueSid: string): Promise<void> => {
// export type Body = {
// taskSid?: string;
// originalQueueSid?: string;
// targetSid?: string;
// request: { cookies: {}; headers: {} };
// Token: string;
// };

const body = {
// taskSid,
originalQueueSid: queueSid,
};

// return fetchProtectedApi('/assignSwitchboarding', body);
try {
console.log('>>>switchboardingQueue', body);
return await fetchProtectedApi('/assignSwitchboarding', body);
} catch (err) {
throw new ApiError(err.message, { response: err.response, body: err.body });
}
};
1 change: 1 addition & 0 deletions plugin-hrm-form/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ export type FeatureFlags = {
enable_save_insights: boolean; // Enables Saving Aditional Data on Insights
enable_separate_timeline_view: boolean; // Enables a limited inline case timelinbe with a link to the full timeline
enable_sort_cases: boolean; // Enables Sorting at Case List
enable_switchboarding: boolean; // Enables Switchboarding
enable_teams_view_enhancements2: boolean; // Enables custom Teams View UI with labels
enable_transfers: boolean; // Enables Transfering Contacts
enable_twilio_transcripts: boolean; // Enables Viewing Transcripts Stored at Twilio
Expand Down
Loading