@ -5,10 +5,11 @@ import {
|
||||
Variable,
|
||||
VariableWithValue,
|
||||
Theme,
|
||||
IntegrationBlockType,
|
||||
GoogleAnalyticsBlock,
|
||||
PixelBlock,
|
||||
SessionState,
|
||||
TypebotInSession,
|
||||
Block,
|
||||
} from '@typebot.io/schemas'
|
||||
import {
|
||||
ChatReply,
|
||||
@ -30,6 +31,10 @@ import { getNextGroup } from './getNextGroup'
|
||||
import { upsertResult } from './queries/upsertResult'
|
||||
import { continueBotFlow } from './continueBotFlow'
|
||||
import { parseVariables } from './variables/parseVariables'
|
||||
import { defaultSettings } from '@typebot.io/schemas/features/typebot/settings/constants'
|
||||
import { IntegrationBlockType } from '@typebot.io/schemas/features/blocks/integrations/constants'
|
||||
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
import { VisitedEdge } from '@typebot.io/prisma'
|
||||
|
||||
type Props = {
|
||||
version: 1 | 2
|
||||
@ -45,7 +50,9 @@ export const startSession = async ({
|
||||
startParams,
|
||||
userId,
|
||||
initialSessionState,
|
||||
}: Props): Promise<ChatReply & { newSessionState: SessionState }> => {
|
||||
}: Props): Promise<
|
||||
ChatReply & { newSessionState: SessionState; visitedEdges: VisitedEdge[] }
|
||||
> => {
|
||||
if (!startParams)
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
@ -64,10 +71,10 @@ export const startSession = async ({
|
||||
typebotId: typebot.id,
|
||||
prefilledVariables,
|
||||
isRememberUserEnabled:
|
||||
typebot.settings.general.rememberUser?.isEnabled ??
|
||||
(isDefined(typebot.settings.general.isNewResultOnRefreshEnabled)
|
||||
? !typebot.settings.general.isNewResultOnRefreshEnabled
|
||||
: false),
|
||||
typebot.settings.general?.rememberUser?.isEnabled ??
|
||||
(isDefined(typebot.settings.general?.isNewResultOnRefreshEnabled)
|
||||
? !typebot.settings.general?.isNewResultOnRefreshEnabled
|
||||
: defaultSettings.general.rememberUser.isEnabled),
|
||||
})
|
||||
|
||||
const startVariables =
|
||||
@ -75,22 +82,21 @@ export const startSession = async ({
|
||||
? injectVariablesFromExistingResult(prefilledVariables, result.variables)
|
||||
: prefilledVariables
|
||||
|
||||
const typebotInSession = convertStartTypebotToTypebotInSession(
|
||||
typebot,
|
||||
startVariables
|
||||
)
|
||||
|
||||
const initialState: SessionState = {
|
||||
version: '2',
|
||||
version: '3',
|
||||
typebotsQueue: [
|
||||
{
|
||||
resultId: result?.id,
|
||||
typebot: {
|
||||
version: typebot.version,
|
||||
id: typebot.id,
|
||||
groups: typebot.groups,
|
||||
edges: typebot.edges,
|
||||
variables: startVariables,
|
||||
},
|
||||
typebot: typebotInSession,
|
||||
answers: result
|
||||
? result.answers.map((answer) => {
|
||||
const block = typebot.groups
|
||||
.flatMap((group) => group.blocks)
|
||||
.flatMap<Block>((group) => group.blocks)
|
||||
.find((block) => block.id === answer.blockId)
|
||||
if (!block || !isInputBlock(block))
|
||||
return {
|
||||
@ -98,9 +104,9 @@ export const startSession = async ({
|
||||
value: answer.content,
|
||||
}
|
||||
const key =
|
||||
(block.options.variableId
|
||||
(block.options?.variableId
|
||||
? startVariables.find(
|
||||
(variable) => variable.id === block.options.variableId
|
||||
(variable) => variable.id === block.options?.variableId
|
||||
)?.name
|
||||
: typebot.groups.find((group) =>
|
||||
group.blocks.find(
|
||||
@ -135,13 +141,18 @@ export const startSession = async ({
|
||||
},
|
||||
dynamicTheme: parseDynamicTheme(initialState),
|
||||
messages: [],
|
||||
visitedEdges: [],
|
||||
}
|
||||
}
|
||||
|
||||
let chatReply = await startBotFlow({
|
||||
version,
|
||||
state: initialState,
|
||||
startGroupId: startParams.startGroupId,
|
||||
...('startGroupId' in startParams
|
||||
? { startGroupId: startParams.startGroupId }
|
||||
: 'startEventId' in startParams
|
||||
? { startEventId: startParams.startEventId }
|
||||
: {}),
|
||||
})
|
||||
|
||||
// If params has message and first block is an input block, we can directly continue the bot flow
|
||||
@ -165,7 +176,7 @@ export const startSession = async ({
|
||||
version,
|
||||
state: {
|
||||
...newSessionState,
|
||||
currentBlock: { groupId: firstBlock.groupId, blockId: firstBlock.id },
|
||||
currentBlockId: firstBlock.id,
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -177,6 +188,7 @@ export const startSession = async ({
|
||||
clientSideActions: startFlowClientActions,
|
||||
newSessionState,
|
||||
logs,
|
||||
visitedEdges,
|
||||
} = chatReply
|
||||
|
||||
const clientSideActions = startFlowClientActions ?? []
|
||||
@ -188,12 +200,12 @@ export const startSession = async ({
|
||||
if (isDefined(startClientSideAction)) {
|
||||
if (!result) {
|
||||
if ('startPropsToInject' in startClientSideAction) {
|
||||
const { customHeadCode, googleAnalyticsId, pixelId, pixelIds, gtmId } =
|
||||
const { customHeadCode, googleAnalyticsId, pixelIds, gtmId } =
|
||||
startClientSideAction.startPropsToInject
|
||||
let toolsList = ''
|
||||
if (customHeadCode) toolsList += 'Custom head code, '
|
||||
if (googleAnalyticsId) toolsList += 'Google Analytics, '
|
||||
if (pixelId || pixelIds) toolsList += 'Pixel, '
|
||||
if (pixelIds) toolsList += 'Pixel, '
|
||||
if (gtmId) toolsList += 'Google Tag Manager, '
|
||||
toolsList = toolsList.slice(0, -2)
|
||||
startLogs.push({
|
||||
@ -229,6 +241,7 @@ export const startSession = async ({
|
||||
},
|
||||
dynamicTheme: parseDynamicTheme(newSessionState),
|
||||
logs: startLogs.length > 0 ? startLogs : undefined,
|
||||
visitedEdges,
|
||||
}
|
||||
|
||||
return {
|
||||
@ -249,6 +262,7 @@ export const startSession = async ({
|
||||
clientSideActions.length > 0 ? clientSideActions : undefined,
|
||||
dynamicTheme: parseDynamicTheme(newSessionState),
|
||||
logs: startLogs.length > 0 ? startLogs : undefined,
|
||||
visitedEdges,
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,12 +355,13 @@ const getResult = async ({
|
||||
|
||||
const parseDynamicThemeInState = (theme: Theme) => {
|
||||
const hostAvatarUrl =
|
||||
theme.chat.hostAvatar?.isEnabled ?? true
|
||||
? theme.chat.hostAvatar?.url
|
||||
theme.chat?.hostAvatar?.isEnabled ?? defaultTheme.chat.hostAvatar.isEnabled
|
||||
? theme.chat?.hostAvatar?.url
|
||||
: undefined
|
||||
const guestAvatarUrl =
|
||||
theme.chat.guestAvatar?.isEnabled ?? false
|
||||
? theme.chat.guestAvatar?.url
|
||||
theme.chat?.guestAvatar?.isEnabled ??
|
||||
defaultTheme.chat.guestAvatar.isEnabled
|
||||
? theme.chat?.guestAvatar?.url
|
||||
: undefined
|
||||
if (!hostAvatarUrl?.startsWith('{{') && !guestAvatarUrl?.startsWith('{{'))
|
||||
return
|
||||
@ -361,28 +376,30 @@ const parseDynamicThemeInState = (theme: Theme) => {
|
||||
const parseStartClientSideAction = (
|
||||
typebot: StartTypebot
|
||||
): NonNullable<ChatReply['clientSideActions']>[number] | undefined => {
|
||||
const blocks = typebot.groups.flatMap((group) => group.blocks)
|
||||
const blocks = typebot.groups.flatMap<Block>((group) => group.blocks)
|
||||
const pixelBlocks = (
|
||||
blocks.filter(
|
||||
(block) =>
|
||||
block.type === IntegrationBlockType.PIXEL &&
|
||||
isNotEmpty(block.options.pixelId) &&
|
||||
block.options.isInitSkip !== true
|
||||
isNotEmpty(block.options?.pixelId) &&
|
||||
block.options?.isInitSkip !== true
|
||||
) as PixelBlock[]
|
||||
).map((pixelBlock) => pixelBlock.options.pixelId as string)
|
||||
).map((pixelBlock) => pixelBlock.options?.pixelId as string)
|
||||
|
||||
const startPropsToInject = {
|
||||
customHeadCode: isNotEmpty(typebot.settings.metadata.customHeadCode)
|
||||
? sanitizeAndParseHeadCode(typebot.settings.metadata.customHeadCode)
|
||||
customHeadCode: isNotEmpty(typebot.settings.metadata?.customHeadCode)
|
||||
? sanitizeAndParseHeadCode(
|
||||
typebot.settings.metadata?.customHeadCode as string
|
||||
)
|
||||
: undefined,
|
||||
gtmId: typebot.settings.metadata.googleTagManagerId,
|
||||
gtmId: typebot.settings.metadata?.googleTagManagerId,
|
||||
googleAnalyticsId: (
|
||||
blocks.find(
|
||||
(block) =>
|
||||
block.type === IntegrationBlockType.GOOGLE_ANALYTICS &&
|
||||
block.options.trackingId
|
||||
block.options?.trackingId
|
||||
) as GoogleAnalyticsBlock | undefined
|
||||
)?.options.trackingId,
|
||||
)?.options?.trackingId,
|
||||
pixelIds: pixelBlocks.length > 0 ? pixelBlocks : undefined,
|
||||
}
|
||||
|
||||
@ -403,8 +420,10 @@ const sanitizeAndParseTheme = (
|
||||
theme: Theme,
|
||||
{ variables }: { variables: Variable[] }
|
||||
): Theme => ({
|
||||
general: deepParseVariables(variables)(theme.general),
|
||||
chat: deepParseVariables(variables)(theme.chat),
|
||||
general: theme.general
|
||||
? deepParseVariables(variables)(theme.general)
|
||||
: undefined,
|
||||
chat: theme.chat ? deepParseVariables(variables)(theme.chat) : undefined,
|
||||
customCss: theme.customCss
|
||||
? removeLiteBadgeCss(parseVariables(variables)(theme.customCss))
|
||||
: undefined,
|
||||
@ -421,3 +440,25 @@ const removeLiteBadgeCss = (code: string) => {
|
||||
const liteBadgeCssRegex = /.*#lite-badge.*{[\s\S][^{]*}/gm
|
||||
return code.replace(liteBadgeCssRegex, '')
|
||||
}
|
||||
|
||||
const convertStartTypebotToTypebotInSession = (
|
||||
typebot: StartTypebot,
|
||||
startVariables: Variable[]
|
||||
): TypebotInSession =>
|
||||
typebot.version === '6'
|
||||
? {
|
||||
version: typebot.version,
|
||||
id: typebot.id,
|
||||
groups: typebot.groups,
|
||||
edges: typebot.edges,
|
||||
variables: startVariables,
|
||||
events: typebot.events,
|
||||
}
|
||||
: {
|
||||
version: typebot.version,
|
||||
id: typebot.id,
|
||||
groups: typebot.groups,
|
||||
edges: typebot.edges,
|
||||
variables: startVariables,
|
||||
events: typebot.events,
|
||||
}
|
||||
|
Reference in New Issue
Block a user