Skip to content

Commit

Permalink
chore(react): changes in webchat regarding move to botState model
Browse files Browse the repository at this point in the history
  • Loading branch information
vanbasten17 committed Oct 19, 2021
1 parent a295c73 commit f231f45
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 120 deletions.
6 changes: 4 additions & 2 deletions packages/botonic-react/src/experimental/dev-app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ export class DevApp extends WebchatApp {
enableAnimations={enableAnimations}
storage={storage}
storageKey={storageKey}
getString={(stringId, session) => this.bot.getString(stringId, session)}
setLocale={(locale, session) => this.bot.setLocale(locale, session)}
getString={(stringId, botState) =>
this.bot.getString(stringId, botState)
}
setLocale={(locale, botState) => this.bot.setLocale(locale, botState)}
onInit={(...args) => this.onInitWebchat(...args)}
onOpen={(...args) => this.onOpenWebchat(...args)}
onClose={(...args) => this.onCloseWebchat(...args)}
Expand Down
29 changes: 16 additions & 13 deletions packages/botonic-react/src/experimental/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ class WebsocketBackendService {
// On Event Received...
this.wsClient.addEventListener('message', event => {
console.log(event, this.onEvent)
const message = JSON.parse(decode(event.data))
const eventData = JSON.parse(decode(event.data))
if (this.onEvent && typeof this.onEvent === 'function')
this.onEvent({ message })
this.onEvent(eventData)
})
}
async doAuthAndUpdateJwt() {
Expand Down Expand Up @@ -72,7 +72,7 @@ class WebsocketBackendService {
`${REST_API_URL}events/`,
{
message,
sender: user,
sender: user, // TODO: Really needed or we should pass user information through JWT?
},
{ headers: { Authorization: 'Bearer ' + this.jwt } } // Note: Do not use string template as it will convert the token with commas, which will be invalid
)
Expand All @@ -85,22 +85,22 @@ class WebsocketBackendService {
if (hasErrors) {
// TODO: Handle rest of errors
await this.doAuthAndUpdateJwt()
await this.postMessage(user, message)
// await this.postMessage(user, message) // Temporary, avoid infinite events loop
}
}
}

export class FullstackProdApp extends WebchatApp {
async onUserInput({ user, input }) {
this.onMessage && this.onMessage(this, { from: 'user', message: input })
async onUserInput({ user, input, session, botState }) {
this.onMessage && this.onMessage(this, { from: input.from, message: input })
this.backendService.postMessage(user, input)
}

async doAuth({ userId }) {
return await this.backendService.doAuth({ userId })
}

onStateChange({ session: { user }, messagesJSON, jwt, updateJwt }) {
onStateChange({ user, messagesJSON, jwt, updateJwt }) {
if (!this.backendService && user) {
const lastMessage = messagesJSON[messagesJSON.length - 1]
this.backendService = new WebsocketBackendService({
Expand All @@ -121,8 +121,8 @@ export class FullstackDevApp extends DevApp {
console.log('FullstackDevApp ', args.playgroundCode)
}

async onUserInput({ user, input }) {
this.onMessage && this.onMessage(this, { from: 'user', message: input })
async onUserInput({ user, input, session, botState }) {
this.onMessage && this.onMessage(this, { from: input.from, message: input })
this.backendService && this.backendService.postMessage(user, input)
}

Expand Down Expand Up @@ -176,8 +176,10 @@ export class FullstackDevApp extends DevApp {
storageKey={storageKey}
playgroundCode={this.playgroundCode}
onStateChange={webchatState => this.onStateChange(webchatState)}
getString={(stringId, session) => this.bot.getString(stringId, session)}
setLocale={(locale, session) => this.bot.setLocale(locale, session)}
getString={(stringId, botState) =>
this.bot.getString(stringId, botState)
}
setLocale={(locale, botState) => this.bot.setLocale(locale, botState)}
onInit={(...args) => this.onInitWebchat(...args)}
onOpen={(...args) => this.onOpenWebchat(...args)}
onClose={(...args) => this.onCloseWebchat(...args)}
Expand All @@ -191,7 +193,7 @@ export class FullstackDevApp extends DevApp {
return await this.backendService.doAuth({ userId })
}

onStateChange({ session: { user }, messagesJSON, jwt, updateJwt }) {
onStateChange({ user, messagesJSON, jwt, updateJwt }) {
if (!this.backendService && user) {
const lastMessage = messagesJSON[messagesJSON.length - 1]
this.backendService = new WebsocketBackendService({
Expand Down Expand Up @@ -257,6 +259,7 @@ export class BrowserProdApp extends WebchatApp {
...botOptions,
})
}
// TODO: Review how this be done for only browser versions
async onUserInput({ input, session, lastRoutePath }) {
this.onMessage && this.onMessage(this, { from: 'user', message: input })
const resp = await this.bot.input({ input, session, lastRoutePath })
Expand All @@ -277,10 +280,10 @@ export { ShareButton } from '../components/share-button'
export { Subtitle } from '../components/subtitle'
export { Title } from '../components/title'
export { WebchatSettings } from '../components/webchat-settings'
export { RequestContext, WebchatContext } from '../contexts'
export { staticAsset } from '../util/environment'
export { getBotonicApp } from '../webchat'
export { WebviewApp } from '../webview'
export { RequestContext, WebchatContext } from './contexts'
// Experimental
export { Audio } from './components/audio'
export { Carousel } from './components/carousel'
Expand Down
13 changes: 7 additions & 6 deletions packages/botonic-react/src/experimental/util/webchat.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { PROVIDER } from '@botonic/core'
import merge from 'lodash.merge'
import UAParser from 'ua-parser-js'
import { v4 as uuidv4 } from 'uuid'
Expand Down Expand Up @@ -34,14 +35,14 @@ export const createUser = () => {
return {
id: uuidv4(),
name,
channel: PROVIDER.DEV,
}
}
export const initSession = session => {
if (!session) session = {}
const hasUserId = session.user && session.user.id !== undefined
if (!session.user || Object.keys(session.user).length === 0 || !hasUserId)
session.user = !hasUserId ? merge(session.user, createUser()) : createUser()
return session

export const initUser = user => {
if (!user) return createUser()
if (user && !user.id) return merge(user, createUser())
return user
}

export const shouldKeepSessionOnReload = ({
Expand Down
41 changes: 27 additions & 14 deletions packages/botonic-react/src/experimental/webchat-app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,29 +139,42 @@ export class WebchatApp {
}

onServiceEvent(event) {
if (event.action === 'connectionChange')
const { action, ...eventData } = event
if (action === 'connectionChange')
this.webchatRef.current.setOnline(event.online)
// TODO: Temporary solution, decide how we will send these events in next iterations
else if (event.message.action === 'update_message_info') {
const { message } = event.message
this.updateMessageInfo(message.id, message)
} else if (event.action === 'update_message_info')
this.updateMessageInfo(event.message.id, event.message)
else if (event.message.type === 'update_webchat_settings')
this.updateWebchatSettings(event.message.data)
else if (event.message.type === 'sender_action')
this.setTyping(event.message.data === 'typing_on')
else {
else if (action === 'update_message_info') {
this.updateMessageInfo(eventData.id, eventData)
} else if (action === 'update_user') {
this.updateUser(eventData)
} else if (action === 'update_session') {
this.updateSession(eventData)
} else if (action === 'update_bot_state') {
this.updateBotState(eventData)
}
// TODO: Discuss how this updates to be done
else if (eventData.type === 'update_webchat_settings')
this.updateWebchatSettings(event.data)
else if (eventData.type === 'sender_action')
this.setTyping(event.data === 'typing_on')
else if (eventData.eventType === 'message') {
this.onMessage &&
this.onMessage(this, { from: SENDERS.bot, message: event.message })
this.addBotMessage(event.message)
this.onMessage(this, { from: SENDERS.bot, message: eventData })
this.addBotMessage(eventData)
}
}

updateUser(user) {
this.webchatRef.current.updateUser(user)
}

updateSession(session) {
this.webchatRef.current.updateSession(session)
}

updateBotState(botState) {
this.webchatRef.current.updateBotState(botState)
}

addBotMessage(message) {
this.webchatRef.current.addBotResponse({
response: msgToBotonic(
Expand Down
2 changes: 2 additions & 0 deletions packages/botonic-react/src/experimental/webchat/actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ export const UPDATE_LAST_MESSAGE_DATE = 'updateLastMessageDate'
export const SET_CURRENT_ATTACHMENT = 'setCurrentAttachment'
export const SET_ONLINE = 'setOnline'
export const UPDATE_JWT = 'updateJwt'
export const UPDATE_USER = 'updateUser'
export const UPDATE_BOT_STATE = 'updateBotState'
51 changes: 45 additions & 6 deletions packages/botonic-react/src/experimental/webchat/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
TOGGLE_EMOJI_PICKER,
TOGGLE_PERSISTENT_MENU,
TOGGLE_WEBCHAT,
UPDATE_BOT_STATE,
UPDATE_DEV_SETTINGS,
UPDATE_HANDOFF,
UPDATE_JWT,
Expand All @@ -24,10 +25,32 @@ import {
UPDATE_SESSION,
UPDATE_THEME,
UPDATE_TYPING,
UPDATE_USER,
UPDATE_WEBVIEW,
} from './actions'
import { webchatReducer } from './webchat-reducer'

export const initialUser = {
id: undefined,
name: undefined,
userName: undefined,
channel: undefined,
idFromChannel: undefined,
isOnline: true,
}

const initialBotState = {
botId: undefined,
lastRoutePath: null,
isFirstInteraction: true,
retries: 0,
locale: undefined,
isHandoff: false,
isShadowing: false,
}

const initialSession = {}

export const webchatInitialState = {
width: WEBCHAT.DEFAULTS.WIDTH,
height: WEBCHAT.DEFAULTS.HEIGHT,
Expand All @@ -38,9 +61,9 @@ export const webchatInitialState = {
typing: false,
webview: null,
webviewParams: null,
session: { user: null },
lastRoutePath: null,
handoff: false,
// session: { user: null },
// lastRoutePath: null,
// handoff: false,
theme: {
headerTitle: WEBCHAT.DEFAULTS.TITLE,
brandColor: COLORS.BOTONIC_BLUE,
Expand All @@ -53,7 +76,7 @@ export const webchatInitialState = {
},
themeUpdates: {},
error: {},
online: true,
isWebchatOnline: true,
devSettings: { keepSessionOnReload: false },
isWebchatOpen: false,
isEmojiPickerOpen: false,
Expand All @@ -62,6 +85,9 @@ export const webchatInitialState = {
lastMessageUpdate: undefined,
currentAttachment: undefined,
jwt: null,
user: initialUser,
session: initialSession,
botState: initialBotState,
}

export function useWebchat() {
Expand All @@ -87,12 +113,23 @@ export function useWebchat() {
type: UPDATE_WEBVIEW,
payload: { webview, webviewParams: params },
})
const updateSession = session => {
const updateSession = session =>
webchatDispatch({
type: UPDATE_SESSION,
payload: session,
})
}

const updateUser = user =>
webchatDispatch({
type: UPDATE_USER,
payload: user,
})

const updateBotState = botState =>
webchatDispatch({
type: UPDATE_BOT_STATE,
payload: botState,
})

const updateLastRoutePath = path =>
webchatDispatch({
Expand Down Expand Up @@ -198,6 +235,8 @@ export function useWebchat() {
updateLastMessageDate,
setCurrentAttachment,
updateJwt,
updateBotState,
updateUser,
}
}

Expand Down
12 changes: 9 additions & 3 deletions packages/botonic-react/src/experimental/webchat/session-view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ const KeepSessionContainer = styled.div`
export const SessionView = props => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { webchatState, updateDevSettings } = props.webchatHooks || useWebchat()
const { latestInput: input, session, lastRoutePath } = webchatState
const { latestInput: input, session, botState } = webchatState
const { type, id, ...latestInputData } = input

const toggleSessionView = () =>
updateDevSettings({
...webchatState.devSettings,
Expand All @@ -122,7 +124,7 @@ export const SessionView = props => {
label='INPUT:'
value={
input && Object.keys(input).length
? `[${input.type}] ${input.data || ''}`
? `[${type}] ${JSON.stringify(latestInputData) || ''}`
: ''
}
/>
Expand All @@ -137,8 +139,12 @@ export const SessionView = props => {
/>
<SessionViewAttribute
label='PATH:'
value={lastRoutePath ? `/${lastRoutePath}` : '/'}
value={botState.lastRoutePath ? `/${botState.lastRoutePath}` : '/'}
/>
<SessionViewAttribute label='BOT STATE:' />
<SessionContainer>
<JSONTree data={botState} hideRoot={true} />
</SessionContainer>
<SessionViewAttribute label='SESSION:' />
<SessionContainer>
<JSONTree data={session} hideRoot={true} />
Expand Down
Loading

0 comments on commit f231f45

Please sign in to comment.