Flex is a multichannel contact center. We support a number of channels out-of-the-box, and are constantly adding more. As of version 1.0 we support the following native channels:
With the Task Channel Definition API you can also add custom channels and override the behavior of existing ones.
To add a custom channel, you need to make changes in the following places:
Add a custom channel in TaskRouter
Trigger the custom channel to be routed to the agent
Define how the custom channel is rendered in the UI with Task Channel Definition API
All task channels that Flex UI handles are defined and registered by the Task Channels API. Flex registers its default Task Channel definitions (see below), but users and plugins can register their own. When task-based components are rendered, the first matching channel definition for a given task will be used. If there is more than one channel definition match for a task, then the most recently registered definition will be used. This allows you to register a more specific channel definition to override the behavior of a general one.
See below interface TaskChannelDefinition
for what can be set up. All parameters are optional; the parameters from the Default
task channel definition will be used if not specified. The most important property of a task channel definition is the isApplicable
callback function. The callback receives a task as an argument and must return Boolean true
if this definition can be used to handle the given task.
In a task channel definition you can specify:
Predefined Task Channels definitions are available via Twilio.Flex.DefaultTaskChannels
objects for reference. Channels that are defined by default:
Call - Twilio.Flex.DefaultTaskChannels.Call
Chat - Twilio.Flex.DefaultTaskChannels.Chat
Chat SMS - Twilio.Flex.DefaultTaskChannels.ChatSms
Chat Messenger - Twilio.Flex.DefaultTaskChannels.ChatMessenger
Chat WhatsApp - Twilio.Flex.DefaultTaskChannels.ChatWhatsApp
Default - Twilio.Flex.DefaultTaskChannels.Default
It is not recommended to change Twilio.Flex.DefaultTaskChannels
at runtime. You should create your own definition and register it instead.
Predefined Task Channels definitions are available via Twilio.Flex.DefaultTaskChannels and they can be altered with custom logic when required.
The example below demonstrates how you can define your own custom icon for browser notification of an IncomingTask
with channel type Chat
1const originalChatNotifications = Flex.DefaultTaskChannels.Chat.notifications.override.IncomingTask;2Flex.DefaultTaskChannels.Chat.notifications.override.IncomingTask = {3...originalChatNotifications,4options: {5...originalChatNotifications.options,6browser: {7...originalChatNotifications.options.browser,8options: {9...originalChatNotifications.options.browser.options,10icon: “CUSTOM_ICON_URL”11}12}13}14};
The example below demonstrates how you can define your own custom icon for browser notification of an IncomingTask
with channel type Voice
1const overrides = Flex.DefaultTaskChannels.Call.notifications.override.IncomingTask;2Flex.DefaultTaskChannels.Call.notifications.override.IncomingTask = (notification, cancel) => {3overrides(notification, cancel);4notification.options.browser.options.icon = “CUSTOM_ICON_URL”;5};
Tasks can be rendered depending on which media type they support. We have helper functions to define custom channels that support the following media type:
Call - voice call based
Chat - messaging based like WebChat, SMS, Facebook Messenger, etc.
Generic - no media
Flex has the following helper functions to create channel definitions with default values for chat, call, and generic.
Chat channel creation with default chat templates:
1Flex.DefaultTaskChannels.createChatTaskChannel(name: string, isApplicable: TaskChannelApplicableCb,2icon: string | React.ReactNode = "Message", iconActive: string | React.ReactNode = "MessageBold", color: string = defaultChannelColors.chat): TaskChannelDefinition
Call channel creation with default templates:
Call channel definition uses callbacks to determine the icon and colors (based on call state and destination to render)
Flex.DefaultTaskChannels.createCallTaskChannel(name: string, isApplicable: TaskChannelApplicableCb): TaskChannelDefinition
Generic channel creation with default templates:
1Flex.DefaultTaskChannels.createDefaultTaskChannel(name: string, isApplicable: TaskChannelApplicableCb,2icon: string | React.ReactNode = "GenericTask", iconActive: string | React.ReactNode = "GenericTaskBold", color: string = defaultChannelColors.custom): TaskChannelDefinition
To register a task channel definition use:
Flex.TaskChannels.register(definition: TaskChannelDefinition, mergeWithDefaultChannel = true);
You must register your channel definitions before Flex finishes initializing.
For example:
1const myOwnChatChannel = Flex.DefaultTaskChannels.createChatTaskChannel("myChat",2(task) => task.taskChannelUniqueName === "chat" && task.attributes.somethingSpecial === "myCustom");3// can modify myOwnChatChannel here45Flex.TaskChannels.register(myOwnChatChannel);
Flex.TaskChannels.unregister(myOwnChatChannel);
- to unregister previously registered channel
Flex.TaskChannels.getRegistered();
- to get all registered task channels
Flex.TaskChannels.getForTask(task: ITask);
- to get a matching task channel definition for a task
1export enum TaskChannelCapability {2Info = "Info", // whether channel has info panel3Call = "Call", // whether channel has call canvas capabilities4Chat = "Chat", // whether channel has chat canvas capabilities5Video = "Video", // whether channel has video calling capabilities6Wrapup = "Wrapup" // whether channel needs to go to Wrapup state before can be completed7}89export type TaskCallbackType<T> = (10task: ITask,11componentType: React.ComponentType,12...args: Array<any>13) => T;14export type TaskStatusBasedTypeBase<T> = {15Reserved?: T;16Assigned?: T;17Wrapping?: T;18Completed?: T;19Canceled?: T;20Pending?: T;21};22export type TaskStatusBasedType<T = string> =23| T24| TaskCallbackType<T>25| TaskStatusBasedTypeBase<T>;26export type TaskChannelApplicableCb = (task: ITask) => boolean;2728export type TaskChannelComponentRegistration = {29target: keyof FlexComponents;30component: React.ReactChild;31options?: ContentFragmentProps;32};3334export type TaskChannelComponentRemoveRequest = {35target: keyof FlexComponents;36key: React.Key;37options?: RemoveComponentCallOptions;38};3940/**41* Defines a task channel42*43* @export44* @interface TaskChannelDefinition45*/46export interface TaskChannelDefinition {47// for internal usage, will be set to an array of callbacks to invoke to unregister custom components48_registrationCallbacks?: Array<Function>;4950name: string;5152/**53* Used in TaskList, TaskCard, Canvases54*/55colors?: {56main?: TaskStatusBasedType<string>;57};5859/**60* Returns whether this task channel is applicable for a given task.61* @param task task instance to evaluate the channel for62*/63isApplicable: TaskChannelApplicableCb;6465/**66* Icons to render to the task channel67*/68icons?: {69/**70* List icon to be used in TaskList and TaskCardList71*/72list?: TaskStatusBasedType<string | React.ReactNode>;73/**74* Icon to be used in Tab headers if tab is not selected75*/76main?: TaskStatusBasedType<string | React.ReactNode>;77/**78* Icon to be used in Tab headers if tab is selected and in Task Canvases as the main icon79*/80active?: TaskStatusBasedType<string | React.ReactNode>;81};8283/**84* Templates for components85*/86templates?: {87IncomingTaskCanvas?: {88firstLine?: TaskStatusBasedType<string>;89secondLine?: TaskStatusBasedType<string>;90};91CallCanvas?: {92firstLine?: TaskStatusBasedType<string>;93secondLine?: TaskStatusBasedType<string>;94};95TaskListItem?: {96firstLine?: TaskStatusBasedType<string>;97secondLine?: TaskStatusBasedType<string>;98extraInfo?: TaskStatusBasedType<string>;99};100TaskCanvasHeader?: {101title?: TaskStatusBasedType<string>;102endButton?: TaskStatusBasedType<string>;103};104TaskCard?: {105firstLine?: TaskStatusBasedType<string>;106secondLine?: TaskStatusBasedType<string>;107};108TaskInfoPanel?: {109content: TaskStatusBasedType<string>;110};111Supervisor?: {112TaskCanvasHeader?: {113title?: TaskStatusBasedType<string>;114endButton?: TaskStatusBasedType<string>;115};116TaskInfoPanel?: {117content: TaskStatusBasedType<string>;118};119TaskOverviewCanvas: {120firstLine?: TaskStatusBasedType<string>;121secondLine?: TaskStatusBasedType<string>;122};123};124};125126/**127* Set of capabilities, used to render Tabs128*/129capabilities: Set<TaskChannelCapability>;130131/**132* Character limit of a message.133*/134charLimit: number;135136/**137* Custom components to be added for this task channel. E.g. custom Tabs.138* Supports only components that have a static "Content" property139*/140addedComponents?: Array<TaskChannelComponentRegistration>;141142/**143* Custom components to be replaced for this task channel.144* Supports only components that have a static "Content" property145*/146replacedComponents?: Array<TaskChannelComponentRegistration>;147148/**149* Custom components to be removed for this task channel150*/151removedComponents?: Array<TaskChannelComponentRemoveRequest>;152153/**154* Custom component props to be passed in if we have a matching task channel.155* Works only for task based components.156*/157// componentProps?: {158// [K in keyof FlexComponents]?: any;159// };160}
Adding a Tab to custom channel
1MyCallChannel.addedComponents = [2{3target: "TaskCanvasTabs",4component: <MyTab5key="myTab"6icon={<img src="https://someimage.png" />}7iconActive={<img src="someimage.png" />}8/>9}10];
Replacing a component (e.g. TaskInfoPanel or MessagingCanvas)
1const MyComponent = <div key="X">My Call Task Info Panel</div>;2MyCallChannel.replacedComponents = [3{ component: MyComponent, target: "TaskInfoPanel" }4];
Replacing a component conditionally
1MyCallChannel.replacedComponents = [2{ component: MyComponent, target: "MessagingCanvas", options:3{ if: (props) => props.task.status === "wrapping" }4}5];
Change strings based on task types (e.g., for end task button in the header):
1myOwnChatChannel.templates.TaskCanvasHeader.endButton = {2Assigned: "End Task",3Reserved: undefined,4Wrapping: "Wrap up",5Completed: "Template1",6Canceled: "Template2",7Pending: "Template3"8};
Removing a component conditionally (e.g., remove action button from TaskListItem if task is in state "wrapping")
1Flex.DefaultTaskChannels.Call.removedComponents = [{2target: "TaskCanvasHeader",3key: "actions",4options: {5if: (props) => props.task.status === "wrapping"6}7}];