(api) Add CRUD typebot endpoints

Closes #320, closes #696
This commit is contained in:
Baptiste Arnaud
2023-08-17 09:39:11 +02:00
parent 019f72ac7e
commit 454d320c6b
78 changed files with 25014 additions and 1073 deletions

View File

@@ -24,8 +24,8 @@ import { useRouter } from 'next/router'
import React, { useMemo } from 'react'
import { deleteFolderQuery } from '../queries/deleteFolderQuery'
import { useToast } from '@/hooks/useToast'
import { updateFolderQuery } from '../queries/updateFolderQuery'
import { useI18n, useScopedI18n } from '@/locales'
import { updateFolderQuery } from '../queries/updateFolderQuery'
export const FolderButton = ({
folder,

View File

@@ -15,7 +15,6 @@ import { BackButton } from './BackButton'
import { useWorkspace } from '@/features/workspace/WorkspaceProvider'
import { useToast } from '@/hooks/useToast'
import { useFolders } from '../hooks/useFolders'
import { patchTypebotQuery } from '../queries/patchTypebotQuery'
import { createFolderQuery } from '../queries/createFolderQuery'
import { CreateBotButton } from './CreateBotButton'
import { CreateFolderButton } from './CreateFolderButton'
@@ -25,6 +24,7 @@ import { TypebotCardOverlay } from './TypebotButtonOverlay'
import { useI18n } from '@/locales'
import { useTypebots } from '@/features/dashboard/hooks/useTypebots'
import { TypebotInDashboard } from '@/features/dashboard/types'
import { trpc } from '@/lib/trpc'
type Props = { folder: DashboardFolder | null }
@@ -65,6 +65,15 @@ export const FolderContent = ({ folder }: Props) => {
},
})
const { mutate: updateTypebot } = trpc.typebot.updateTypebot.useMutation({
onError: (error) => {
showToast({ description: error.message })
},
onSuccess: () => {
refetchTypebots()
},
})
const {
typebots,
isLoading: isTypebotLoading,
@@ -81,11 +90,12 @@ export const FolderContent = ({ folder }: Props) => {
const moveTypebotToFolder = async (typebotId: string, folderId: string) => {
if (!typebots) return
const { error } = await patchTypebotQuery(typebotId, {
folderId: folderId === 'root' ? null : folderId,
updateTypebot({
typebotId,
typebot: {
folderId: folderId === 'root' ? null : folderId,
},
})
if (error) showToast({ description: error.message })
refetchTypebots()
}
const handleCreateFolder = async () => {

View File

@@ -18,18 +18,13 @@ import { ConfirmModal } from '@/components/ConfirmModal'
import { GripIcon } from '@/components/icons'
import { useTypebotDnd } from '../TypebotDndProvider'
import { useDebounce } from 'use-debounce'
import { Plan } from '@typebot.io/prisma'
import { useWorkspace } from '@/features/workspace/WorkspaceProvider'
import { useToast } from '@/hooks/useToast'
import { MoreButton } from './MoreButton'
import { EmojiOrImageIcon } from '@/components/EmojiOrImageIcon'
import { deletePublishedTypebotQuery } from '@/features/publish/queries/deletePublishedTypebotQuery'
import { useScopedI18n } from '@/locales'
import { deleteTypebotQuery } from '@/features/dashboard/queries/deleteTypebotQuery'
import { getTypebotQuery } from '@/features/dashboard/queries/getTypebotQuery'
import { importTypebotQuery } from '@/features/dashboard/queries/importTypebotQuery'
import { TypebotInDashboard } from '@/features/dashboard/types'
import { isMobile } from '@/helpers/isMobile'
import { trpc, trpcVanilla } from '@/lib/trpc'
type Props = {
typebot: TypebotInDashboard
@@ -46,7 +41,6 @@ export const TypebotButton = ({
}: Props) => {
const scopedT = useScopedI18n('folders.typebotButton')
const router = useRouter()
const { workspace } = useWorkspace()
const { draggedTypebot } = useTypebotDnd()
const [draggedTypebotDebounced] = useDebounce(draggedTypebot, 200)
const {
@@ -57,6 +51,34 @@ export const TypebotButton = ({
const { showToast } = useToast()
const { mutate: createTypebot } = trpc.typebot.createTypebot.useMutation({
onError: (error) => {
showToast({ description: error.message })
},
onSuccess: ({ typebot }) => {
router.push(`/typebots/${typebot.id}/edit`)
},
})
const { mutate: deleteTypebot } = trpc.typebot.deleteTypebot.useMutation({
onError: (error) => {
showToast({ description: error.message })
},
onSuccess: () => {
onTypebotUpdated()
},
})
const { mutate: unpublishTypebot } =
trpc.typebot.unpublishTypebot.useMutation({
onError: (error) => {
showToast({ description: error.message })
},
onSuccess: () => {
onTypebotUpdated()
},
})
const handleTypebotClick = () => {
if (draggedTypebotDebounced) return
router.push(
@@ -68,28 +90,27 @@ export const TypebotButton = ({
const handleDeleteTypebotClick = async () => {
if (isReadOnly) return
const { error } = await deleteTypebotQuery(typebot.id)
if (error)
return showToast({
description: error.message,
})
onTypebotUpdated()
deleteTypebot({
typebotId: typebot.id,
})
}
const handleDuplicateClick = async (e: React.MouseEvent) => {
e.stopPropagation()
const { data } = await getTypebotQuery(typebot.id)
const typebotToDuplicate = data?.typebot
if (!typebotToDuplicate) return
const { data: createdTypebot, error } = await importTypebotQuery(
data.typebot,
workspace?.plan ?? Plan.FREE
)
if (error)
return showToast({
description: error.message,
const { typebot: typebotToDuplicate } =
await trpcVanilla.typebot.getTypebot.query({
typebotId: typebot.id,
})
if (createdTypebot) router.push(`/typebots/${createdTypebot?.id}/edit`)
if (!typebotToDuplicate) return
createTypebot({
workspaceId: typebotToDuplicate.workspaceId,
typebot: {
...typebotToDuplicate,
customDomain: undefined,
publicId: undefined,
name: duplicateName(typebotToDuplicate.name),
},
})
}
const handleDeleteClick = (e: React.MouseEvent) => {
@@ -100,12 +121,7 @@ export const TypebotButton = ({
const handleUnpublishClick = async (e: React.MouseEvent) => {
e.stopPropagation()
if (!typebot.publishedTypebotId) return
const { error } = await deletePublishedTypebotQuery({
publishedTypebotId: typebot.publishedTypebotId,
typebotId: typebot.id,
})
if (error) showToast({ description: error.message })
else onTypebotUpdated()
unpublishTypebot({ typebotId: typebot.id })
}
return (
@@ -205,3 +221,10 @@ export const TypebotButton = ({
</Button>
)
}
const duplicateName = (name: string | `${string} (${number})`) => {
const match = name.match(/^(.*) \((\d+)\)$/)
if (!match) return `${name} (1)`
const [, nameWithoutNumber, number] = match
return `${nameWithoutNumber} (${Number(number) + 1})`
}