2
0

♻️ (bot) Change to features-centric folder structure

This commit is contained in:
Baptiste Arnaud
2022-11-15 14:59:34 +01:00
committed by Baptiste Arnaud
parent a5c8a8a95c
commit 972094425a
92 changed files with 1245 additions and 943 deletions

View File

@ -0,0 +1,83 @@
import { safeStringify } from '@/features/variables'
import {
Answer,
ResultValues,
VariableWithUnknowValue,
VariableWithValue,
} from 'models'
import React, { createContext, ReactNode, useContext, useState } from 'react'
const answersContext = createContext<{
resultId?: string
resultValues: ResultValues
addAnswer: (
answer: Answer & { uploadedFiles: boolean }
) => Promise<void> | undefined
updateVariables: (variables: VariableWithUnknowValue[]) => void
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
}>({})
export const AnswersProvider = ({
children,
resultId,
onNewAnswer,
onVariablesUpdated,
}: {
resultId?: string
onNewAnswer: (
answer: Answer & { uploadedFiles: boolean }
) => Promise<void> | undefined
onVariablesUpdated?: (variables: VariableWithValue[]) => void
children: ReactNode
}) => {
const [resultValues, setResultValues] = useState<ResultValues>({
answers: [],
variables: [],
createdAt: new Date().toISOString(),
})
const addAnswer = (answer: Answer & { uploadedFiles: boolean }) => {
setResultValues((resultValues) => ({
...resultValues,
answers: [...resultValues.answers, answer],
}))
return onNewAnswer && onNewAnswer(answer)
}
const updateVariables = (newVariables: VariableWithUnknowValue[]) => {
const serializedNewVariables = newVariables.map((variable) => ({
...variable,
value: safeStringify(variable.value),
})) as VariableWithValue[]
setResultValues((resultValues) => {
const updatedVariables = [
...resultValues.variables.filter((v) =>
serializedNewVariables.every((variable) => variable.id !== v.id)
),
...serializedNewVariables,
]
if (onVariablesUpdated) onVariablesUpdated(updatedVariables)
return {
...resultValues,
variables: updatedVariables,
}
})
}
return (
<answersContext.Provider
value={{
resultId,
resultValues,
addAnswer,
updateVariables,
}}
>
{children}
</answersContext.Provider>
)
}
export const useAnswers = () => useContext(answersContext)

View File

@ -0,0 +1,28 @@
import React, { createContext, ReactNode, useContext } from 'react'
const chatContext = createContext<{
scroll: () => void
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
}>({})
export const ChatProvider = ({
children,
onScroll,
}: {
children: ReactNode
onScroll: () => void
}) => {
const scroll = onScroll
return (
<chatContext.Provider
value={{
scroll,
}}
>
{children}
</chatContext.Provider>
)
}
export const useChat = () => useContext(chatContext)

View File

@ -0,0 +1,155 @@
import { TypebotViewerProps } from '@/components/TypebotViewer'
import { safeStringify } from '@/features/variables'
import { sendEventToParent } from '@/utils/chat'
import { Log } from 'db'
import { Edge, PublicTypebot, Typebot } from 'models'
import React, {
createContext,
ReactNode,
useContext,
useEffect,
useState,
} from 'react'
export type LinkedTypebot = Pick<
PublicTypebot | Typebot,
'id' | 'groups' | 'variables' | 'edges'
>
export type LinkedTypebotQueue = {
typebotId: string
edgeId: string
}[]
const typebotContext = createContext<{
currentTypebotId: string
typebot: TypebotViewerProps['typebot']
linkedTypebots: LinkedTypebot[]
apiHost: string
isPreview: boolean
linkedBotQueue: LinkedTypebotQueue
isLoading: boolean
setCurrentTypebotId: (id: string) => void
updateVariableValue: (variableId: string, value: unknown) => void
createEdge: (edge: Edge) => void
injectLinkedTypebot: (typebot: Typebot | PublicTypebot) => LinkedTypebot
popEdgeIdFromLinkedTypebotQueue: () => void
pushEdgeIdInLinkedTypebotQueue: (bot: {
typebotId: string
edgeId: string
}) => void
onNewLog: (log: Omit<Log, 'id' | 'createdAt' | 'resultId'>) => void
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
}>({})
export const TypebotProvider = ({
children,
typebot,
apiHost,
isPreview,
isLoading,
onNewLog,
}: {
children: ReactNode
typebot: TypebotViewerProps['typebot']
apiHost: string
isLoading: boolean
isPreview: boolean
onNewLog: (log: Omit<Log, 'id' | 'createdAt' | 'resultId'>) => void
}) => {
const [localTypebot, setLocalTypebot] =
useState<TypebotViewerProps['typebot']>(typebot)
const [linkedTypebots, setLinkedTypebots] = useState<LinkedTypebot[]>([])
const [currentTypebotId, setCurrentTypebotId] = useState(typebot.typebotId)
const [linkedBotQueue, setLinkedBotQueue] = useState<LinkedTypebotQueue>([])
useEffect(() => {
setLocalTypebot((localTypebot) => ({
...localTypebot,
theme: typebot.theme,
settings: typebot.settings,
}))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [typebot.theme, typebot.settings])
const updateVariableValue = (variableId: string, value: unknown) => {
const formattedValue = safeStringify(value)
sendEventToParent({
newVariableValue: {
name:
typebot.variables.find((variable) => variable.id === variableId)
?.name ?? '',
value: formattedValue ?? '',
},
})
setLocalTypebot((typebot) => ({
...typebot,
variables: typebot.variables.map((v) =>
v.id === variableId ? { ...v, value: formattedValue } : v
),
}))
}
const createEdge = (edge: Edge) => {
setLocalTypebot((typebot) => ({
...typebot,
edges: [...typebot.edges, edge],
}))
}
const injectLinkedTypebot = (typebot: Typebot | PublicTypebot) => {
const typebotToInject = {
id: 'typebotId' in typebot ? typebot.typebotId : typebot.id,
groups: typebot.groups,
edges: typebot.edges,
variables: typebot.variables,
}
setLinkedTypebots((typebots) => [...typebots, typebotToInject])
const updatedTypebot = {
...localTypebot,
groups: [...localTypebot.groups, ...typebotToInject.groups],
variables: [...localTypebot.variables, ...typebotToInject.variables],
edges: [...localTypebot.edges, ...typebotToInject.edges],
}
setLocalTypebot(updatedTypebot)
return typebotToInject
}
const pushEdgeIdInLinkedTypebotQueue = (bot: {
typebotId: string
edgeId: string
}) => setLinkedBotQueue((queue) => [...queue, bot])
const popEdgeIdFromLinkedTypebotQueue = () => {
setLinkedBotQueue((queue) => queue.slice(1))
setCurrentTypebotId(linkedBotQueue[0].typebotId)
}
return (
<typebotContext.Provider
value={{
typebot: localTypebot,
linkedTypebots,
apiHost,
isPreview,
updateVariableValue,
createEdge,
injectLinkedTypebot,
onNewLog,
linkedBotQueue,
isLoading,
pushEdgeIdInLinkedTypebotQueue,
popEdgeIdFromLinkedTypebotQueue,
currentTypebotId,
setCurrentTypebotId,
}}
>
{children}
</typebotContext.Provider>
)
}
export const useTypebot = () => useContext(typebotContext)