Twilio Flex UI: How do I wrap TaskListItem with another component so that I can revise firstLine and secondLine?

102 views Asked by At

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;
}
0

There are 0 answers