Skip to content

Commit

Permalink
[SE-51] Add per-contact transfer options (#629)
Browse files Browse the repository at this point in the history
  • Loading branch information
dremin authored Sep 20, 2024
1 parent 46de177 commit dea22c2
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 17 deletions.
2 changes: 1 addition & 1 deletion docs/docs/feature-library/contacts.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This feature adds a contacts directory to Flex. The contacts directory consists
- Personal contacts are contacts which are created by the worker, and are specific to that worker. The worker can add, modify, or delete any of their personal contacts.
- Shared contacts are contacts which are visible to all workers. By default, only workers with the admin or supervisor role can add, modify, or delete shared contacts. However, these can be optionally made editable for agents as well.

Contacts can be viewed, managed, and dialed using the contacts view added to Flex. In addition, a "Call Contact" section is added to the outbound dialer panel, allowing easy dialing of contacts from any view. Also, if the `custom-transfer-directory` feature is enabled, contacts are available in the transfer panel for cold or warm transfer.
Contacts can be viewed, managed, and dialed using the contacts view added to Flex. In addition, a "Call Contact" section is added to the outbound dialer panel, allowing easy dialing of contacts from any view. Also, if the `custom-transfer-directory` feature is enabled, contacts are available in the transfer panel for cold or warm transfer, and shared contacts can be configured to disable cold and/or warm transfer capability.

## User experience

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import { Template, templates } from '@twilio/flex-ui';
import { Button } from '@twilio-paste/core/button';
import { Input } from '@twilio-paste/core/input';
import { Switch } from '@twilio-paste/core/switch';
import { useUIDSeed } from '@twilio-paste/core/uid-library';
import { Modal, ModalBody, ModalFooter, ModalFooterActions, ModalHeader, ModalHeading } from '@twilio-paste/core/modal';
import { Label } from '@twilio-paste/core/label';
Expand All @@ -23,6 +24,8 @@ const ContactEditModal = ({ contact, isOpen, shared, handleClose }: Props) => {
const [name, setName] = useState(contact?.name ?? '');
const [phoneNumber, setPhoneNumber] = useState(contact?.phoneNumber ?? '');
const [notes, setNotes] = useState(contact?.notes ?? '');
const [allowColdTransfer, setAllowColdTransfer] = useState(contact?.allowColdTransfer ?? true);
const [allowWarmTransfer, setAllowWarmTransfer] = useState(contact?.allowWarmTransfer ?? true);
const [isSaving, setIsSaving] = useState(false);

const seed = useUIDSeed();
Expand All @@ -33,26 +36,34 @@ const ContactEditModal = ({ contact, isOpen, shared, handleClose }: Props) => {
setName('');
setPhoneNumber('');
setNotes('');
setAllowColdTransfer(true);
setAllowWarmTransfer(true);
}
}, [isOpen]);

useEffect(() => {
setName(contact?.name ?? '');
setPhoneNumber(contact?.phoneNumber ?? '');
setNotes(contact?.notes ?? '');
setAllowColdTransfer(contact?.allowColdTransfer ?? true);
setAllowWarmTransfer(contact?.allowWarmTransfer ?? true);
}, [contact]);

