♻️ Introduce typebot v6 with events (#1013)

Closes #885
This commit is contained in:
Baptiste Arnaud
2023-11-08 15:34:16 +01:00
committed by GitHub
parent 68e4fc71fb
commit 35300eaf34
634 changed files with 58971 additions and 31449 deletions

View File

@@ -7,16 +7,16 @@ import {
useColorModeValue,
} from '@chakra-ui/react'
import { ToolIcon, TemplateIcon, DownloadIcon } from '@/components/icons'
import { Typebot } from '@typebot.io/schemas'
import { useRouter } from 'next/router'
import React, { useState } from 'react'
import { ImportTypebotFromFileButton } from './ImportTypebotFromFileButton'
import { TemplatesModal } from './TemplatesModal'
import { useWorkspace } from '@/features/workspace/WorkspaceProvider'
import { useUser } from '@/features/account/hooks/useUser'
import { useToast } from '@/hooks/useToast'
import { trpc } from '@/lib/trpc'
import { useTranslate } from '@tolgee/react'
import { Typebot } from '@typebot.io/schemas'
import { TemplatesModal } from './TemplatesModal'
export const CreateNewTypebotButtons = () => {
const { t } = useTranslate()
@@ -29,12 +29,41 @@ export const CreateNewTypebotButtons = () => {
const { showToast } = useToast()
const { mutate } = trpc.typebot.createTypebot.useMutation({
const { mutate: createTypebot } = trpc.typebot.createTypebot.useMutation({
onMutate: () => {
setIsLoading(true)
},
onError: (error) => {
showToast({ description: error.message })
showToast({
title: 'Failed to create bot',
description: error.message,
})
},
onSuccess: (data) => {
router.push({
pathname: `/typebots/${data.typebot.id}/edit`,
query:
router.query.isFirstBot === 'true'
? {
isFirstBot: 'true',
}
: {},
})
},
onSettled: () => {
setIsLoading(false)
},
})
const { mutate: importTypebot } = trpc.typebot.importTypebot.useMutation({
onMutate: () => {
setIsLoading(true)
},
onError: (error) => {
showToast({
title: 'Failed to import bot',
description: error.message,
})
},
onSuccess: (data) => {
router.push({
@@ -55,19 +84,21 @@ export const CreateNewTypebotButtons = () => {
const handleCreateSubmit = async (typebot?: Typebot) => {
if (!user || !workspace) return
const folderId = router.query.folderId?.toString() ?? null
mutate({
workspaceId: workspace.id,
typebot: {
...(typebot
? {
...typebot,
publicId: undefined,
customDomain: undefined,
}
: {}),
folderId,
},
})
if (typebot)
importTypebot({
workspaceId: workspace.id,
typebot: {
...typebot,
folderId,
},
})
else
createTypebot({
workspaceId: workspace.id,
typebot: {
folderId,
},
})
}
return (
@@ -130,6 +161,7 @@ export const CreateNewTypebotButtons = () => {
isOpen={isOpen}
onClose={onClose}
onTypebotChoose={handleCreateSubmit}
isLoading={isLoading}
/>
</VStack>
)

View File

@@ -1,9 +1,7 @@
import { useToast } from '@/hooks/useToast'
import { Button, ButtonProps, chakra } from '@chakra-ui/react'
import { Typebot, typebotCreateSchema } from '@typebot.io/schemas'
import { preprocessTypebot } from '@typebot.io/schemas/features/typebot/helpers/preprocessTypebot'
import { Typebot } from '@typebot.io/schemas'
import React, { ChangeEvent } from 'react'
import { z } from 'zod'
import { useTranslate } from '@tolgee/react'
type Props = {
@@ -22,10 +20,12 @@ export const ImportTypebotFromFileButton = ({
const file = e.target.files[0]
const fileContent = await readFile(file)
try {
const typebot = z
.preprocess(preprocessTypebot, typebotCreateSchema)
.parse(JSON.parse(fileContent))
onNewTypebot(typebot as Typebot)
const typebot = JSON.parse(fileContent)
onNewTypebot({
...typebot,
events: typebot.events ?? null,
icon: typebot.icon ?? null,
} as Typebot)
} catch (err) {
console.error(err)
showToast({

View File

@@ -25,17 +25,21 @@ type Props = {
isOpen: boolean
onClose: () => void
onTypebotChoose: (typebot: Typebot) => void
isLoading: boolean
}
export const TemplatesModal = ({ isOpen, onClose, onTypebotChoose }: Props) => {
export const TemplatesModal = ({
isOpen,
onClose,
onTypebotChoose,
isLoading,
}: Props) => {
const { t } = useTranslate()
const templateCardBackgroundColor = useColorModeValue('white', 'gray.800')
const [typebot, setTypebot] = useState<Typebot>()
const [selectedTemplate, setSelectedTemplate] = useState<TemplateProps>(
templates[0]
)
const [isLoading, setIsLoading] = useState(false)
const { showToast } = useToast()
const fetchTemplate = useCallback(
@@ -55,10 +59,9 @@ export const TemplatesModal = ({ isOpen, onClose, onTypebotChoose }: Props) => {
fetchTemplate(templates[0])
}, [fetchTemplate])
const onUseThisTemplateClick = () => {
const onUseThisTemplateClick = async () => {
if (!typebot) return
onTypebotChoose(typebot)
setIsLoading(true)
}
return (

View File

@@ -106,7 +106,6 @@ export const templates: TemplateProps[] = [
emoji: '🦾',
fileName: 'lead-gen-ai.json',
category: 'marketing',
isNew: true,
description:
'You are a marketing agency and this bot allows you generate new leads interested in your services. An AI block is used to dig deeper into the user needs.',
},
@@ -115,7 +114,6 @@ export const templates: TemplateProps[] = [
emoji: '🐶',
fileName: 'dog-insurance-offer.json',
category: 'marketing',
isNew: true,
description:
'You are a dog insurance company. This bot allows you to collect information about the dog and provide a quote.',
},

View File

@@ -8,7 +8,7 @@ test.describe.parallel('Templates page', () => {
page.locator('button >> text="Settings & Members"')
).toBeEnabled()
await page.click('text=Start from scratch')
await expect(page).toHaveURL(new RegExp(`/edit`))
await expect(page).toHaveURL(new RegExp(`/edit`), { timeout: 20000 })
})
test('From file should import correctly', async ({ page }) => {
@@ -18,7 +18,7 @@ test.describe.parallel('Templates page', () => {
'input[type="file"]',
getTestAsset('typebots/singleChoiceTarget.json')
)
await expect(page).toHaveURL(new RegExp(`/edit`))
await expect(page).toHaveURL(new RegExp(`/edit`), { timeout: 20000 })
})
test('Templates should be previewable and usable', async ({ page }) => {