diff --git a/apps/builder/components/shared/Graph/Graph.tsx b/apps/builder/components/shared/Graph/Graph.tsx index 914696e73..b4b62c8d5 100644 --- a/apps/builder/components/shared/Graph/Graph.tsx +++ b/apps/builder/components/shared/Graph/Graph.tsx @@ -27,8 +27,14 @@ export const Graph = ({ answersCounts?: AnswersCount[] onUnlockProPlanClick?: () => void } & FlexProps) => { - const { draggedStepType, setDraggedStepType, draggedStep, setDraggedStep } = - useStepDnd() + const { + draggedStepType, + setDraggedStepType, + draggedStep, + setDraggedStep, + draggedItem, + setDraggedItem, + } = useStepDnd() const graphContainerRef = useRef(null) const editorContainerRef = useRef(null) const { createBlock } = useTypebot() @@ -77,6 +83,7 @@ export const Graph = ({ const handleMouseUp = (e: MouseEvent) => { if (!typebot) return + if (draggedItem) setDraggedItem(undefined) if (!draggedStep && !draggedStepType) return const coordinates = { x: e.clientX - graphPosition.x - blockWidth / 3, diff --git a/apps/builder/components/shared/Graph/Nodes/ItemNode/ItemNodesList.tsx b/apps/builder/components/shared/Graph/Nodes/ItemNode/ItemNodesList.tsx index 36ceac460..18fc20c53 100644 --- a/apps/builder/components/shared/Graph/Nodes/ItemNode/ItemNodesList.tsx +++ b/apps/builder/components/shared/Graph/Nodes/ItemNode/ItemNodesList.tsx @@ -22,7 +22,7 @@ export const ItemNodesList = ({ indices: { blockIndex, stepIndex }, isReadOnly = false, }: Props) => { - const { typebot, createItem, deleteItem } = useTypebot() + const { typebot, createItem, detachItemFromStep } = useTypebot() const { draggedItem, setDraggedItem, mouseOverBlock } = useStepDnd() const placeholderRefs = useRef([]) const blockId = typebot?.blocks[blockIndex].id @@ -96,7 +96,7 @@ export const ItemNodesList = ({ ) => { if (!typebot || isReadOnly) return placeholderRefs.current.splice(itemIndex + 1, 1) - deleteItem({ blockIndex, stepIndex, itemIndex }) + detachItemFromStep({ blockIndex, stepIndex, itemIndex }) setPosition(absolute) setRelativeCoordinates(relative) setDraggedItem(item) diff --git a/apps/builder/contexts/TypebotContext/actions/edges.ts b/apps/builder/contexts/TypebotContext/actions/edges.ts index 690c2cca6..935abbdf0 100644 --- a/apps/builder/contexts/TypebotContext/actions/edges.ts +++ b/apps/builder/contexts/TypebotContext/actions/edges.ts @@ -1,4 +1,11 @@ -import { Typebot, Edge, StepWithItems, StepIndices, ItemIndices } from 'models' +import { + Typebot, + Edge, + StepWithItems, + StepIndices, + ItemIndices, + Step, +} from 'models' import { WritableDraft } from 'immer/dist/types/types-external' import { SetTypebot } from '../TypebotContext' import { produce } from 'immer' @@ -98,9 +105,11 @@ const deleteOutgoingEdgeIdProps = ( const fromStepIndex = typebot.blocks[fromBlockIndex].steps.findIndex( byId(edge.from.stepId) ) - const step = typebot.blocks[fromBlockIndex].steps[fromStepIndex] + const step = typebot.blocks[fromBlockIndex].steps[fromStepIndex] as + | Step + | undefined const fromItemIndex = - edge.from.itemId && stepHasItems(step) + edge.from.itemId && step && stepHasItems(step) ? step.items.findIndex(byId(edge.from.itemId)) : -1 if (fromStepIndex !== -1) diff --git a/apps/builder/contexts/TypebotContext/actions/items.ts b/apps/builder/contexts/TypebotContext/actions/items.ts index 13a68e3be..47e21b605 100644 --- a/apps/builder/contexts/TypebotContext/actions/items.ts +++ b/apps/builder/contexts/TypebotContext/actions/items.ts @@ -8,29 +8,44 @@ import { import { SetTypebot } from '../TypebotContext' import produce from 'immer' import { cleanUpEdgeDraft } from './edges' -import { stepHasItems } from 'utils' +import { byId, stepHasItems } from 'utils' import cuid from 'cuid' export type ItemsActions = { - createItem: (item: Omit, indices: ItemIndices) => void + createItem: ( + item: ButtonItem | Omit, + indices: ItemIndices + ) => void updateItem: (indices: ItemIndices, updates: Partial>) => void + detachItemFromStep: (indices: ItemIndices) => void deleteItem: (indices: ItemIndices) => void } const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({ createItem: ( - item: Omit, + item: ButtonItem | Omit, { blockIndex, stepIndex, itemIndex }: ItemIndices ) => setTypebot((typebot) => produce(typebot, (typebot) => { const step = typebot.blocks[blockIndex].steps[stepIndex] if (step.type !== InputStepType.CHOICE) return - step.items.splice(itemIndex, 0, { + const newItem = { ...item, stepId: step.id, - id: cuid(), - }) + id: 'id' in item ? item.id : cuid(), + } + if (item.outgoingEdgeId) { + const edgeIndex = typebot.edges.findIndex(byId(item.outgoingEdgeId)) + edgeIndex !== -1 + ? (typebot.edges[edgeIndex].from = { + blockId: step.blockId, + stepId: step.id, + itemId: newItem.id, + }) + : (newItem.outgoingEdgeId = undefined) + } + step.items.splice(itemIndex, 0, newItem) }) ), updateItem: ( @@ -49,7 +64,15 @@ const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({ } as Item }) ), - + detachItemFromStep: ({ blockIndex, stepIndex, itemIndex }: ItemIndices) => + setTypebot((typebot) => + produce(typebot, (typebot) => { + const step = typebot.blocks[blockIndex].steps[ + stepIndex + ] as StepWithItems + step.items.splice(itemIndex, 1) + }) + ), deleteItem: ({ blockIndex, stepIndex, itemIndex }: ItemIndices) => setTypebot((typebot) => produce(typebot, (typebot) => { diff --git a/apps/builder/contexts/TypebotContext/actions/steps.ts b/apps/builder/contexts/TypebotContext/actions/steps.ts index 421bdec37..d8003ac77 100644 --- a/apps/builder/contexts/TypebotContext/actions/steps.ts +++ b/apps/builder/contexts/TypebotContext/actions/steps.ts @@ -13,6 +13,7 @@ import { SetTypebot } from '../TypebotContext' import produce from 'immer' import { cleanUpEdgeDraft, deleteEdgeDraft } from './edges' import cuid from 'cuid' +import { byId } from 'utils' export type StepsActions = { createStep: ( @@ -74,7 +75,9 @@ const stepsAction = (setTypebot: SetTypebot): StepsActions => ({ deleteStep: ({ blockIndex, stepIndex }: StepIndices) => setTypebot((typebot) => produce(typebot, (typebot) => { + const removingStep = typebot.blocks[blockIndex].steps[stepIndex] removeStepFromBlock({ blockIndex, stepIndex })(typebot) + cleanUpEdgeDraft(typebot, removingStep.id) removeEmptyBlocks(typebot) }) ), @@ -83,8 +86,6 @@ const stepsAction = (setTypebot: SetTypebot): StepsActions => ({ const removeStepFromBlock = ({ blockIndex, stepIndex }: StepIndices) => (typebot: WritableDraft) => { - const removingStep = typebot.blocks[blockIndex].steps[stepIndex] - cleanUpEdgeDraft(typebot, removingStep.id) typebot.blocks[blockIndex].steps.splice(stepIndex, 1) } @@ -122,11 +123,20 @@ const moveStepToBlock = ( step: DraggableStep, blockId: string, { blockIndex, stepIndex }: StepIndices -) => - typebot.blocks[blockIndex].steps.splice(stepIndex ?? 0, 0, { - ...step, - blockId, - outgoingEdgeId: undefined, - }) +) => { + const newStep = { ...step, blockId } + if (step.outgoingEdgeId) { + if (typebot.blocks[blockIndex].steps.length > stepIndex ?? 0) { + deleteEdgeDraft(typebot, step.outgoingEdgeId) + newStep.outgoingEdgeId = undefined + } else { + const edgeIndex = typebot.edges.findIndex(byId(step.outgoingEdgeId)) + edgeIndex !== -1 + ? (typebot.edges[edgeIndex].from.blockId = blockId) + : (newStep.outgoingEdgeId = undefined) + } + } + typebot.blocks[blockIndex].steps.splice(stepIndex ?? 0, 0, newStep) +} export { stepsAction, createStepDraft } diff --git a/apps/builder/playwright/tests/bubbles/embed.spec.ts b/apps/builder/playwright/tests/bubbles/embed.spec.ts index c2e1ca63d..8907442e0 100644 --- a/apps/builder/playwright/tests/bubbles/embed.spec.ts +++ b/apps/builder/playwright/tests/bubbles/embed.spec.ts @@ -30,7 +30,7 @@ test.describe.parallel('Embed bubble step', () => { await page.fill('input[placeholder="Paste the link or code..."]', pdfSrc) await expect(page.locator('iframe#embed-bubble-content')).toHaveAttribute( 'src', - `https://docs.google.com/viewer?embedded=true&url=${pdfSrc}` + pdfSrc ) await page.fill( 'input[placeholder="Paste the link or code..."]', diff --git a/apps/builder/playwright/tests/editor.spec.ts b/apps/builder/playwright/tests/editor.spec.ts index 913ff5274..42babbf15 100644 --- a/apps/builder/playwright/tests/editor.spec.ts +++ b/apps/builder/playwright/tests/editor.spec.ts @@ -51,7 +51,10 @@ test.describe.parallel('Editor', () => { await expect(page.locator('[data-testid="edge"] >> nth=0')).toBeVisible() await expect(page.locator('[data-testid="edge"] >> nth=1')).toBeVisible() - await page.click('[data-testid="clickable-edge"] >> nth=0', { force: true }) + await page.click('[data-testid="clickable-edge"] >> nth=0', { + force: true, + button: 'right', + }) await page.click('text=Delete') const total = await page.locator('[data-testid="edge"]').count() expect(total).toBe(1)