♻️ Normalize data
This commit is contained in:
@ -8,26 +8,28 @@
|
||||
"dependencies": {
|
||||
"db": "*",
|
||||
"fast-equals": "^2.0.4",
|
||||
"models": "*",
|
||||
"react-frame-component": "^5.2.1",
|
||||
"react-scroll": "^1.8.4",
|
||||
"react-transition-group": "^4.4.2"
|
||||
"react-transition-group": "^4.4.2",
|
||||
"utils": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^21.0.1",
|
||||
"@rollup/plugin-node-resolve": "^13.1.1",
|
||||
"@rollup/plugin-node-resolve": "^13.1.3",
|
||||
"@rollup/plugin-typescript": "^8.3.0",
|
||||
"@types/react": "^17.0.38",
|
||||
"@types/react-scroll": "^1.8.3",
|
||||
"@types/react-transition-group": "^4.4.4",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"autoprefixer": "^10.4.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.4.5",
|
||||
"rollup": "^2.62.0",
|
||||
"rollup": "^2.63.0",
|
||||
"rollup-plugin-dts": "^4.1.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-postcss": "^4.0.2",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"tailwindcss": "^3.0.8",
|
||||
"tailwindcss": "^3.0.11",
|
||||
"typescript": "^4.5.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -1,21 +1,21 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Block, Step } from '../../models'
|
||||
import { animateScroll as scroll } from 'react-scroll'
|
||||
import { TransitionGroup, CSSTransition } from 'react-transition-group'
|
||||
import { ChatStep } from './ChatStep'
|
||||
import { AvatarSideContainer } from './AvatarSideContainer'
|
||||
import { HostAvatarsContext } from '../../contexts/HostAvatarsContext'
|
||||
import { Step, Table } from 'models'
|
||||
|
||||
type ChatBlockProps = {
|
||||
block: Block
|
||||
steps: Table<Step>
|
||||
onBlockEnd: (nextBlockId?: string) => void
|
||||
}
|
||||
|
||||
export const ChatBlock = ({ block, onBlockEnd }: ChatBlockProps) => {
|
||||
export const ChatBlock = ({ steps, onBlockEnd }: ChatBlockProps) => {
|
||||
const [displayedSteps, setDisplayedSteps] = useState<Step[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
setDisplayedSteps([block.steps[0]])
|
||||
setDisplayedSteps([steps.byId[steps.allIds[0]]])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
@ -33,10 +33,10 @@ export const ChatBlock = ({ block, onBlockEnd }: ChatBlockProps) => {
|
||||
const currentStep = [...displayedSteps].pop()
|
||||
if (
|
||||
currentStep?.target?.blockId ||
|
||||
displayedSteps.length === block.steps.length
|
||||
displayedSteps.length === steps.allIds.length
|
||||
)
|
||||
return onBlockEnd(currentStep?.target?.blockId)
|
||||
const nextStep = block.steps[displayedSteps.length]
|
||||
const nextStep = steps.byId[displayedSteps.length]
|
||||
if (nextStep) setDisplayedSteps([...displayedSteps, nextStep])
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useAnswers } from '../../../contexts/AnswersContext'
|
||||
import { useHostAvatars } from '../../../contexts/HostAvatarsContext'
|
||||
import { Step } from '../../../models'
|
||||
import { Step } from 'models'
|
||||
import { isTextInputStep, isTextStep } from '../../../services/utils'
|
||||
import { GuestBubble } from './bubbles/GuestBubble'
|
||||
import { HostMessageBubble } from './bubbles/HostMessageBubble'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { useHostAvatars } from '../../../../contexts/HostAvatarsContext'
|
||||
import { useTypebot } from '../../../../contexts/TypebotContext'
|
||||
import { StepType, TextStep } from '../../../../models'
|
||||
import { StepType, TextStep } from 'models'
|
||||
import { computeTypingTimeout } from '../../../../services/chat'
|
||||
import { TypingContent } from './TypingContent'
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { Answer, PublicTypebot } from '..'
|
||||
|
||||
import { Block } from '..'
|
||||
import { ChatBlock } from './ChatBlock/ChatBlock'
|
||||
import { useFrame } from 'react-frame-component'
|
||||
import { setCssVariablesValue } from '../services/theme'
|
||||
import { useAnswers } from '../contexts/AnswersContext'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { Answer, Block, PublicTypebot } from 'models'
|
||||
import { filterTable } from 'utils'
|
||||
|
||||
type Props = {
|
||||
typebot: PublicTypebot
|
||||
@ -28,14 +28,17 @@ export const ConversationContainer = ({
|
||||
|
||||
const displayNextBlock = (blockId?: string) => {
|
||||
if (!blockId) return onCompleted()
|
||||
const nextBlock = typebot.blocks.find((b) => b.id === blockId)
|
||||
const nextBlock = typebot.blocks.byId[blockId]
|
||||
if (!nextBlock) return onCompleted()
|
||||
onNewBlockVisible(blockId)
|
||||
setDisplayedBlocks([...displayedBlocks, nextBlock])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const firstBlockId = typebot.startBlock.steps[0].target?.blockId
|
||||
const blocks = typebot.blocks
|
||||
const firstBlockId =
|
||||
typebot.steps.byId[blocks.byId[blocks.allIds[0]].stepIds[0]].target
|
||||
?.blockId
|
||||
if (firstBlockId) displayNextBlock(firstBlockId)
|
||||
}, [])
|
||||
|
||||
@ -58,7 +61,7 @@ export const ConversationContainer = ({
|
||||
{displayedBlocks.map((block, idx) => (
|
||||
<ChatBlock
|
||||
key={block.id + idx}
|
||||
block={block}
|
||||
steps={filterTable(block.stepIds, typebot.steps)}
|
||||
onBlockEnd={displayNextBlock}
|
||||
/>
|
||||
))}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { Answer, BackgroundType, PublicTypebot } from '../models'
|
||||
import { TypebotContext } from '../contexts/TypebotContext'
|
||||
import Frame from 'react-frame-component'
|
||||
//@ts-ignore
|
||||
import style from '../assets/style.css'
|
||||
import { ConversationContainer } from './ConversationContainer'
|
||||
import { AnswersContext } from '../contexts/AnswersContext'
|
||||
import { Answer, BackgroundType, PublicTypebot } from 'models'
|
||||
|
||||
export type TypebotViewerProps = {
|
||||
typebot: PublicTypebot
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Answer } from '../models'
|
||||
import { Answer } from 'models'
|
||||
import React, { createContext, ReactNode, useContext, useState } from 'react'
|
||||
|
||||
const answersContext = createContext<{
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { PublicTypebot } from 'models'
|
||||
import React, { createContext, ReactNode, useContext } from 'react'
|
||||
import { PublicTypebot } from '../models/publicTypebot'
|
||||
|
||||
const typebotContext = createContext<{
|
||||
typebot: PublicTypebot
|
||||
|
@ -1,3 +1 @@
|
||||
export * from './components/TypebotViewer'
|
||||
export * from './models'
|
||||
export { parseNewTypebot } from './services/utils'
|
||||
|
@ -1,9 +0,0 @@
|
||||
import { Answer as AnswerFromPrisma } from 'db'
|
||||
|
||||
export type Answer = Omit<AnswerFromPrisma, 'resultId' | 'createdAt'>
|
||||
|
||||
export type Stats = {
|
||||
totalViews: number
|
||||
totalStarts: number
|
||||
completionRate: number
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
export * from './typebot'
|
||||
export * from './publicTypebot'
|
||||
export * from './result'
|
||||
export * from './answer'
|
@ -1,12 +0,0 @@
|
||||
import { PublicTypebot as PublicTypebotFromPrisma } from 'db'
|
||||
import { Block, Settings, StartBlock, Theme } from '.'
|
||||
|
||||
export type PublicTypebot = Omit<
|
||||
PublicTypebotFromPrisma,
|
||||
'blocks' | 'startBlock' | 'theme' | 'settings'
|
||||
> & {
|
||||
blocks: Block[]
|
||||
startBlock: StartBlock
|
||||
theme: Theme
|
||||
settings: Settings
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
import { Result as ResultFromPrisma } from 'db'
|
||||
|
||||
export type Result = Omit<ResultFromPrisma, 'createdAt'> & { createdAt: string }
|
@ -1,87 +0,0 @@
|
||||
import { Typebot as TypebotFromPrisma } from 'db'
|
||||
|
||||
export type Typebot = Omit<
|
||||
TypebotFromPrisma,
|
||||
'blocks' | 'startBlock' | 'theme' | 'settings'
|
||||
> & {
|
||||
blocks: Block[]
|
||||
startBlock: StartBlock
|
||||
theme: Theme
|
||||
settings: Settings
|
||||
}
|
||||
|
||||
export type StartBlock = {
|
||||
id: `start-block`
|
||||
graphCoordinates: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
title: string
|
||||
steps: [StartStep]
|
||||
}
|
||||
|
||||
export type StartStep = {
|
||||
id: 'start-step'
|
||||
blockId: 'start-block'
|
||||
target?: Target
|
||||
type: StepType.START
|
||||
label: string
|
||||
}
|
||||
|
||||
export type Block = {
|
||||
id: string
|
||||
title: string
|
||||
steps: Step[]
|
||||
graphCoordinates: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
}
|
||||
|
||||
export enum StepType {
|
||||
START = 'start',
|
||||
TEXT = 'text',
|
||||
TEXT_INPUT = 'text input',
|
||||
}
|
||||
|
||||
export type Target = { blockId: string; stepId?: string }
|
||||
|
||||
export type Step = BubbleStep | InputStep
|
||||
export type BubbleStep = TextStep
|
||||
export type InputStep = TextInputStep
|
||||
export type StepBase = { id: string; blockId: string; target?: Target }
|
||||
export type TextStep = StepBase & {
|
||||
type: StepType.TEXT
|
||||
content: { html: string; richText: unknown[]; plainText: string }
|
||||
}
|
||||
export type TextInputStep = StepBase & {
|
||||
type: StepType.TEXT_INPUT
|
||||
}
|
||||
|
||||
export type Theme = {
|
||||
general: {
|
||||
font: string
|
||||
background: Background
|
||||
}
|
||||
}
|
||||
|
||||
export enum BackgroundType {
|
||||
COLOR = 'Color',
|
||||
IMAGE = 'Image',
|
||||
NONE = 'None',
|
||||
}
|
||||
|
||||
export type Background = {
|
||||
type: BackgroundType
|
||||
content: string
|
||||
}
|
||||
|
||||
export type Settings = {
|
||||
typingEmulation: TypingEmulationSettings
|
||||
}
|
||||
|
||||
export type TypingEmulationSettings = {
|
||||
enabled: boolean
|
||||
speed: number
|
||||
maxDelay: number
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { TypingEmulationSettings } from '../models'
|
||||
import { TypingEmulationSettings } from 'models'
|
||||
|
||||
export const computeTypingTimeout = (
|
||||
bubbleContent: string,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BackgroundType, Theme } from '../models'
|
||||
import { BackgroundType, Theme } from 'models'
|
||||
|
||||
const cssVariableNames = {
|
||||
container: {
|
||||
|
@ -1,55 +1,7 @@
|
||||
import { Prisma } from 'db'
|
||||
import {
|
||||
Step,
|
||||
TextStep,
|
||||
StepType,
|
||||
TextInputStep,
|
||||
BackgroundType,
|
||||
Settings,
|
||||
StartBlock,
|
||||
Theme,
|
||||
} from '../models'
|
||||
import { Step, TextStep, StepType, TextInputStep } from 'models'
|
||||
|
||||
export const isTextStep = (step: Step): step is TextStep =>
|
||||
step.type === StepType.TEXT
|
||||
|
||||
export const isTextInputStep = (step: Step): step is TextInputStep =>
|
||||
step.type === StepType.TEXT_INPUT
|
||||
|
||||
export const parseNewTypebot = ({
|
||||
ownerId,
|
||||
folderId,
|
||||
name,
|
||||
}: {
|
||||
ownerId: string
|
||||
folderId: string | null
|
||||
name: string
|
||||
}): Prisma.TypebotUncheckedCreateInput => {
|
||||
const startBlock: StartBlock = {
|
||||
id: 'start-block',
|
||||
title: 'Start',
|
||||
graphCoordinates: { x: 0, y: 0 },
|
||||
steps: [
|
||||
{
|
||||
id: 'start-step',
|
||||
blockId: 'start-block',
|
||||
label: 'Form starts here',
|
||||
type: StepType.START,
|
||||
},
|
||||
],
|
||||
}
|
||||
const theme: Theme = {
|
||||
general: {
|
||||
font: 'Open Sans',
|
||||
background: { type: BackgroundType.NONE, content: '#ffffff' },
|
||||
},
|
||||
}
|
||||
const settings: Settings = {
|
||||
typingEmulation: {
|
||||
enabled: true,
|
||||
speed: 300,
|
||||
maxDelay: 1.5,
|
||||
},
|
||||
}
|
||||
return { folderId, name, ownerId, startBlock, theme, settings }
|
||||
}
|
||||
|
Reference in New Issue
Block a user