2021-12-22 14:59:07 +01:00
|
|
|
import React, { useEffect, useRef, useState } from 'react'
|
|
|
|
|
|
|
|
import { ChatBlock } from './ChatBlock/ChatBlock'
|
2021-12-23 09:37:42 +01:00
|
|
|
import { useFrame } from 'react-frame-component'
|
|
|
|
import { setCssVariablesValue } from '../services/theme'
|
2021-12-29 10:22:26 +01:00
|
|
|
import { useAnswers } from '../contexts/AnswersContext'
|
|
|
|
import { deepEqual } from 'fast-equals'
|
2022-03-01 07:13:09 +01:00
|
|
|
import { Answer, Block, Edge, Theme, VariableWithValue } from 'models'
|
2022-02-17 16:08:01 +01:00
|
|
|
import { byId, isNotDefined } from 'utils'
|
2022-02-07 08:05:53 +01:00
|
|
|
import { animateScroll as scroll } from 'react-scroll'
|
2022-02-10 10:25:38 +01:00
|
|
|
import { useTypebot } from 'contexts/TypebotContext'
|
2021-12-22 14:59:07 +01:00
|
|
|
|
2021-12-29 10:22:26 +01:00
|
|
|
type Props = {
|
2022-02-10 10:25:38 +01:00
|
|
|
theme: Theme
|
2022-02-04 19:00:08 +01:00
|
|
|
onNewBlockVisible: (edge: Edge) => void
|
2021-12-30 10:24:16 +01:00
|
|
|
onNewAnswer: (answer: Answer) => void
|
2021-12-29 10:22:26 +01:00
|
|
|
onCompleted: () => void
|
2022-02-17 16:08:01 +01:00
|
|
|
onVariablesPrefilled?: (prefilledVariables: VariableWithValue[]) => void
|
2021-12-29 10:22:26 +01:00
|
|
|
}
|
2021-12-22 14:59:07 +01:00
|
|
|
export const ConversationContainer = ({
|
2022-02-10 10:25:38 +01:00
|
|
|
theme,
|
2021-12-29 10:22:26 +01:00
|
|
|
onNewBlockVisible,
|
2021-12-30 10:24:16 +01:00
|
|
|
onNewAnswer,
|
2021-12-29 10:22:26 +01:00
|
|
|
onCompleted,
|
2022-02-17 16:08:01 +01:00
|
|
|
onVariablesPrefilled,
|
2021-12-29 10:22:26 +01:00
|
|
|
}: Props) => {
|
2022-02-17 10:46:04 +01:00
|
|
|
const { typebot, updateVariableValue } = useTypebot()
|
2021-12-23 09:37:42 +01:00
|
|
|
const { document: frameDocument } = useFrame()
|
2022-01-15 17:30:20 +01:00
|
|
|
const [displayedBlocks, setDisplayedBlocks] = useState<
|
2022-03-01 07:13:09 +01:00
|
|
|
{ block: Block; startStepIndex: number }[]
|
2022-01-15 17:30:20 +01:00
|
|
|
>([])
|
2021-12-30 10:24:16 +01:00
|
|
|
const [localAnswer, setLocalAnswer] = useState<Answer | undefined>()
|
2022-02-22 06:55:15 +01:00
|
|
|
const {
|
|
|
|
resultValues: { answers },
|
|
|
|
setPrefilledVariables,
|
|
|
|
} = useAnswers()
|
2021-12-22 14:59:07 +01:00
|
|
|
const bottomAnchor = useRef<HTMLDivElement | null>(null)
|
2022-02-07 08:05:53 +01:00
|
|
|
const scrollableContainer = useRef<HTMLDivElement | null>(null)
|
2021-12-22 14:59:07 +01:00
|
|
|
|
2022-01-19 18:54:49 +01:00
|
|
|
const displayNextBlock = (edgeId?: string) => {
|
2022-02-04 19:00:08 +01:00
|
|
|
const nextEdge = typebot.edges.find(byId(edgeId))
|
|
|
|
if (!nextEdge) return onCompleted()
|
|
|
|
const nextBlock = typebot.blocks.find(byId(nextEdge.to.blockId))
|
2021-12-29 10:22:26 +01:00
|
|
|
if (!nextBlock) return onCompleted()
|
2022-02-04 19:00:08 +01:00
|
|
|
const startStepIndex = nextEdge.to.stepId
|
|
|
|
? nextBlock.steps.findIndex(byId(nextEdge.to.stepId))
|
|
|
|
: 0
|
|
|
|
onNewBlockVisible(nextEdge)
|
|
|
|
setDisplayedBlocks([
|
|
|
|
...displayedBlocks,
|
|
|
|
{ block: nextBlock, startStepIndex },
|
|
|
|
])
|
2021-12-22 14:59:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
useEffect(() => {
|
2022-02-17 16:08:01 +01:00
|
|
|
const prefilledVariables = injectUrlParamsIntoVariables()
|
2022-02-22 06:55:15 +01:00
|
|
|
if (onVariablesPrefilled) {
|
|
|
|
onVariablesPrefilled(prefilledVariables)
|
|
|
|
setPrefilledVariables(prefilledVariables)
|
|
|
|
}
|
2022-02-04 19:00:08 +01:00
|
|
|
displayNextBlock(typebot.blocks[0].steps[0].outgoingEdgeId)
|
2022-01-25 18:19:37 +01:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2021-12-22 14:59:07 +01:00
|
|
|
}, [])
|
|
|
|
|
2022-02-17 10:46:04 +01:00
|
|
|
const injectUrlParamsIntoVariables = () => {
|
|
|
|
const urlParams = new URLSearchParams(location.search)
|
2022-02-17 16:08:01 +01:00
|
|
|
const prefilledVariables: VariableWithValue[] = []
|
2022-02-17 10:46:04 +01:00
|
|
|
urlParams.forEach((value, key) => {
|
|
|
|
const matchingVariable = typebot.variables.find(
|
|
|
|
(v) => v.name.toLowerCase() === key.toLowerCase()
|
|
|
|
)
|
2022-02-17 16:08:01 +01:00
|
|
|
if (isNotDefined(matchingVariable)) return
|
|
|
|
updateVariableValue(matchingVariable?.id, value)
|
|
|
|
prefilledVariables.push({ ...matchingVariable, value })
|
2022-02-17 10:46:04 +01:00
|
|
|
})
|
2022-02-17 16:08:01 +01:00
|
|
|
return prefilledVariables
|
2022-02-17 10:46:04 +01:00
|
|
|
}
|
|
|
|
|
2021-12-23 09:37:42 +01:00
|
|
|
useEffect(() => {
|
2022-02-10 10:25:38 +01:00
|
|
|
setCssVariablesValue(theme, frameDocument.body.style)
|
|
|
|
}, [theme, frameDocument])
|
2021-12-23 09:37:42 +01:00
|
|
|
|
2021-12-29 10:22:26 +01:00
|
|
|
useEffect(() => {
|
2021-12-30 10:24:16 +01:00
|
|
|
const answer = [...answers].pop()
|
|
|
|
if (!answer || deepEqual(localAnswer, answer)) return
|
|
|
|
setLocalAnswer(answer)
|
|
|
|
onNewAnswer(answer)
|
2022-01-25 18:19:37 +01:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
2021-12-29 10:22:26 +01:00
|
|
|
}, [answers])
|
|
|
|
|
2022-02-07 08:05:53 +01:00
|
|
|
const autoScrollToBottom = () => {
|
|
|
|
if (!scrollableContainer.current) return
|
|
|
|
scroll.scrollToBottom({
|
|
|
|
duration: 500,
|
|
|
|
container: scrollableContainer.current,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-12-22 14:59:07 +01:00
|
|
|
return (
|
|
|
|
<div
|
2022-02-07 08:05:53 +01:00
|
|
|
ref={scrollableContainer}
|
2021-12-22 14:59:07 +01:00
|
|
|
className="overflow-y-scroll w-full lg:w-3/4 min-h-full rounded lg:px-5 px-3 pt-10 relative scrollable-container typebot-chat-view"
|
|
|
|
>
|
2022-01-15 17:30:20 +01:00
|
|
|
{displayedBlocks.map((displayedBlock, idx) => (
|
2021-12-22 14:59:07 +01:00
|
|
|
<ChatBlock
|
2022-01-15 17:30:20 +01:00
|
|
|
key={displayedBlock.block.id + idx}
|
2022-02-04 19:00:08 +01:00
|
|
|
steps={displayedBlock.block.steps}
|
|
|
|
startStepIndex={displayedBlock.startStepIndex}
|
2022-02-07 08:05:53 +01:00
|
|
|
onScroll={autoScrollToBottom}
|
2021-12-22 14:59:07 +01:00
|
|
|
onBlockEnd={displayNextBlock}
|
|
|
|
/>
|
|
|
|
))}
|
|
|
|
{/* We use a block to simulate padding because it makes iOS scroll flicker */}
|
2022-02-07 08:05:53 +01:00
|
|
|
<div className="w-full h-32" ref={bottomAnchor} />
|
2021-12-22 14:59:07 +01:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|