const save = async () => {
setIsSaving(true);
if (isNew) {
await ContactsUtil.addContact(name, phoneNumber, notes, shared);
await ContactsUtil.addContact(name, phoneNumber, notes, shared, allowColdTransfer, allowWarmTransfer);
} else if (contact) {
const newContact = {
...contact,
name,
phoneNumber,
notes,
};
if (shared) {
newContact.allowColdTransfer = allowColdTransfer;
newContact.allowWarmTransfer = allowWarmTransfer;
}
await ContactsUtil.updateContact(newContact, shared);
}
handleClose();
Expand Down Expand Up @@ -100,6 +111,30 @@ const ContactEditModal = ({ contact, isOpen, shared, handleClose }: Props) => {
</Label>
<TextArea id={seed('notes')} name="notes" value={notes} onChange={(e) => setNotes(e.target.value)} />
</FormControl>
{ContactsUtil.shouldShowTransferOptions(shared) && (
<>
<FormControl>
<Switch
checked={allowColdTransfer}
onChange={(e) => setAllowColdTransfer(e.target.checked)}
id={seed('allow-cold-transfer')}
name={'allow-cold-transfer'}
>
<Template source={templates[StringTemplates.AllowColdTransfer]} />
</Switch>
</FormControl>
<FormControl>
<Switch
checked={allowWarmTransfer}
onChange={(e) => setAllowWarmTransfer(e.target.checked)}
id={seed('allow-warm-transfer')}
name={'allow-warm-transfer'}
>
<Template source={templates[StringTemplates.AllowWarmTransfer]} />
</Switch>
</FormControl>
</>
)}
</Form>
</ModalBody>
<ModalFooter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export enum StringTemplates {
CurrentPage = 'PSContactCurrentPage',
NextPage = 'PSContactNextPage',
PreviousPage = 'PSContactPreviousPage',
AllowColdTransfer = 'PSContactAllowColdTransfer',
AllowWarmTransfer = 'PSContactAllowWarmTransfer',
}

export const stringHook = () => ({
Expand Down Expand Up @@ -85,6 +87,8 @@ export const stringHook = () => ({
[StringTemplates.CurrentPage]: 'Page {{current}} of {{total}}',
[StringTemplates.NextPage]: 'Next page',
[StringTemplates.PreviousPage]: 'Previous page',
[StringTemplates.AllowColdTransfer]: 'Allow cold transfers to this contact',
[StringTemplates.AllowWarmTransfer]: 'Allow warm transfers to this contact',
},
'es-MX': esMX,
'es-ES': esES,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ export interface Contact {
name: string;
notes: string;
phoneNumber: string;
allowColdTransfer?: boolean;
allowWarmTransfer?: boolean;
}

export interface HistoricalContact {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
isSharedDirectoryEnabled,
isSharedDirectoryAgentEditable,
} from '../config';
import { getUserLanguage } from '../../../utils/configuration';
import { getUserLanguage, getLoadedFeatures, getFeatureFlags } from '../../../utils/configuration';
import SyncClient, { getAllSyncMapItems } from '../../../utils/sdk-clients/sync/SyncClient';
import logger from '../../../utils/logger';

Expand Down Expand Up @@ -187,7 +187,14 @@ class ContactsUtil {
}
};

addContact = async (name: string, phoneNumber: string, notes: string, shared: boolean) => {
addContact = async (
name: string,
phoneNumber: string,
notes: string,
shared: boolean,
allowColdTransfer?: boolean,
allowWarmTransfer?: boolean,
) => {
if (!this.workerSid && !shared) {
logger.error('[contacts] Error adding contact: No worker sid');
return;
Expand All @@ -197,12 +204,16 @@ class ContactsUtil {
return;
}
try {
const contact = {
const contact: Contact = {
key: uuidv4(),
name,
phoneNumber,
notes,
};
if (shared) {
contact.allowColdTransfer = allowColdTransfer ?? true;
contact.allowWarmTransfer = allowWarmTransfer ?? true;
}
const map = await SyncClient.map(`${CONTACTS_KEY}_${shared ? this.accountSid : this.workerSid}`);
await map.set(contact.key, contact);
} catch (error: any) {
Expand Down Expand Up @@ -243,6 +254,11 @@ class ContactsUtil {
logger.error('[contacts] Error updating contact', error);
}
};

shouldShowTransferOptions = (shared: boolean) =>
shared &&
getLoadedFeatures().includes('custom-transfer-directory') &&
(getFeatureFlags()?.features?.custom_transfer_directory?.external_directory?.enabled || false);
}

const contactsUtil = new ContactsUtil();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,20 @@ const ExternalDirectoryTab = (props: OwnProps) => {
// Map the contacts directory entries to a DirectoryEntry array
const generateContactsEntries = (shared: boolean): Array<DirectoryEntry> => {
return (
(shared ? sharedContactList : myContactList)?.map(
(entry: any) =>
({
cold_transfer_enabled: true,
warm_transfer_enabled: isVoiceXWTEnabled(),
label: entry.name,
address: entry.phoneNumber,
tooltip: entry.phoneNumber,
type: 'number',
key: uuidv4(),
} as DirectoryEntry),
) ?? [] // Return an empty array if the contacts feature is disabled
(shared ? sharedContactList : myContactList)
?.map(
(entry: any) =>
({
cold_transfer_enabled: shared ? entry.allowColdTransfer ?? true : true,
warm_transfer_enabled: isVoiceXWTEnabled() && shared ? entry.allowWarmTransfer ?? true : true,
label: entry.name,
address: entry.phoneNumber,
tooltip: entry.phoneNumber,
type: 'number',
key: uuidv4(),
} as DirectoryEntry),
)
?.filter((entry: DirectoryEntry) => entry.cold_transfer_enabled || entry.warm_transfer_enabled) ?? [] // Return an empty array if the contacts feature is disabled
);
};

Expand Down

0 comments on commit dea22c2

Please sign in to comment.