Created
April 5, 2020 05:27
-
-
Save chase2981/5e3208e46ca747701eeb0219551823a9 to your computer and use it in GitHub Desktop.
Twilio Flex MessagingCanvas Examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from "react"; | |
import { | |
Manager, Actions, MessagingCanvas, MessagingCanvasContext, DynamicComponent, ContextProvider, MessageList, StateHelper, TaskHelper, ITask, | |
Supervisor, | |
TaskChannelDefinition, | |
TaskContextProps, | |
Theme | |
} from '@twilio/flex-ui'; | |
import CoreApiService from '../Shared/CoreApiService'; | |
import { Channel } from 'twilio-chat/lib/channel'; | |
import { createChatTaskChannel } from '@twilio/flex-ui/src/task_channels'; | |
import { SupervisorState } from '@twilio/flex-ui/src/state/SupervisorState'; | |
import { SessionState } from '@twilio/flex-ui/src/state/SessionState'; | |
interface Props extends TaskContextProps { | |
key: string; | |
channelDefinition?: TaskChannelDefinition; | |
// channels: Channel[]; | |
session: SessionState; | |
supervisor: SupervisorState; | |
task?: ITask; | |
theme?: Theme; | |
} | |
interface State { | |
callSid?: string; | |
channelSid?: string; | |
channel?: Channel; | |
task?: ITask; | |
} | |
export default class SupervisorTaskCanvasComponent extends React.Component<Props, State> { | |
coreApiSvc: CoreApiService; | |
channelSid: string; | |
myChannel: Channel; | |
task?: ITask; | |
constructor(public props: Props) { | |
super(props); | |
this.coreApiSvc = new CoreApiService(); | |
} | |
componentDidMount() { | |
if (this.props && this.props.task) { | |
this.handleTaskChange(this.props.task); | |
} | |
} | |
componentDidUpdate(prevProps: Props, prevState: State) { | |
if (this.props && this.props.task && (!prevProps || !prevProps.task)) { | |
return this.handleTaskChange(this.props.task); | |
} | |
else if (prevProps && prevProps.task && this.props && this.props.task && prevProps.task.sid != this.props.task.sid) { | |
return this.handleTaskChange(this.props.task); | |
} | |
} | |
isMessageTask(task: ITask) { | |
return task.taskChannelUniqueName.includes('chat'); | |
} | |
isVoiceTask(task: ITask) { | |
return task.taskChannelUniqueName.includes('voice'); | |
} | |
handleVoiceTask(task: ITask) { | |
let voiceClient = Manager.getInstance().voiceClient; | |
this.channelSid = task.attributes.channelSid; | |
this.setState({ callSid: task.attributes.call_sid }); | |
} | |
handleMessageTask(task: ITask) { | |
let chatClient = Manager.getInstance().chatClient; | |
this.channelSid = task.attributes.channelSid; | |
this.setState({ channelSid: task.attributes.channelSid }); | |
chatClient.getChannelBySid(task.attributes.channelSid).then((channel: any) => { | |
// if (this.myChannel) { | |
// this.myChannel.removeMember(this.props.session.identity); | |
// } | |
this.myChannel = channel; | |
this.myChannel.getMembers().then((channelMembers) => { | |
if (!channelMembers.some(cm => cm.identity === this.props.session.identity)) { | |
// simply join the channel if not already joined, and everything else will just work, so long as the user has permissions to join | |
this.myChannel.join().then((r) => { | |
// var channelState = StateHelper.getChatChannelStateForTask(payload.task); | |
// var channelSid = TaskHelper.getTaskChatChannelSid(payload.task); | |
}) | |
} | |
this.setState({ channel: this.myChannel }, () => { | |
/* after state updated callback */ | |
}) | |
}); | |
}, (err) => { | |
console.warn(err); | |
}) | |
} | |
handleTaskChange(task) { | |
this.setState({ task: task }); | |
if (this.isMessageTask(task)) { | |
this.handleMessageTask(task); | |
} | |
if (this.isVoiceTask(task)) { | |
this.handleVoiceTask(task); | |
} | |
} | |
render() { | |
if (!this.state) { | |
return null; | |
} | |
return <MessagingCanvas autoInitChannel={true} sid={this.channelSid} key='demo-supervisor-task-canvas-messaging-canvas' showWelcomeMessage={false}></MessagingCanvas> | |
} | |
componentWillUnmount() { | |
// if (this.myChannel) { | |
// this.myChannel.removeMember(this.props.session.identity); | |
// } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { connect } from 'react-redux'; | |
import { FlexState, Manager, withTaskContext } from '@twilio/flex-ui'; | |
import { RdFlexState } from 'core/rdFlexState'; | |
import SupervisorTaskCanvasComponent from './SupervisorTaskCanvasComponent'; | |
const mapStateToProps = (state: RdFlexState & FlexState, ownProps: any): any => { | |
if (!state || !state.flex || !state.rd) | |
return {}; | |
return { | |
supervisor: state.flex.supervisor, | |
session: state.flex.session, | |
config: state.flex.config, | |
channels: state.flex.chat.channels | |
} | |
} | |
const mapDispatchToProps = { | |
// updateDisplay: updateDisplay, | |
// updateLeadCardForm: updateLeadCardForm, | |
// updateResidentCardForm: updateResidentCardForm, | |
} | |
export default connect( | |
mapStateToProps, | |
mapDispatchToProps | |
)(SupervisorTaskCanvasComponent); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { FlexPlugin } from "flex-plugin"; | |
import * as React from "react"; | |
// import RootContainer from "./RootContainer"; | |
import * as Flex from "@twilio/flex-ui"; | |
import { Manager, MessagingCanvas, Actions, SideLink, View } from '@twilio/flex-ui'; | |
import SupervisorTaskCanvasContainer from './SupervisorTaskCanvasContainer'; | |
import './SupervisorTaskCanvasComponent.scss'; | |
interface Props { | |
key: string; | |
} | |
interface State { | |
channelSid?: string; | |
} | |
export default class SupervisorTaskCanvasFlexPlugin extends FlexPlugin { | |
state: State; | |
constructor(public props: Readonly<Props> = { key: 'SupervisorTaskCanvasFlexPlugin' }) { | |
super(props.key); | |
} | |
init(flex: typeof Flex, manager: Manager) { | |
flex.Supervisor.TaskOverviewCanvas.Content.add( | |
<SupervisorTaskCanvasContainer key='rd-supervisor-task-overview-canvas-supervisor-task-canvas-container'></SupervisorTaskCanvasContainer>, | |
{ | |
// align: 'start', | |
// if: props => props.task.source.taskChannelUniqueName === "chat", | |
sortOrder: 1 | |
} | |
) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from "react"; | |
import { | |
Manager, | |
Actions, | |
MessagingCanvas, | |
MessagingCanvasContext, | |
DynamicComponent, | |
ContextProvider, | |
MessageList, | |
StateHelper, | |
TaskHelper, | |
ITask, | |
Supervisor, | |
TaskChannelDefinition, | |
Theme, | |
ThemeProvider, | |
Config, | |
MessageListItem | |
} from "@twilio/flex-ui"; | |
import CoreApiService from "../../../Shared/CoreApiService"; | |
import { Channel } from "twilio-chat/lib/channel"; | |
import { SessionState } from '@twilio/flex-ui/src/state/SessionState'; | |
interface Props { | |
channelSid?: string; | |
key: string; | |
session: SessionState; | |
taskChange?: Function; | |
theme: Theme; | |
} | |
interface State { | |
callSid?: string; | |
channel?: any; | |
channelSid?: string; | |
} | |
export default class TaskDetailMessagingCanvasComponent extends React.Component<Props, State> { | |
coreApiSvc: CoreApiService; | |
channelSid: string; | |
messagingCanvasRef: any; | |
myChannel: Channel; | |
task?: ITask; | |
static getDerivedStateFromProps(nextProps: Readonly<Props>, prevState: State) { | |
return { | |
...prevState, | |
...{ | |
channelSid: nextProps.channelSid | |
} | |
} | |
} | |
constructor(public props: Props) { | |
super(props); | |
this.coreApiSvc = new CoreApiService(); | |
this.messagingCanvasRef = React.createRef(); | |
this.state = { | |
} | |
} | |
componentDidMount() { | |
if (this.props.channelSid) { | |
this.handleMessageTask(this.props.channelSid); | |
} | |
} | |
componentDidUpdate(prevProps: Props, prevState: State) { | |
if (this.props.channelSid && this.props.channelSid !== prevProps.channelSid) { | |
this.handleMessageTask(this.props.channelSid); | |
} | |
} | |
isMessageTask(task: ITask) { | |
return task.taskChannelUniqueName.includes('chat'); | |
} | |
isVoiceTask(task: ITask) { | |
return task.taskChannelUniqueName.includes('voice'); | |
} | |
handleVoiceTask(task: ITask) { | |
let voiceClient = Manager.getInstance().voiceClient; | |
this.channelSid = task.attributes.channelSid; | |
this.setState({ callSid: task.attributes.call_sid }); | |
} | |
handleMessageTask(channelSid) { | |
let chatClient = Manager.getInstance().chatClient; | |
this.channelSid = channelSid; | |
this.setState({ channelSid: channelSid }); | |
} | |
async update(newVal: any) { | |
return new Promise((resolve, reject) => { | |
this.setState(newVal, () => { | |
resolve(this.state); | |
}); | |
}); | |
} | |
render() { | |
const colors = this.props.theme.colors; | |
const palette: any = this.props.theme.palette; | |
const notFoundDetailTemplate = ( | |
<div style={{ | |
fontSize: '90px', textAlign: 'center', width: '100%', | |
margin: '25% 25%' | |
}}> | |
<svg version="1.1" viewBox="0 0 64 64" height="64" width="64"><g transform="matrix(2.6666666666666665,0,0,2.6666666666666665,0,0)"><path d="M 23.25,13.5c0.001-2.899-2.349-5.249-5.248-5.25c-0.001,0-0.001,0-0.002,0h-3c-2.899,0-5.25,2.351-5.25,5.25 s2.351,5.25,5.25,5.25h0.75l4.5,4.5v-5.024C22.079,17.362,23.246,15.522,23.25,13.5z " stroke="#707070" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M 6.75,12.75l-3,3v-5.024 C1.134,9.49,0.015,6.367,1.251,3.751C2.118,1.915,3.969,0.745,6,0.75h3c2.322,0,4.369,1.525,5.033,3.75" stroke="#707070" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg> | |
</div> | |
); | |
return ( | |
!this.state || !this.state.channelSid ? ( | |
<div style={{ height: '90%', display: 'flex' }}> | |
{notFoundDetailTemplate} | |
</div> | |
) : ( | |
<div className='task__details_cont' style={{ height: '90%' }}> | |
{this.state && this.state.channelSid ? ( | |
<React.Fragment> | |
<MessagingCanvas autoInitChannel={true} sid={this.state.channelSid} key='rd-task-lookup-view-messaging-canvas' ref={this.messagingCanvasRef} showWelcomeMessage={false}></MessagingCanvas> | |
</React.Fragment> | |
) : null} | |
</div> | |
) | |
); | |
} | |
componentWillUnmount() { | |
if (this.myChannel) { | |
this.myChannel.removeMember(this.props.session.identity); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { connect } from 'react-redux'; | |
import { FlexState, Manager, withTheme } from '@twilio/flex-ui'; | |
import { RdFlexState } from 'core/rdFlexState'; | |
import TaskDetailMessagingCanvasComponent from './TaskDetailMessagingCanvasComponent'; | |
const mapStateToProps = (state: RdFlexState & FlexState, ownProps: any) => { | |
if (!state || !state.flex || !state.rd) | |
return {}; | |
return { | |
supervisor: state.flex.supervisor, | |
session: state.flex.session, | |
config: state.flex.config, | |
channels: state.flex.chat.channels | |
} | |
} | |
const mapDispatchToProps = { | |
} | |
export default | |
withTheme( | |
connect( | |
mapStateToProps, | |
mapDispatchToProps | |
)(TaskDetailMessagingCanvasComponent as any) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
v2
here's the easier way to invoke the messaging-canvas in your flex apps, as of ~2021..
you no longer have to manually join the channel yourself and do all that jazz, you still need the supervisor programmable chat role setup on your user to auto-join the channels however..
TaskDetailCanvas.tsx
import * as React from "react"; import { Manager, Actions, MessagingCanvas, MessagingCanvasContext, DynamicComponent, ContextProvider, MessageList, StateHelper, TaskHelper, ITask, Supervisor, TaskChannelDefinition, Theme, ThemeProvider, Config, MessageListItem } from "@twilio/flex-ui"; import CoreApiService from "../../../Shared/CoreApiService"; import { Channel } from "twilio-chat/lib/channel"; import { SessionState } from '@twilio/flex-ui/src/state/SessionState'; interface Props { channelSid?: string; key: string; session: SessionState; taskChange?: Function; theme: Theme; } interface State { callSid?: string; channel?: any; channelSid?: string; } export class TaskDetailCanvasComponent extends React.Component<Props, State> { coreApiSvc: CoreApiService; channelSid: string; messagingCanvasRef: any; myChannel: Channel; task?: ITask; static getDerivedStateFromProps(nextProps: Readonly<Props>, prevState: State) { return { ...prevState, ...{ channelSid: nextProps.channelSid } } } constructor(public props: Props) { super(props); this.coreApiSvc = new CoreApiService(); this.messagingCanvasRef = React.createRef(); this.state = { } } componentDidMount() { if (this.props.channelSid) { this.handleMessageTask(this.props.channelSid); } } componentDidUpdate(prevProps: Props, prevState: State) { if (this.props.channelSid && this.props.channelSid !== prevProps.channelSid) { this.handleMessageTask(this.props.channelSid); } } isMessageTask(task: ITask) { return task.taskChannelUniqueName.includes('chat'); } isVoiceTask(task: ITask) { return task.taskChannelUniqueName.includes('voice'); } handleVoiceTask(task: ITask) { let voiceClient = Manager.getInstance().voiceClient; this.channelSid = task.attributes.channelSid; this.setState({ callSid: task.attributes.call_sid }); } handleMessageTask(channelSid) { let chatClient = Manager.getInstance().chatClient; this.channelSid = channelSid; this.setState({ channelSid: channelSid }); } async update(newVal: any) { return new Promise((resolve, reject) => { this.setState(newVal, () => { resolve(this.state); }); }); } render() { const colors = this.props.theme.colors; const palette: any = this.props.theme.palette; const notFoundDetailTemplate = ( <div style={{ fontSize: '90px', textAlign: 'center', width: '100%', margin: '25% 25%' }}> <svg version="1.1" viewBox="0 0 64 64" height="64" width="64"><g transform="matrix(2.6666666666666665,0,0,2.6666666666666665,0,0)"><path d="M 23.25,13.5c0.001-2.899-2.349-5.249-5.248-5.25c-0.001,0-0.001,0-0.002,0h-3c-2.899,0-5.25,2.351-5.25,5.25 s2.351,5.25,5.25,5.25h0.75l4.5,4.5v-5.024C22.079,17.362,23.246,15.522,23.25,13.5z " stroke="#707070" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M 6.75,12.75l-3,3v-5.024 C1.134,9.49,0.015,6.367,1.251,3.751C2.118,1.915,3.969,0.745,6,0.75h3c2.322,0,4.369,1.525,5.033,3.75" stroke="#707070" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></g></svg> </div> ); return ( !this.state || !this.state.channelSid ? ( <div style={{ height: '90%', display: 'flex' }}> {notFoundDetailTemplate} </div> ) : ( <div className='task__details_cont' style={{ height: '90%' }}> {this.state && this.state.channelSid ? ( <React.Fragment> + <MessagingCanvas autoInitChannel={true} sid={this.state.channelSid} key='rd-task-lookup-view-messaging-canvas' ref={this.messagingCanvasRef} showWelcomeMessage={false}></MessagingCanvas> </React.Fragment> ) : null} </div> ) ); } componentWillUnmount() { if (this.myChannel) { this.myChannel.removeMember(this.props.session.identity); } } }