twiliotwilio-apitwilio-flex

Update task attributes in flex for assigned task


I am updating a task property through a request to my backend for an assigned task, this request is made on a custom component, on a button click during the call.

I can see in my twilio console that the update went fine and the new value is shown there, but the task prop on my flex components are not being updated, maintaining the same attributes since the assignment.

Is there a way to "refresh" the task in flex? I would need this updated attribute in order to perform a conditional rendering on my custom component.

Thanks in advance to anyone that helps me out.

import React from 'react';
import { withTaskContext } from '@twilio/flex-ui';

class IsRecording extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        // this.task = this.props.tasks
            return (
                <div>
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#E50000">
                        <path
                            d="M16 16c0 1.104-.896 2-2 2h-12c-1.104 0-2-.896-2-2v-8c0-1.104.896-2 2-2h12c1.104 0 2 .896 2 2v8zm8-10l-6 4.223v3.554l6 4.223v-12z"/>
                        <animate
                            attributeType="XML"
                            attributeName="fill"
                            values="#800;#f00;#800;#800"
                            dur="1.5s"
                            repeatCount="indefinite"/>
                    </svg>
                </div>
            )
    }
};

export default withTaskContext(IsRecording);

Solution

  • Twilio developer evangelist here.

    If you have access to the task object within Flex you do not need to do so via the back-end. Instead, you can call on task.setAttributes and that will update the task attributes directly and cause it to update the state everywhere within Flex.

    However, the difficulty here is that a supervisor will not have a live view on tasks, so you need to do a little more work to have the supervisor listen for changes on the tasks. I had a play around and got this working. It uses the Sync liveQuery interface to subscribe to updates to workers' tasks.

    We create the live query subscription on componentDidMount. The first argument when creating the live query is "tr-task" and this refers to all tasks in the system. The second argument is the query, in this case we are querying for all tasks for this worker.

    Once we get the query we can load the current items and set them in the state. We then listen for additions, updates and removals and update the state accordingly.

    In the render function we calculate whether any of the tasks have an isRecording attribute and display the icon accordingly.

    Here's the <IsRecording> component:

    import React from "react";
    import { Manager } from "@twilio/flex-ui";
    
    class IsRecording extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          tasks: [],
        };
      }
    
      componentDidMount() {
        Manager.getInstance()
          .insightsClient.liveQuery(
            "tr-task",
            `data.worker_sid == "${this.props.worker.sid}"`
          )
          .then((query) => {
            this.liveQuery = query;
            const items = query.getItems();
            this.setState({ tasks: Object.values(items) });
            query.on("itemAdded", (item) => {
              this.setState((prevState) => ({
                tasks: [...prevState.tasks, item.value],
              }));
            });
            query.on("itemUpdated", (item) => {
              this.setState((prevState) => ({
                tasks: [
                  ...prevState.tasks.filter((task) => task.sid !== item.value.sid),
                  item.value,
                ],
              }));
            });
            query.on("itemRemoved", (item) => {
              this.setState((prevState) => ({
                tasks: prevState.tasks.filter(
                  (task) => task.sid !== item.previousItemData.sid
                ),
              }));
            });
          })
          .catch((err) =>
            console.debug(`Error when subscribing to live updates for Tasks`, err)
          );
      }
    
      componentWillUnmount() {
        if (this.liveQuery) {
          this.liveQuery.removeAllListeners();
          this.liveQuery.close();
        }
      }
    
      render() {
        if (this.state.tasks.some((task) => task.attributes.isRecording)) {
          return (
            <div>
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#E50000">
                <path d="M16 16c0 1.104-.896 2-2 2h-12c-1.104 0-2-.896-2-2v-8c0-1.104.896-2 2-2h12c1.104 0 2 .896 2 2v8zm8-10l-6 4.223v3.554l6 4.223v-12z" />
                <animate attributeType="XML" attributeName="fill" values="#800;#f00;#800;#800" dur="1.5s" repeatCount="indefinite" />
              </svg>
            </div>
          );
        } else {
          return null;
        }
      }
    }
    
    export default IsRecording;
    

    You attach it to the WorkersDataTable like this:

        flex.WorkersDataTable.Content.add(
          <ColumnDefinition
            key="is-recording"
            header={"Recording"}
            content={(items) => {
              return (
                <IsRecording
                  key={`is-recording-${items.worker.sid}`}
                  worker={items.worker}
                />
              );
            }}
          />
        );