🚸 (js) Display last input if send message errored
This commit is contained in:
@ -60,11 +60,17 @@ export const Bot = (props: BotProps & { class?: string }) => {
|
||||
},
|
||||
})
|
||||
if (error && 'code' in error && typeof error.code === 'string') {
|
||||
if (typeof props.typebot !== 'string' || (props.isPreview ?? false)) {
|
||||
setError(
|
||||
new Error('An error occurred while loading the bot.', {
|
||||
cause: error.message,
|
||||
})
|
||||
)
|
||||
}
|
||||
if (['BAD_REQUEST', 'FORBIDDEN'].includes(error.code))
|
||||
setError(new Error('This bot is now closed.'))
|
||||
if (error.code === 'NOT_FOUND')
|
||||
setError(new Error("The bot you're looking for doesn't exist."))
|
||||
return
|
||||
}
|
||||
|
||||
if (!data) return setError(new Error("Error! Couldn't initiate the chat."))
|
||||
|
@ -12,6 +12,7 @@ type Props = Pick<ChatReply, 'messages' | 'input'> & {
|
||||
inputIndex: number
|
||||
context: BotContext
|
||||
isLoadingBubbleDisplayed: boolean
|
||||
hasError: boolean
|
||||
onNewBubbleDisplayed: (blockId: string) => Promise<void>
|
||||
onScrollToBottom: () => void
|
||||
onSubmit: (input: string) => void
|
||||
@ -90,6 +91,7 @@ export const ChatChunk = (props: Props) => {
|
||||
isInputPrefillEnabled={
|
||||
props.settings.general.isInputPrefillEnabled ?? true
|
||||
}
|
||||
hasError={props.hasError}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@ -59,6 +59,7 @@ export const ConversationContainer = (props: Props) => {
|
||||
const [theme, setTheme] = createSignal(props.initialChatReply.typebot.theme)
|
||||
const [isSending, setIsSending] = createSignal(false)
|
||||
const [blockedPopupUrl, setBlockedPopupUrl] = createSignal<string>()
|
||||
const [hasError, setHasError] = createSignal(false)
|
||||
|
||||
onMount(() => {
|
||||
;(async () => {
|
||||
@ -82,19 +83,30 @@ export const ConversationContainer = (props: Props) => {
|
||||
})
|
||||
|
||||
const sendMessage = async (message: string | undefined) => {
|
||||
setHasError(false)
|
||||
const currentBlockId = [...chatChunks()].pop()?.input?.id
|
||||
if (currentBlockId && props.onAnswer && message)
|
||||
props.onAnswer({ message, blockId: currentBlockId })
|
||||
const longRequest = setTimeout(() => {
|
||||
setIsSending(true)
|
||||
}, 1000)
|
||||
const data = await sendMessageQuery({
|
||||
const { data, error } = await sendMessageQuery({
|
||||
apiHost: props.context.apiHost,
|
||||
sessionId: props.initialChatReply.sessionId,
|
||||
message,
|
||||
})
|
||||
clearTimeout(longRequest)
|
||||
setIsSending(false)
|
||||
if (error) {
|
||||
setHasError(true)
|
||||
props.onNewLogs?.([
|
||||
{
|
||||
description: 'Error while sending message',
|
||||
details: error,
|
||||
status: 'error',
|
||||
},
|
||||
])
|
||||
}
|
||||
if (!data) return
|
||||
if (data.logs) props.onNewLogs?.(data.logs)
|
||||
if (data.dynamicTheme) setDynamicTheme(data.dynamicTheme)
|
||||
@ -174,6 +186,7 @@ export const ConversationContainer = (props: Props) => {
|
||||
onScrollToBottom={autoScrollToBottom}
|
||||
onSkip={handleSkip}
|
||||
context={props.context}
|
||||
hasError={hasError() && index() === chatChunks().length - 1}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
|
@ -5,6 +5,7 @@ export const ErrorMessage = (props: Props) => {
|
||||
return (
|
||||
<div class="h-full flex justify-center items-center flex-col">
|
||||
<p class="text-2xl text-center">{props.error.message}</p>
|
||||
<p class="text-center">{props.error.cause as string}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ type Props = {
|
||||
inputIndex: number
|
||||
context: BotContext
|
||||
isInputPrefillEnabled: boolean
|
||||
hasError: boolean
|
||||
onSubmit: (answer: string) => void
|
||||
onSkip: () => void
|
||||
}
|
||||
@ -56,16 +57,14 @@ export const InputChatBlock = (props: Props) => {
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={answer()} keyed>
|
||||
{(answer) => (
|
||||
<GuestBubble
|
||||
message={answer}
|
||||
showAvatar={props.guestAvatar?.isEnabled ?? false}
|
||||
avatarSrc={props.guestAvatar?.url && props.guestAvatar.url}
|
||||
/>
|
||||
)}
|
||||
<Match when={answer() && !props.hasError}>
|
||||
<GuestBubble
|
||||
message={answer() as string}
|
||||
showAvatar={props.guestAvatar?.isEnabled ?? false}
|
||||
avatarSrc={props.guestAvatar?.url && props.guestAvatar.url}
|
||||
/>
|
||||
</Match>
|
||||
<Match when={isNotDefined(answer())}>
|
||||
<Match when={isNotDefined(answer()) || props.hasError}>
|
||||
<div
|
||||
class="flex justify-end animate-fade-in"
|
||||
data-blockid={props.block.id}
|
||||
|
@ -2,15 +2,12 @@ import { guessApiHost } from '@/utils/guessApiHost'
|
||||
import type { ChatReply, SendMessageInput } from '@typebot.io/schemas'
|
||||
import { isNotEmpty, sendRequest } from '@typebot.io/lib'
|
||||
|
||||
export async function sendMessageQuery({
|
||||
export const sendMessageQuery = ({
|
||||
apiHost,
|
||||
...body
|
||||
}: SendMessageInput & { apiHost?: string }) {
|
||||
const response = await sendRequest<ChatReply>({
|
||||
}: SendMessageInput & { apiHost?: string }) =>
|
||||
sendRequest<ChatReply>({
|
||||
method: 'POST',
|
||||
url: `${isNotEmpty(apiHost) ? apiHost : guessApiHost()}/api/v1/sendMessage`,
|
||||
body,
|
||||
})
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
@ -3,4 +3,6 @@ import { env } from '@typebot.io/lib'
|
||||
const cloudViewerUrl = 'https://viewer.typebot.io'
|
||||
|
||||
export const guessApiHost = () =>
|
||||
env('VIEWER_URL')?.split(',')[0] ?? cloudViewerUrl
|
||||
env('VIEWER_INTERNAL_URL') ??
|
||||
env('VIEWER_URL')?.split(',')[0] ??
|
||||
cloudViewerUrl
|
||||
|
Reference in New Issue
Block a user