2
0

Improve new bot engine client side actions

We make sure to save client side actions in an array that will be executed sequentially
This commit is contained in:
Baptiste Arnaud
2023-01-26 15:26:42 +01:00
parent 0fc82cf73b
commit 9aab6ddb2c
15 changed files with 133 additions and 106 deletions

View File

@ -12,14 +12,17 @@ type Props = Pick<ChatReply, 'messages' | 'input'> & {
context: BotContext
onScrollToBottom: () => void
onSubmit: (input: string) => void
onEnd?: () => void
onSkip: () => void
onAllBubblesDisplayed: () => void
}
export const ChatChunk = (props: Props) => {
const [displayedMessageIndex, setDisplayedMessageIndex] = createSignal(0)
onMount(() => {
if (props.messages.length === 0) {
props.onAllBubblesDisplayed()
}
props.onScrollToBottom()
})
@ -30,8 +33,9 @@ export const ChatChunk = (props: Props) => {
: displayedMessageIndex() + 1
)
props.onScrollToBottom()
if (!props.input && displayedMessageIndex() === props.messages.length)
return props.onEnd?.()
if (displayedMessageIndex() === props.messages.length) {
props.onAllBubblesDisplayed()
}
}
return (

View File

@ -3,8 +3,8 @@ import { createEffect, createSignal, For } from 'solid-js'
import { sendMessageQuery } from '@/queries/sendMessageQuery'
import { ChatChunk } from './ChatChunk'
import { BotContext, InitialChatReply } from '@/types'
import { executeIntegrations } from '@/utils/executeIntegrations'
import { executeLogic } from '@/utils/executeLogic'
import { isNotDefined } from 'utils'
import { executeClientSideAction } from '@/utils/executeClientSideActions'
const parseDynamicTheme = (
initialTheme: Theme,
@ -42,10 +42,13 @@ type Props = {
export const ConversationContainer = (props: Props) => {
let chatContainer: HTMLDivElement | undefined
let bottomSpacer: HTMLDivElement | undefined
const [chatChunks, setChatChunks] = createSignal<ChatReply[]>([
const [chatChunks, setChatChunks] = createSignal<
Pick<ChatReply, 'messages' | 'input' | 'clientSideActions'>[]
>([
{
input: props.initialChatReply.input,
messages: props.initialChatReply.messages,
clientSideActions: props.initialChatReply.clientSideActions,
},
])
const [dynamicTheme, setDynamicTheme] = createSignal<
@ -77,17 +80,12 @@ export const ConversationContainer = (props: Props) => {
groupId: data.input.groupId,
})
}
if (data.integrations) {
executeIntegrations(data.integrations)
}
if (data.logic) {
await executeLogic(data.logic)
}
setChatChunks((displayedChunks) => [
...displayedChunks,
{
input: data.input,
messages: data.messages,
clientSideActions: data.clientSideActions,
},
])
}
@ -99,6 +97,19 @@ export const ConversationContainer = (props: Props) => {
}, 50)
}
const handleAllBubblesDisplayed = async () => {
const lastChunk = chatChunks().at(-1)
if (!lastChunk) return
if (lastChunk.clientSideActions) {
for (const action of lastChunk.clientSideActions) {
await executeClientSideAction(action)
}
}
if (isNotDefined(lastChunk.input)) {
props.onEnd?.()
}
}
return (
<div
ref={chatContainer}
@ -112,12 +123,12 @@ export const ConversationContainer = (props: Props) => {
input={chatChunk.input}
theme={theme()}
settings={props.initialChatReply.typebot.settings}
onAllBubblesDisplayed={handleAllBubblesDisplayed}
onSubmit={sendMessage}
onScrollToBottom={autoScrollToBottom}
onSkip={() => {
// TODO: implement skip
}}
onEnd={props.onEnd}
context={props.context}
/>
)}

View File

@ -0,0 +1,22 @@
import { executeChatwoot } from '@/features/blocks/integrations/chatwoot'
import { executeGoogleAnalyticsBlock } from '@/features/blocks/integrations/googleAnalytics/utils/executeGoogleAnalytics'
import { executeCode } from '@/features/blocks/logic/code'
import { executeRedirect } from '@/features/blocks/logic/redirect'
import type { ChatReply } from 'models'
export const executeClientSideAction = async (
clientSideAction: NonNullable<ChatReply['clientSideActions']>[0]
) => {
if ('chatwoot' in clientSideAction) {
executeChatwoot(clientSideAction.chatwoot)
}
if ('googleAnalytics' in clientSideAction) {
executeGoogleAnalyticsBlock(clientSideAction.googleAnalytics)
}
if ('codeToExecute' in clientSideAction) {
await executeCode(clientSideAction.codeToExecute)
}
if ('redirect' in clientSideAction) {
executeRedirect(clientSideAction.redirect)
}
}

View File

@ -1,14 +0,0 @@
import { executeChatwoot } from '@/features/blocks/integrations/chatwoot'
import { executeGoogleAnalyticsBlock } from '@/features/blocks/integrations/googleAnalytics/utils/executeGoogleAnalytics'
import type { ChatReply } from 'models'
export const executeIntegrations = async (
integrations: ChatReply['integrations']
) => {
if (integrations?.chatwoot?.codeToExecute) {
executeChatwoot(integrations.chatwoot)
}
if (integrations?.googleAnalytics) {
executeGoogleAnalyticsBlock(integrations.googleAnalytics)
}
}

View File

@ -1,12 +0,0 @@
import { executeCode } from '@/features/blocks/logic/code'
import { executeRedirect } from '@/features/blocks/logic/redirect'
import type { ChatReply } from 'models'
export const executeLogic = async (logic: ChatReply['logic']) => {
if (logic?.codeToExecute) {
await executeCode(logic.codeToExecute)
}
if (logic?.redirect) {
executeRedirect(logic.redirect)
}
}