⚡ 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:
@ -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 (
|
||||
|
@ -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}
|
||||
/>
|
||||
)}
|
||||
|
22
packages/js/src/utils/executeClientSideActions.ts
Normal file
22
packages/js/src/utils/executeClientSideActions.ts
Normal 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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user