⚡ Restore chat state when user is remembered (#1333)
Closes #993 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a detailed explanation page for the "Remember user" setting in the app documentation. - Introduced persistence of chat state across sessions, with options for local or session storage. - Enhanced bot functionality to store and retrieve initial chat replies and manage bot open state with improved storage handling. - Added a new callback for chat state persistence to bot component props. - **Improvements** - Updated the general settings form to clarify the description of the "Remember user" feature. - Enhanced custom CSS handling and progress value persistence in bot components. - Added conditional transition disabling in various components for smoother user experiences. - Simplified the handling of `onTransitionEnd` across multiple bubble components. - **Refactor** - Renamed `inputIndex` to `chunkIndex` or `index` in various components for consistency. - Removed unused ESLint disable comments related to reactivity rules. - Adjusted import statements and cleaned up code across several files. - **Bug Fixes** - Fixed potential issues with undefined callbacks by introducing optional chaining in component props. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -8,7 +8,10 @@ import { BotContext, InitialChatReply, OutgoingLog } from '@/types'
|
||||
import { ErrorMessage } from './ErrorMessage'
|
||||
import {
|
||||
getExistingResultIdFromStorage,
|
||||
getInitialChatReplyFromStorage,
|
||||
setInitialChatReplyInStorage,
|
||||
setResultInStorage,
|
||||
wipeExistingChatStateInStorage,
|
||||
} from '@/utils/storage'
|
||||
import { setCssVariablesValue } from '@/utils/setCssVariablesValue'
|
||||
import immutableCss from '../assets/immutable.css'
|
||||
@@ -20,6 +23,8 @@ import { HTTPError } from 'ky'
|
||||
import { injectFont } from '@/utils/injectFont'
|
||||
import { ProgressBar } from './ProgressBar'
|
||||
import { Portal } from 'solid-js/web'
|
||||
import { defaultSettings } from '@typebot.io/schemas/features/typebot/settings/constants'
|
||||
import { persist } from '@/utils/persist'
|
||||
|
||||
export type BotProps = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -35,6 +40,7 @@ export type BotProps = {
|
||||
onInit?: () => void
|
||||
onEnd?: () => void
|
||||
onNewLogs?: (logs: OutgoingLog[]) => void
|
||||
onChatStatePersisted?: (isEnabled: boolean) => void
|
||||
startFrom?: StartFrom
|
||||
}
|
||||
|
||||
@@ -59,14 +65,13 @@ export const Bot = (props: BotProps & { class?: string }) => {
|
||||
typeof props.typebot === 'string' ? props.typebot : undefined
|
||||
const isPreview =
|
||||
typeof props.typebot !== 'string' || (props.isPreview ?? false)
|
||||
const resultIdInStorage = getExistingResultIdFromStorage(typebotIdFromProps)
|
||||
const { data, error } = await startChatQuery({
|
||||
stripeRedirectStatus: urlParams.get('redirect_status') ?? undefined,
|
||||
typebot: props.typebot,
|
||||
apiHost: props.apiHost,
|
||||
isPreview,
|
||||
resultId: isNotEmpty(props.resultId)
|
||||
? props.resultId
|
||||
: getExistingResultIdFromStorage(typebotIdFromProps),
|
||||
resultId: isNotEmpty(props.resultId) ? props.resultId : resultIdInStorage,
|
||||
prefilledVariables: {
|
||||
...prefilledVariables,
|
||||
...props.prefilledVariables,
|
||||
@@ -111,17 +116,40 @@ export const Bot = (props: BotProps & { class?: string }) => {
|
||||
)
|
||||
}
|
||||
|
||||
if (data.resultId && typebotIdFromProps)
|
||||
setResultInStorage(data.typebot.settings.general?.rememberUser?.storage)(
|
||||
typebotIdFromProps,
|
||||
data.resultId
|
||||
if (
|
||||
data.resultId &&
|
||||
typebotIdFromProps &&
|
||||
(data.typebot.settings.general?.rememberUser?.isEnabled ??
|
||||
defaultSettings.general.rememberUser.isEnabled)
|
||||
) {
|
||||
if (resultIdInStorage && resultIdInStorage !== data.resultId)
|
||||
wipeExistingChatStateInStorage(data.typebot.id)
|
||||
const storage =
|
||||
data.typebot.settings.general?.rememberUser?.storage ??
|
||||
defaultSettings.general.rememberUser.storage
|
||||
setResultInStorage(storage)(typebotIdFromProps, data.resultId)
|
||||
const initialChatInStorage = getInitialChatReplyFromStorage(
|
||||
data.typebot.id
|
||||
)
|
||||
setInitialChatReply(data)
|
||||
setCustomCss(data.typebot.theme.customCss ?? '')
|
||||
if (initialChatInStorage) {
|
||||
setInitialChatReply(initialChatInStorage)
|
||||
} else {
|
||||
setInitialChatReply(data)
|
||||
setInitialChatReplyInStorage(data, {
|
||||
typebotId: data.typebot.id,
|
||||
storage,
|
||||
})
|
||||
}
|
||||
props.onChatStatePersisted?.(true)
|
||||
} else {
|
||||
setInitialChatReply(data)
|
||||
if (data.input?.id && props.onNewInputBlock)
|
||||
props.onNewInputBlock(data.input)
|
||||
if (data.logs) props.onNewLogs?.(data.logs)
|
||||
props.onChatStatePersisted?.(false)
|
||||
}
|
||||
|
||||
if (data.input?.id && props.onNewInputBlock)
|
||||
props.onNewInputBlock(data.input)
|
||||
if (data.logs) props.onNewLogs?.(data.logs)
|
||||
setCustomCss(data.typebot.theme.customCss ?? '')
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
@@ -178,6 +206,16 @@ export const Bot = (props: BotProps & { class?: string }) => {
|
||||
resultId: initialChatReply.resultId,
|
||||
sessionId: initialChatReply.sessionId,
|
||||
typebot: initialChatReply.typebot,
|
||||
storage:
|
||||
initialChatReply.typebot.settings.general?.rememberUser
|
||||
?.isEnabled &&
|
||||
!(
|
||||
typeof props.typebot !== 'string' ||
|
||||
(props.isPreview ?? false)
|
||||
)
|
||||
? initialChatReply.typebot.settings.general?.rememberUser
|
||||
?.storage ?? defaultSettings.general.rememberUser.storage
|
||||
: undefined,
|
||||
}}
|
||||
progressBarRef={props.progressBarRef}
|
||||
onNewInputBlock={props.onNewInputBlock}
|
||||
@@ -203,8 +241,12 @@ type BotContentProps = {
|
||||
}
|
||||
|
||||
const BotContent = (props: BotContentProps) => {
|
||||
const [progressValue, setProgressValue] = createSignal<number | undefined>(
|
||||
props.initialChatReply.progress
|
||||
const [progressValue, setProgressValue] = persist(
|
||||
createSignal<number | undefined>(props.initialChatReply.progress),
|
||||
{
|
||||
storage: props.context.storage,
|
||||
key: `typebot-${props.context.typebot.id}-progressValue`,
|
||||
}
|
||||
)
|
||||
let botContainer: HTMLDivElement | undefined
|
||||
|
||||
|
||||
Reference in New Issue
Block a user