In Twilio Flex UI, when receiving a phone call or SMS, my goal is to leave the TaskListItem design the same, yet update the firstLine
and secondLine
props with updated custom async content for the incoming task.
At first, I was thinking I could update manager.strings
with the information I needed, yet that updates for ALL tasks at once so that won't work. I could also append extra info at the bottom of a TaskListItem
without disturbing default Flex UI functionality, yet my project requirements prefer text updates in the firstLine
and secondLine
in the TaskListItem
itself. I could also rewrite the full TaskListItem
component to replace, yet that's duplicate work that might not be needed.
Now I'm working to just wrap the TaskListItem
component and pass through the props. Eventually, I'll customize the firstLine
and secondLine
props with an async update, yet I'm struggling to get the basic wrapper to work. I don't get any errors, yet when I set my UI status to available for the tasks to show (one SMS message for now), I get these console logs followed by a freeze and Flex crash (IDs anatomized):
[2023-11-06T17:23:56.541Z] Worker %s received Event: worker.activity.update. Proceeding to update ... WK00000000000000000000000000000000
twilio-flex.unbundled-react.min.js:679 [2023-11-06T17:23:56.607Z] Worker %s received Event: reservation.created. WK00000000000000000000000000000000
twilio-flex.unbundled-react.min.js:679 [2023-11-06T17:23:56.607Z] Attempting to create and insert Reservation into Worker %s reservations map. WK00000000000000000000000000000000
//... then it crashes after a while
Here's the plugin code I'm testing:
import React, { useEffect } from 'react';
import * as Flex from '@twilio/flex-ui';
import { FlexPlugin } from '@twilio/flex-plugin';
import { TaskListItem, TaskListItemProps } from '@twilio/flex-ui';
const PLUGIN_NAME = 'MyPlugin';
export default class MyPlugin extends FlexPlugin {
constructor() {
super(PLUGIN_NAME);
}
async init(flex: typeof Flex, manager: Flex.Manager): Promise<void> {
const MyTaskListItemWrapper = (
props: TaskListItemProps
): JSX.Element | null => {
useEffect(() => {
console.log('this will get called once on first render, yet does not when attempting to pass through TaskListItem');
// I'm going to async update the `firstLine` and `secondLine` TaskListItem eventually after an extra API call, leaving all else the same.
}, []);
return <TaskListItem {...props} />;
/*
return (
<div>
I can return this, yet returning TaskListItem results in a
Flex UI crash.
</div>
);
*/
};
flex.TaskListItem.Content.replace(
<MyTaskListItemWrapper key="MyTaskListItemWrapper" />
);
}
}
If I log props, I'm not seeing much data there. Perhaps I need to wrap in withTaskContext
and/or something else with UI API. I'm sure I'm missing something. Any ideas on how to proceed?
UPDATE: This also fails with the same crash after learing about addWrapper():
Flex.TaskListItem.Content.addWrapper(
(OriginalComponent) => (originalProps) => {
const updatedProps = {
...originalProps,
firstLine: 'Custom First Line',
secondLine: 'Custom Second Line',
};
const CustomBanner = () => <div>Customer Banner</div>;
return (
<>
<CustomBanner />
<OriginalComponent {...updatedProps} />
</>
);
}
);
However, I'm also noticing since I'm working in TypeScript that Flex.TaskListItem.Content.addWrapper
expects ComponentWrapper<TaskListItemChildrenProps>
, which different than TaskListItemProps
. Perhaps I need to wrap its children here instead of the component itself? I'll race you to an answer.
UPDATE: I have been able to wrap other similarly listed components without issue. For example:
flex.IncomingTaskCanvas.Content.addWrapper(
(OriginalComponent) => (originalProps) => {
const updatedProps = {
...originalProps,
secondLine: 'Custom Second Line',
};
return <OriginalComponent {...updatedProps} />;
}
);
Is it possible that there's an issue with TaskListItem
or am I missing something?
UPDATE: It looks like TaskListItem props are mostly read only. I may have to find an alternate solution unless I'm misunderstanding. I'm still open to thoughts.
export interface TaskListItemProps {
readonly visible?: boolean;
readonly selected?: boolean;
readonly selectedTaskSid?: string;
readonly onSelected?: (taskSid: string) => void;
readonly icon?: string | React.ReactNode;
readonly iconColor?: string;
readonly actions?: Array<React.ReactElement<any>>;
readonly firstLine?: React.ReactNode;
readonly secondLine?: React.ReactNode;
readonly extraInfo?: React.ReactNode;
readonly large?: boolean;
readonly itemSize?: TaskListItemSize;
}