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