@@ -52,9 +52,11 @@ export const TypebotHeader = () => {
|
||||
}, 1000)
|
||||
const { isOpen, onOpen } = useDisclosure()
|
||||
|
||||
const handleNameSubmit = (name: string) => updateTypebot({ name })
|
||||
const handleNameSubmit = (name: string) =>
|
||||
updateTypebot({ updates: { name } })
|
||||
|
||||
const handleChangeIcon = (icon: string) => updateTypebot({ icon })
|
||||
const handleChangeIcon = (icon: string) =>
|
||||
updateTypebot({ updates: { icon } })
|
||||
|
||||
const handlePreviewClick = async () => {
|
||||
setStartPreviewAtGroup(undefined)
|
||||
|
||||
@@ -5,11 +5,6 @@ import {
|
||||
createTypebots,
|
||||
importTypebotInDatabase,
|
||||
} from '@typebot.io/lib/playwright/databaseActions'
|
||||
import {
|
||||
waitForSuccessfulDeleteRequest,
|
||||
waitForSuccessfulPostRequest,
|
||||
waitForSuccessfulPutRequest,
|
||||
} from '@typebot.io/lib/playwright/testHelpers'
|
||||
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
|
||||
@@ -236,25 +231,13 @@ test('Published typebot menu should work', async ({ page }) => {
|
||||
await expect(page.locator("text='Start'")).toBeVisible()
|
||||
await expect(page.locator('button >> text="Published"')).toBeVisible()
|
||||
await page.click('[aria-label="Show published typebot menu"]')
|
||||
await Promise.all([
|
||||
waitForSuccessfulPutRequest(page),
|
||||
page.click('text="Close typebot to new responses"'),
|
||||
])
|
||||
await page.click('text="Close typebot to new responses"')
|
||||
await expect(page.locator('button >> text="Closed"')).toBeDisabled()
|
||||
await page.click('[aria-label="Show published typebot menu"]')
|
||||
await Promise.all([
|
||||
waitForSuccessfulPutRequest(page),
|
||||
page.click('text="Reopen typebot to new responses"'),
|
||||
])
|
||||
await page.click('text="Reopen typebot to new responses"')
|
||||
await expect(page.locator('button >> text="Published"')).toBeDisabled()
|
||||
await page.click('[aria-label="Show published typebot menu"]')
|
||||
await Promise.all([
|
||||
waitForSuccessfulDeleteRequest(page),
|
||||
page.click('button >> text="Unpublish typebot"'),
|
||||
])
|
||||
await Promise.all([
|
||||
waitForSuccessfulPostRequest(page),
|
||||
page.click('button >> text="Publish"'),
|
||||
])
|
||||
await page.click('button >> text="Unpublish typebot"')
|
||||
await page.click('button >> text="Publish"')
|
||||
await expect(page.locator('button >> text="Published"')).toBeVisible()
|
||||
})
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
LogicBlockType,
|
||||
PublicTypebot,
|
||||
Typebot,
|
||||
Webhook,
|
||||
} from '@typebot.io/schemas'
|
||||
import { LogicBlockType, PublicTypebot, Typebot } from '@typebot.io/schemas'
|
||||
import { Router, useRouter } from 'next/router'
|
||||
import {
|
||||
createContext,
|
||||
@@ -12,7 +7,6 @@ import {
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { isDefined, omit } from '@typebot.io/lib'
|
||||
import { edgesAction, EdgesActions } from './typebotActions/edges'
|
||||
@@ -22,21 +16,11 @@ import { blocksAction, BlocksActions } from './typebotActions/blocks'
|
||||
import { variablesAction, VariablesActions } from './typebotActions/variables'
|
||||
import { dequal } from 'dequal'
|
||||
import { useToast } from '@/hooks/useToast'
|
||||
import { useTypebotQuery } from '@/hooks/useTypebotQuery'
|
||||
import { useUndo } from '../hooks/useUndo'
|
||||
import { updateTypebotQuery } from '../queries/updateTypebotQuery'
|
||||
import { updateWebhookQuery } from '@/features/blocks/integrations/webhook/queries/updateWebhookQuery'
|
||||
import { useAutoSave } from '@/hooks/useAutoSave'
|
||||
import { createWebhookQuery } from '@/features/blocks/integrations/webhook/queries/createWebhookQuery'
|
||||
import { duplicateWebhookQuery } from '@/features/blocks/integrations/webhook/queries/duplicateWebhookQuery'
|
||||
import { parseDefaultPublicId } from '@/features/publish/helpers/parseDefaultPublicId'
|
||||
import { createPublishedTypebotQuery } from '@/features/publish/queries/createPublishedTypebotQuery'
|
||||
import { deletePublishedTypebotQuery } from '@/features/publish/queries/deletePublishedTypebotQuery'
|
||||
import { updatePublishedTypebotQuery } from '@/features/publish/queries/updatePublishedTypebotQuery'
|
||||
import { preventUserFromRefreshing } from '@/helpers/preventUserFromRefreshing'
|
||||
import { areTypebotsEqual } from '@/features/publish/helpers/areTypebotsEqual'
|
||||
import { isPublished as isPublishedHelper } from '@/features/publish/helpers/isPublished'
|
||||
import { convertTypebotToPublicTypebot } from '@/features/publish/helpers/convertTypebotToPublicTypebot'
|
||||
import { convertPublicTypebotToTypebot } from '@/features/publish/helpers/convertPublicTypebotToTypebot'
|
||||
import { trpc } from '@/lib/trpc'
|
||||
|
||||
@@ -66,23 +50,18 @@ const typebotContext = createContext<
|
||||
typebot?: Typebot
|
||||
publishedTypebot?: PublicTypebot
|
||||
linkedTypebots?: Pick<Typebot, 'id' | 'groups' | 'variables' | 'name'>[]
|
||||
webhooks: Webhook[]
|
||||
isReadOnly?: boolean
|
||||
isPublished: boolean
|
||||
isPublishing: boolean
|
||||
isSavingLoading: boolean
|
||||
save: () => Promise<void>
|
||||
save: () => Promise<Typebot | undefined>
|
||||
undo: () => void
|
||||
redo: () => void
|
||||
canRedo: boolean
|
||||
canUndo: boolean
|
||||
updateWebhook: (
|
||||
webhookId: string,
|
||||
webhook: Partial<Webhook>
|
||||
) => Promise<void>
|
||||
updateTypebot: (updates: UpdateTypebotPayload) => void
|
||||
publishTypebot: () => void
|
||||
unpublishTypebot: () => void
|
||||
updateTypebot: (props: {
|
||||
updates: UpdateTypebotPayload
|
||||
save?: boolean
|
||||
}) => Promise<Typebot | undefined>
|
||||
restorePublishedTypebot: () => void
|
||||
} & GroupsActions &
|
||||
BlocksActions &
|
||||
@@ -104,15 +83,48 @@ export const TypebotProvider = ({
|
||||
const { showToast } = useToast()
|
||||
|
||||
const {
|
||||
typebot,
|
||||
publishedTypebot,
|
||||
webhooks,
|
||||
isReadOnly,
|
||||
data: typebotData,
|
||||
isLoading: isFetchingTypebot,
|
||||
mutate,
|
||||
} = useTypebotQuery({
|
||||
typebotId,
|
||||
})
|
||||
refetch: refetchTypebot,
|
||||
} = trpc.typebot.getTypebot.useQuery(
|
||||
{ typebotId: typebotId as string },
|
||||
{
|
||||
enabled: isDefined(typebotId),
|
||||
onError: (error) =>
|
||||
showToast({
|
||||
title: 'Error while fetching typebot. Refresh the page.',
|
||||
description: error.message,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
const { data: publishedTypebotData } =
|
||||
trpc.typebot.getPublishedTypebot.useQuery(
|
||||
{ typebotId: typebotId as string },
|
||||
{
|
||||
enabled: isDefined(typebotId),
|
||||
onError: (error) =>
|
||||
showToast({
|
||||
title: 'Error while fetching published typebot',
|
||||
description: error.message,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
const { mutateAsync: updateTypebot, isLoading: isSaving } =
|
||||
trpc.typebot.updateTypebot.useMutation({
|
||||
onError: (error) =>
|
||||
showToast({
|
||||
title: 'Error while updating typebot',
|
||||
description: error.message,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
refetchTypebot()
|
||||
},
|
||||
})
|
||||
|
||||
const typebot = typebotData?.typebot
|
||||
const publishedTypebot = publishedTypebotData?.publishedTypebot ?? undefined
|
||||
|
||||
const [
|
||||
localTypebot,
|
||||
@@ -180,53 +192,17 @@ export const TypebotProvider = ({
|
||||
const typebotToSave = { ...localTypebot, ...updates }
|
||||
if (dequal(omit(typebot, 'updatedAt'), omit(typebotToSave, 'updatedAt')))
|
||||
return
|
||||
setIsSavingLoading(true)
|
||||
const { data, error } = await updateTypebotQuery(
|
||||
typebotToSave.id,
|
||||
typebotToSave
|
||||
)
|
||||
if (data?.typebot) setLocalTypebot({ ...data.typebot })
|
||||
setIsSavingLoading(false)
|
||||
if (error) {
|
||||
showToast({ title: error.name, description: error.message })
|
||||
return
|
||||
}
|
||||
mutate({
|
||||
setLocalTypebot({ ...typebotToSave })
|
||||
const { typebot: newTypebot } = await updateTypebot({
|
||||
typebotId: typebotToSave.id,
|
||||
typebot: typebotToSave,
|
||||
publishedTypebot,
|
||||
webhooks: webhooks ?? [],
|
||||
})
|
||||
window.removeEventListener('beforeunload', preventUserFromRefreshing)
|
||||
setLocalTypebot({ ...newTypebot })
|
||||
return newTypebot
|
||||
},
|
||||
[
|
||||
localTypebot,
|
||||
mutate,
|
||||
publishedTypebot,
|
||||
setLocalTypebot,
|
||||
showToast,
|
||||
typebot,
|
||||
webhooks,
|
||||
]
|
||||
[localTypebot, setLocalTypebot, typebot, updateTypebot]
|
||||
)
|
||||
|
||||
const savePublishedTypebot = async (newPublishedTypebot: PublicTypebot) => {
|
||||
if (!localTypebot) return
|
||||
setIsPublishing(true)
|
||||
const { error } = await updatePublishedTypebotQuery(
|
||||
newPublishedTypebot.id,
|
||||
newPublishedTypebot,
|
||||
localTypebot.workspaceId
|
||||
)
|
||||
setIsPublishing(false)
|
||||
if (error)
|
||||
return showToast({ title: error.name, description: error.message })
|
||||
mutate({
|
||||
typebot: localTypebot,
|
||||
publishedTypebot: newPublishedTypebot,
|
||||
webhooks: webhooks ?? [],
|
||||
})
|
||||
}
|
||||
|
||||
useAutoSave(
|
||||
{
|
||||
handler: saveTypebot,
|
||||
@@ -246,12 +222,10 @@ export const TypebotProvider = ({
|
||||
}
|
||||
}, [saveTypebot])
|
||||
|
||||
const [isSavingLoading, setIsSavingLoading] = useState(false)
|
||||
const [isPublishing, setIsPublishing] = useState(false)
|
||||
|
||||
const isPublished = useMemo(
|
||||
() =>
|
||||
isDefined(localTypebot) &&
|
||||
isDefined(localTypebot.publicId) &&
|
||||
isDefined(publishedTypebot) &&
|
||||
isPublishedHelper(localTypebot, publishedTypebot),
|
||||
[localTypebot, publishedTypebot]
|
||||
@@ -268,56 +242,18 @@ export const TypebotProvider = ({
|
||||
}
|
||||
}, [localTypebot, typebot])
|
||||
|
||||
const updateLocalTypebot = (updates: UpdateTypebotPayload) =>
|
||||
localTypebot && setLocalTypebot({ ...localTypebot, ...updates })
|
||||
|
||||
const publishTypebot = async () => {
|
||||
const updateLocalTypebot = async ({
|
||||
updates,
|
||||
save,
|
||||
}: {
|
||||
updates: UpdateTypebotPayload
|
||||
save?: boolean
|
||||
}) => {
|
||||
if (!localTypebot) return
|
||||
const newLocalTypebot = { ...localTypebot }
|
||||
if (!publishedTypebot || !localTypebot.publicId) {
|
||||
const newPublicId =
|
||||
localTypebot.publicId ??
|
||||
parseDefaultPublicId(localTypebot.name, localTypebot.id)
|
||||
newLocalTypebot.publicId = newPublicId
|
||||
await saveTypebot({ publicId: newPublicId })
|
||||
}
|
||||
if (publishedTypebot) {
|
||||
await savePublishedTypebot({
|
||||
...convertTypebotToPublicTypebot(newLocalTypebot),
|
||||
id: publishedTypebot.id,
|
||||
})
|
||||
} else {
|
||||
setIsPublishing(true)
|
||||
const { data, error } = await createPublishedTypebotQuery(
|
||||
{
|
||||
...omit(convertTypebotToPublicTypebot(newLocalTypebot), 'id'),
|
||||
},
|
||||
localTypebot.workspaceId
|
||||
)
|
||||
setIsPublishing(false)
|
||||
if (error)
|
||||
return showToast({ title: error.name, description: error.message })
|
||||
mutate({
|
||||
typebot: localTypebot,
|
||||
publishedTypebot: data,
|
||||
webhooks: webhooks ?? [],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const unpublishTypebot = async () => {
|
||||
if (!publishedTypebot || !localTypebot) return
|
||||
setIsPublishing(true)
|
||||
const { error } = await deletePublishedTypebotQuery({
|
||||
publishedTypebotId: publishedTypebot.id,
|
||||
typebotId: localTypebot.id,
|
||||
})
|
||||
setIsPublishing(false)
|
||||
if (error) showToast({ description: error.message })
|
||||
mutate({
|
||||
typebot: localTypebot,
|
||||
webhooks: webhooks ?? [],
|
||||
})
|
||||
const newTypebot = { ...localTypebot, ...updates }
|
||||
setLocalTypebot(newTypebot)
|
||||
if (save) await saveTypebot(newTypebot)
|
||||
return newTypebot
|
||||
}
|
||||
|
||||
const restorePublishedTypebot = () => {
|
||||
@@ -325,64 +261,6 @@ export const TypebotProvider = ({
|
||||
setLocalTypebot(
|
||||
convertPublicTypebotToTypebot(publishedTypebot, localTypebot)
|
||||
)
|
||||
return saveTypebot()
|
||||
}
|
||||
|
||||
const updateWebhook = useCallback(
|
||||
async (webhookId: string, updates: Partial<Webhook>) => {
|
||||
if (!typebot) return
|
||||
const { data } = await updateWebhookQuery({
|
||||
typebotId: typebot.id,
|
||||
webhookId,
|
||||
data: updates,
|
||||
})
|
||||
if (data)
|
||||
mutate({
|
||||
typebot,
|
||||
publishedTypebot,
|
||||
webhooks: (webhooks ?? []).map((w) =>
|
||||
w.id === webhookId ? data.webhook : w
|
||||
),
|
||||
})
|
||||
},
|
||||
[mutate, publishedTypebot, typebot, webhooks]
|
||||
)
|
||||
|
||||
const createWebhook = async (data: Partial<Webhook>) => {
|
||||
if (!typebot) return
|
||||
const response = await createWebhookQuery({
|
||||
typebotId: typebot.id,
|
||||
data,
|
||||
})
|
||||
if (!response.data?.webhook) return
|
||||
mutate({
|
||||
typebot,
|
||||
publishedTypebot,
|
||||
webhooks: (webhooks ?? []).concat(response.data?.webhook),
|
||||
})
|
||||
}
|
||||
|
||||
const duplicateWebhook = async (
|
||||
existingWebhookId: string,
|
||||
newWebhookId: string
|
||||
) => {
|
||||
if (!typebot) return
|
||||
const newWebhook = await duplicateWebhookQuery({
|
||||
existingIds: {
|
||||
typebotId: typebot.id,
|
||||
webhookId: existingWebhookId,
|
||||
},
|
||||
newIds: {
|
||||
typebotId: typebot.id,
|
||||
webhookId: newWebhookId,
|
||||
},
|
||||
})
|
||||
if (!newWebhook) return
|
||||
mutate({
|
||||
typebot,
|
||||
publishedTypebot,
|
||||
webhooks: (webhooks ?? []).concat(newWebhook),
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -391,29 +269,18 @@ export const TypebotProvider = ({
|
||||
typebot: localTypebot,
|
||||
publishedTypebot,
|
||||
linkedTypebots: linkedTypebotsData?.typebots ?? [],
|
||||
webhooks: webhooks ?? [],
|
||||
isReadOnly,
|
||||
isSavingLoading,
|
||||
isReadOnly: typebotData?.isReadOnly,
|
||||
isSavingLoading: isSaving,
|
||||
save: saveTypebot,
|
||||
undo,
|
||||
redo,
|
||||
canUndo,
|
||||
canRedo,
|
||||
publishTypebot,
|
||||
unpublishTypebot,
|
||||
isPublishing,
|
||||
isPublished,
|
||||
updateTypebot: updateLocalTypebot,
|
||||
restorePublishedTypebot,
|
||||
updateWebhook,
|
||||
...groupsActions(setLocalTypebot as SetTypebot, {
|
||||
onWebhookBlockCreated: createWebhook,
|
||||
onWebhookBlockDuplicated: duplicateWebhook,
|
||||
}),
|
||||
...blocksAction(setLocalTypebot as SetTypebot, {
|
||||
onWebhookBlockCreated: createWebhook,
|
||||
onWebhookBlockDuplicated: duplicateWebhook,
|
||||
}),
|
||||
...groupsActions(setLocalTypebot as SetTypebot),
|
||||
...blocksAction(setLocalTypebot as SetTypebot),
|
||||
...variablesAction(setLocalTypebot as SetTypebot),
|
||||
...edgesAction(setLocalTypebot as SetTypebot),
|
||||
...itemsAction(setLocalTypebot as SetTypebot),
|
||||
|
||||
@@ -37,10 +37,7 @@ export type WebhookCallBacks = {
|
||||
) => void
|
||||
}
|
||||
|
||||
export const blocksAction = (
|
||||
setTypebot: SetTypebot,
|
||||
{ onWebhookBlockCreated, onWebhookBlockDuplicated }: WebhookCallBacks
|
||||
): BlocksActions => ({
|
||||
export const blocksAction = (setTypebot: SetTypebot): BlocksActions => ({
|
||||
createBlock: (
|
||||
groupId: string,
|
||||
block: DraggableBlock | DraggableBlockType,
|
||||
@@ -48,13 +45,7 @@ export const blocksAction = (
|
||||
) =>
|
||||
setTypebot((typebot) =>
|
||||
produce(typebot, (typebot) => {
|
||||
createBlockDraft(
|
||||
typebot,
|
||||
block,
|
||||
groupId,
|
||||
indices,
|
||||
onWebhookBlockCreated
|
||||
)
|
||||
createBlockDraft(typebot, block, groupId, indices)
|
||||
})
|
||||
),
|
||||
updateBlock: (
|
||||
@@ -74,10 +65,7 @@ export const blocksAction = (
|
||||
const blocks = typebot.groups[groupIndex].blocks
|
||||
if (blockIndex === blocks.length - 1 && block.outgoingEdgeId)
|
||||
deleteEdgeDraft(typebot, block.outgoingEdgeId as string)
|
||||
const newBlock = duplicateBlockDraft(block.groupId)(
|
||||
block,
|
||||
onWebhookBlockDuplicated
|
||||
)
|
||||
const newBlock = duplicateBlockDraft(block.groupId)(block)
|
||||
typebot.groups[groupIndex].blocks.splice(blockIndex + 1, 0, newBlock)
|
||||
})
|
||||
),
|
||||
@@ -105,8 +93,7 @@ export const createBlockDraft = (
|
||||
typebot: Draft<Typebot>,
|
||||
block: DraggableBlock | DraggableBlockType,
|
||||
groupId: string,
|
||||
{ groupIndex, blockIndex }: BlockIndices,
|
||||
onWebhookBlockCreated?: (data: Partial<Webhook>) => void
|
||||
{ groupIndex, blockIndex }: BlockIndices
|
||||
) => {
|
||||
const blocks = typebot.groups[groupIndex].blocks
|
||||
if (
|
||||
@@ -116,13 +103,7 @@ export const createBlockDraft = (
|
||||
)
|
||||
deleteEdgeDraft(typebot, blocks[blockIndex - 1].outgoingEdgeId as string)
|
||||
typeof block === 'string'
|
||||
? createNewBlock(
|
||||
typebot,
|
||||
block,
|
||||
groupId,
|
||||
{ groupIndex, blockIndex },
|
||||
onWebhookBlockCreated
|
||||
)
|
||||
? createNewBlock(typebot, block, groupId, { groupIndex, blockIndex })
|
||||
: moveBlockToGroup(typebot, block, groupId, { groupIndex, blockIndex })
|
||||
removeEmptyGroups(typebot)
|
||||
}
|
||||
@@ -174,10 +155,7 @@ const moveBlockToGroup = (
|
||||
|
||||
export const duplicateBlockDraft =
|
||||
(groupId: string) =>
|
||||
(
|
||||
block: Block,
|
||||
onWebhookBlockDuplicated: WebhookCallBacks['onWebhookBlockDuplicated']
|
||||
): Block => {
|
||||
(block: Block): Block => {
|
||||
const blockId = createId()
|
||||
if (blockHasItems(block))
|
||||
return {
|
||||
@@ -189,8 +167,6 @@ export const duplicateBlockDraft =
|
||||
} as Block
|
||||
if (isWebhookBlock(block)) {
|
||||
const newWebhookId = createId()
|
||||
if (block.webhookId)
|
||||
onWebhookBlockDuplicated(block.webhookId, newWebhookId)
|
||||
return {
|
||||
...block,
|
||||
groupId,
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
deleteGroupDraft,
|
||||
createBlockDraft,
|
||||
duplicateBlockDraft,
|
||||
WebhookCallBacks,
|
||||
} from './blocks'
|
||||
import { isEmpty, parseGroupTitle } from '@typebot.io/lib'
|
||||
import { Coordinates } from '@/features/graph/types'
|
||||
@@ -29,10 +28,7 @@ export type GroupsActions = {
|
||||
deleteGroup: (groupIndex: number) => void
|
||||
}
|
||||
|
||||
const groupsActions = (
|
||||
setTypebot: SetTypebot,
|
||||
{ onWebhookBlockCreated, onWebhookBlockDuplicated }: WebhookCallBacks
|
||||
): GroupsActions => ({
|
||||
const groupsActions = (setTypebot: SetTypebot): GroupsActions => ({
|
||||
createGroup: ({
|
||||
id,
|
||||
block,
|
||||
@@ -52,13 +48,7 @@ const groupsActions = (
|
||||
blocks: [],
|
||||
}
|
||||
typebot.groups.push(newGroup)
|
||||
createBlockDraft(
|
||||
typebot,
|
||||
block,
|
||||
newGroup.id,
|
||||
indices,
|
||||
onWebhookBlockCreated
|
||||
)
|
||||
createBlockDraft(typebot, block, newGroup.id, indices)
|
||||
})
|
||||
),
|
||||
updateGroup: (groupIndex: number, updates: Partial<Omit<Group, 'id'>>) =>
|
||||
@@ -79,9 +69,7 @@ const groupsActions = (
|
||||
? ''
|
||||
: `${parseGroupTitle(group.title)} copy`,
|
||||
id,
|
||||
blocks: group.blocks.map((block) =>
|
||||
duplicateBlockDraft(id)(block, onWebhookBlockDuplicated)
|
||||
),
|
||||
blocks: group.blocks.map((block) => duplicateBlockDraft(id)(block)),
|
||||
graphCoordinates: {
|
||||
x: group.graphCoordinates.x + 200,
|
||||
y: group.graphCoordinates.y + 100,
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Typebot } from '@typebot.io/schemas'
|
||||
import { sendRequest } from '@typebot.io/lib'
|
||||
|
||||
export const updateTypebotQuery = async (id: string, typebot: Typebot) =>
|
||||
sendRequest<{ typebot: Typebot }>({
|
||||
url: `/api/typebots/${id}`,
|
||||
method: 'PUT',
|
||||
body: typebot,
|
||||
})
|
||||
Reference in New Issue
Block a user