diff --git a/apps/builder/src/features/blocks/inputs/buttons/buttons.spec.ts b/apps/builder/src/features/blocks/inputs/buttons/buttons.spec.ts index 6310ff80f4..9f99596641 100644 --- a/apps/builder/src/features/blocks/inputs/buttons/buttons.spec.ts +++ b/apps/builder/src/features/blocks/inputs/buttons/buttons.spec.ts @@ -51,6 +51,9 @@ test.describe.parallel('Buttons input block', () => { await page.click('[data-testid="block2-icon"]') await page.click('text=Multiple choice?') await page.fill('#button', 'Go') + await page.getByPlaceholder('Select a variable').click() + await page.getByText('var1').click() + await expect(page.getByText('Collectsvar1')).toBeVisible() await page.click('[data-testid="block2-icon"]') await page.locator('text=Item 1').hover() diff --git a/apps/builder/src/features/editor/providers/TypebotProvider/actions/items.ts b/apps/builder/src/features/editor/providers/TypebotProvider/actions/items.ts index 6fe565566c..55556d5001 100644 --- a/apps/builder/src/features/editor/providers/TypebotProvider/actions/items.ts +++ b/apps/builder/src/features/editor/providers/TypebotProvider/actions/items.ts @@ -4,39 +4,72 @@ import { BlockWithItems, defaultConditionContent, ItemType, + Block, + LogicBlockType, + InputBlockType, } from 'models' import { SetTypebot } from '../TypebotProvider' import produce from 'immer' import { cleanUpEdgeDraft } from './edges' import { byId, blockHasItems } from 'utils' import cuid from 'cuid' +import { WritableDraft } from 'immer/dist/types/types-external' + +type NewItem = Pick & Partial export type ItemsActions = { - createItem: (item: Item | Omit, indices: ItemIndices) => void + createItem: (item: NewItem, indices: ItemIndices) => void updateItem: (indices: ItemIndices, updates: Partial>) => void detachItemFromBlock: (indices: ItemIndices) => void deleteItem: (indices: ItemIndices) => void } +const createItem = ( + block: WritableDraft, + item: NewItem, + itemIndex: number +) => { + switch (block.type) { + case LogicBlockType.CONDITION: { + if (item.type === ItemType.CONDITION) { + const newItem = { + ...item, + id: 'id' in item && item.id ? item.id : cuid(), + content: item.content ?? defaultConditionContent, + } + block.items.splice(itemIndex, 0, newItem) + return newItem + } + break + } + case InputBlockType.CHOICE: { + if (item.type === ItemType.BUTTON) { + const newItem = { + ...item, + id: 'id' in item && item.id ? item.id : cuid(), + content: item.content, + } + block.items.splice(itemIndex, 0, newItem) + return newItem + } + break + } + } +} + const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({ createItem: ( - item: Item | Omit, + item: NewItem, { groupIndex, blockIndex, itemIndex }: ItemIndices ) => setTypebot((typebot) => produce(typebot, (typebot) => { - const block = typebot.groups[groupIndex].blocks[ - blockIndex - ] as BlockWithItems + const block = typebot.groups[groupIndex].blocks[blockIndex] + + const newItem = createItem(block, item, itemIndex) + + if (!newItem) return - const newItem = { - id: 'id' in item ? item.id : cuid(), - content: - item.type === ItemType.CONDITION - ? defaultConditionContent - : undefined, - ...item, - } as Item if (item.outgoingEdgeId) { const edgeIndex = typebot.edges.findIndex(byId(item.outgoingEdgeId)) edgeIndex !== -1 @@ -47,7 +80,6 @@ const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({ }) : (newItem.outgoingEdgeId = undefined) } - block.items.splice(itemIndex, 0, newItem) }) ), updateItem: ( diff --git a/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNodesList.tsx b/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNodesList.tsx index f47fd537a6..d24295fea1 100644 --- a/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNodesList.tsx +++ b/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNodesList.tsx @@ -1,7 +1,9 @@ import { Flex, + HStack, Portal, Stack, + Tag, Text, useColorModeValue, useEventListener, @@ -13,7 +15,13 @@ import { useGraph, } from '../../../providers' import { useTypebot } from '@/features/editor' -import { BlockIndices, BlockWithItems, LogicBlockType, Item } from 'models' +import { + BlockIndices, + BlockWithItems, + LogicBlockType, + Item, + Variable, +} from 'models' import React, { useEffect, useRef, useState } from 'react' import { ItemNode } from './ItemNode' import { SourceEndpoint } from '../../Endpoints' @@ -127,8 +135,16 @@ export const ItemNodesList = ({ elem && (placeholderRefs.current[idx] = elem) } + const collectedVariableId = 'options' in block && block.options.variableId + return ( + {collectedVariableId && ( + + )} { ) } + +const CollectVariableLabel = ({ + variableId, + variables, +}: { + variableId: string + variables: Variable[] +}) => ( + + + Collects + + + {variables.find((variable) => variable.id === variableId)?.name} + + +) diff --git a/packages/models/src/features/blocks/blocks.ts b/packages/models/src/features/blocks/blocks.ts index 0d04833f14..f6a0f9f391 100644 --- a/packages/models/src/features/blocks/blocks.ts +++ b/packages/models/src/features/blocks/blocks.ts @@ -5,7 +5,7 @@ import { LogicBlockOptions, } from '.' import { BubbleBlock, bubbleBlockSchema } from './bubbles' -import { InputBlock, inputBlockSchema } from './inputs' +import { ChoiceInputBlock, InputBlock, inputBlockSchema } from './inputs' import { IntegrationBlock, integrationBlockSchema } from './integrations' import { ConditionBlock, LogicBlock, logicBlockSchema } from './logic' import { z } from 'zod' @@ -51,7 +51,7 @@ export type BlockOptions = | LogicBlockOptions | IntegrationBlockOptions -export type BlockWithItems = Omit & { items: Item[] } +export type BlockWithItems = ConditionBlock | ChoiceInputBlock export type BlockBase = z.infer diff --git a/packages/models/src/features/blocks/logic/condition.ts b/packages/models/src/features/blocks/logic/condition.ts index f74c77e23f..b9ff5574af 100644 --- a/packages/models/src/features/blocks/logic/condition.ts +++ b/packages/models/src/features/blocks/logic/condition.ts @@ -43,7 +43,6 @@ export const conditionBlockSchema = blockBaseSchema.and( z.object({ type: z.enum([LogicBlockType.CONDITION]), items: z.array(conditionItemSchema), - options: z.object({}), }) )