🚸 (bot) Update reply if we get new format from backend
This commit is contained in:
@ -744,6 +744,9 @@
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"isAutoplayEnabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@ -1986,6 +1989,7 @@
|
||||
"Custom",
|
||||
"Empty",
|
||||
"User ID",
|
||||
"Now",
|
||||
"Today",
|
||||
"Yesterday",
|
||||
"Tomorrow",
|
||||
|
@ -312,6 +312,9 @@
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"isAutoplayEnabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@ -1554,6 +1557,7 @@
|
||||
"Custom",
|
||||
"Empty",
|
||||
"User ID",
|
||||
"Now",
|
||||
"Today",
|
||||
"Yesterday",
|
||||
"Tomorrow",
|
||||
@ -4031,6 +4035,9 @@
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"isAutoplayEnabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@ -6021,6 +6028,10 @@
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"lastMessageNewFormat": {
|
||||
"type": "string",
|
||||
"description": "The sent message is validated and formatted on the backend. This is set only if the message differs from the formatted version."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
@ -79,8 +79,14 @@ export const sendMessage = publicProcedure
|
||||
clientSideActions,
|
||||
}
|
||||
} else {
|
||||
const { messages, input, clientSideActions, newSessionState, logs } =
|
||||
await continueBotFlow(session.state)(message)
|
||||
const {
|
||||
messages,
|
||||
input,
|
||||
clientSideActions,
|
||||
newSessionState,
|
||||
logs,
|
||||
lastMessageNewFormat,
|
||||
} = await continueBotFlow(session.state)(message)
|
||||
|
||||
const allLogs = clientLogs ? [...(logs ?? []), ...clientLogs] : logs
|
||||
|
||||
@ -101,6 +107,7 @@ export const sendMessage = publicProcedure
|
||||
clientSideActions,
|
||||
dynamicTheme: parseDynamicThemeReply(newSessionState),
|
||||
logs,
|
||||
lastMessageNewFormat,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ export const continueBotFlow =
|
||||
message: 'Current block is not an input block',
|
||||
})
|
||||
|
||||
let formattedReply = null
|
||||
let formattedReply: string | undefined
|
||||
|
||||
if (isInputBlock(block)) {
|
||||
if (reply && !isReplyValid(reply, block))
|
||||
@ -116,25 +116,46 @@ export const continueBotFlow =
|
||||
const nextEdgeId = getOutgoingEdgeId(newSessionState)(block, formattedReply)
|
||||
|
||||
if (groupHasMoreBlocks && !nextEdgeId) {
|
||||
return executeGroup(newSessionState)({
|
||||
const chatReply = await executeGroup(newSessionState)({
|
||||
...group,
|
||||
blocks: group.blocks.slice(blockIndex + 1),
|
||||
})
|
||||
return {
|
||||
...chatReply,
|
||||
lastMessageNewFormat:
|
||||
formattedReply !== reply ? formattedReply : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
if (!nextEdgeId && state.linkedTypebots.queue.length === 0)
|
||||
return { messages: [], newSessionState }
|
||||
return {
|
||||
messages: [],
|
||||
newSessionState,
|
||||
lastMessageNewFormat:
|
||||
formattedReply !== reply ? formattedReply : undefined,
|
||||
}
|
||||
|
||||
const nextGroup = getNextGroup(newSessionState)(nextEdgeId)
|
||||
|
||||
if (!nextGroup) return { messages: [], newSessionState }
|
||||
if (!nextGroup)
|
||||
return {
|
||||
messages: [],
|
||||
newSessionState,
|
||||
lastMessageNewFormat:
|
||||
formattedReply !== reply ? formattedReply : undefined,
|
||||
}
|
||||
|
||||
return executeGroup(newSessionState)(nextGroup.group)
|
||||
const chatReply = executeGroup(newSessionState)(nextGroup.group)
|
||||
return {
|
||||
...chatReply,
|
||||
lastMessageNewFormat:
|
||||
formattedReply !== reply ? formattedReply : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
const processAndSaveAnswer =
|
||||
(state: SessionState, block: InputBlock, itemId?: string) =>
|
||||
async (reply: string | null): Promise<SessionState> => {
|
||||
async (reply: string | undefined): Promise<SessionState> => {
|
||||
if (!reply) return state
|
||||
let newState = await saveAnswer(state, block, itemId)(reply)
|
||||
newState = saveVariableValueIfAny(newState, block)(reply)
|
||||
@ -236,7 +257,7 @@ const getOutgoingEdgeId =
|
||||
({ typebot: { variables } }: Pick<SessionState, 'typebot'>) =>
|
||||
(
|
||||
block: InputBlock | SetVariableBlock | OpenAIBlock | WebhookBlock,
|
||||
reply: string | null
|
||||
reply: string | undefined
|
||||
) => {
|
||||
if (
|
||||
block.type === InputBlockType.CHOICE &&
|
||||
@ -264,8 +285,8 @@ const getOutgoingEdgeId =
|
||||
export const formatReply = (
|
||||
inputValue: string | undefined,
|
||||
blockType: BlockType
|
||||
): string | null => {
|
||||
if (!inputValue) return null
|
||||
): string | undefined => {
|
||||
if (!inputValue) return
|
||||
switch (blockType) {
|
||||
case InputBlockType.PHONE:
|
||||
return formatPhoneNumber(inputValue)
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/js",
|
||||
"version": "0.1.15",
|
||||
"version": "0.1.16",
|
||||
"description": "Javascript library to display typebots on your website",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
@ -93,8 +93,6 @@ export const ChatChunk = (props: Props) => {
|
||||
ref={inputRef}
|
||||
block={props.input}
|
||||
inputIndex={props.inputIndex}
|
||||
onSubmit={props.onSubmit}
|
||||
onSkip={props.onSkip}
|
||||
hasHostAvatar={props.theme.chat.hostAvatar?.isEnabled ?? false}
|
||||
guestAvatar={props.theme.chat.guestAvatar}
|
||||
context={props.context}
|
||||
@ -102,6 +100,8 @@ export const ChatChunk = (props: Props) => {
|
||||
props.settings.general.isInputPrefillEnabled ?? true
|
||||
}
|
||||
hasError={props.hasError}
|
||||
onSubmit={props.onSubmit}
|
||||
onSkip={props.onSkip}
|
||||
/>
|
||||
)}
|
||||
<Show when={props.streamingMessageId} keyed>
|
||||
|
@ -21,6 +21,10 @@ import { executeClientSideAction } from '@/utils/executeClientSideActions'
|
||||
import { LoadingChunk } from './LoadingChunk'
|
||||
import { PopupBlockedToast } from './PopupBlockedToast'
|
||||
import { setStreamingMessage } from '@/utils/streamingMessageSignal'
|
||||
import {
|
||||
formattedMessages,
|
||||
setFormattedMessages,
|
||||
} from '@/utils/formattedMessagesSignal'
|
||||
|
||||
const parseDynamicTheme = (
|
||||
initialTheme: Theme,
|
||||
@ -164,6 +168,15 @@ export const ConversationContainer = (props: Props) => {
|
||||
])
|
||||
}
|
||||
if (!data) return
|
||||
if (data.lastMessageNewFormat) {
|
||||
setFormattedMessages([
|
||||
...formattedMessages(),
|
||||
{
|
||||
inputId: [...chatChunks()].pop()?.input?.id ?? '',
|
||||
formattedMessage: data.lastMessageNewFormat as string,
|
||||
},
|
||||
])
|
||||
}
|
||||
if (data.logs) props.onNewLogs?.(data.logs)
|
||||
if (data.dynamicTheme) setDynamicTheme(data.dynamicTheme)
|
||||
if (data.input?.id && props.onNewInputBlock) {
|
||||
|
@ -25,7 +25,7 @@ import { PhoneInput } from '@/features/blocks/inputs/phone'
|
||||
import { DateForm } from '@/features/blocks/inputs/date'
|
||||
import { RatingForm } from '@/features/blocks/inputs/rating'
|
||||
import { FileUploadForm } from '@/features/blocks/inputs/fileUpload'
|
||||
import { createSignal, Switch, Match } from 'solid-js'
|
||||
import { createSignal, Switch, Match, createEffect } from 'solid-js'
|
||||
import { isNotDefined } from '@typebot.io/lib'
|
||||
import { isMobile } from '@/utils/isMobileSignal'
|
||||
import { PaymentForm } from '@/features/blocks/inputs/payment'
|
||||
@ -33,6 +33,7 @@ import { MultipleChoicesForm } from '@/features/blocks/inputs/buttons/components
|
||||
import { Buttons } from '@/features/blocks/inputs/buttons/components/Buttons'
|
||||
import { SinglePictureChoice } from '@/features/blocks/inputs/pictureChoice/SinglePictureChoice'
|
||||
import { MultiplePictureChoice } from '@/features/blocks/inputs/pictureChoice/MultiplePictureChoice'
|
||||
import { formattedMessages } from '@/utils/formattedMessagesSignal'
|
||||
|
||||
type Props = {
|
||||
ref: HTMLDivElement | undefined
|
||||
@ -49,6 +50,7 @@ type Props = {
|
||||
|
||||
export const InputChatBlock = (props: Props) => {
|
||||
const [answer, setAnswer] = createSignal<string>()
|
||||
const [formattedMessage, setFormattedMessage] = createSignal<string>()
|
||||
|
||||
const handleSubmit = async ({ label, value }: InputSubmitContent) => {
|
||||
setAnswer(label ?? value)
|
||||
@ -60,11 +62,18 @@ export const InputChatBlock = (props: Props) => {
|
||||
props.onSkip()
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const formattedMessage = formattedMessages().find(
|
||||
(message) => message.inputId === props.block.id
|
||||
)?.formattedMessage
|
||||
if (formattedMessage) setFormattedMessage(formattedMessage)
|
||||
})
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={answer() && !props.hasError}>
|
||||
<GuestBubble
|
||||
message={answer() as string}
|
||||
message={formattedMessage() ?? (answer() as string)}
|
||||
showAvatar={props.guestAvatar?.isEnabled ?? false}
|
||||
avatarSrc={props.guestAvatar?.url && props.guestAvatar.url}
|
||||
/>
|
||||
|
5
packages/embeds/js/src/utils/formattedMessagesSignal.ts
Normal file
5
packages/embeds/js/src/utils/formattedMessagesSignal.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { createSignal } from 'solid-js'
|
||||
|
||||
export const [formattedMessages, setFormattedMessages] = createSignal<
|
||||
{ inputId: string; formattedMessage: string }[]
|
||||
>([])
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/nextjs",
|
||||
"version": "0.1.15",
|
||||
"version": "0.1.16",
|
||||
"description": "Convenient library to display typebots on your Next.js website",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/react",
|
||||
"version": "0.1.15",
|
||||
"version": "0.1.16",
|
||||
"description": "Convenient library to display typebots on your Next.js website",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
@ -292,6 +292,12 @@ export const chatReplySchema = z.object({
|
||||
resultId: z.string().optional(),
|
||||
dynamicTheme: dynamicThemeSchema.optional(),
|
||||
logs: z.array(replyLogSchema).optional(),
|
||||
lastMessageNewFormat: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'The sent message is validated and formatted on the backend. This is set only if the message differs from the formatted version.'
|
||||
),
|
||||
})
|
||||
|
||||
export type ChatSession = z.infer<typeof chatSessionSchema>
|
||||
|
Reference in New Issue
Block a user