🚸 (buttons) Show collected variable in buttons block preview
This commit is contained in:
@@ -51,6 +51,9 @@ test.describe.parallel('Buttons input block', () => {
|
|||||||
await page.click('[data-testid="block2-icon"]')
|
await page.click('[data-testid="block2-icon"]')
|
||||||
await page.click('text=Multiple choice?')
|
await page.click('text=Multiple choice?')
|
||||||
await page.fill('#button', 'Go')
|
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.click('[data-testid="block2-icon"]')
|
||||||
|
|
||||||
await page.locator('text=Item 1').hover()
|
await page.locator('text=Item 1').hover()
|
||||||
|
|||||||
@@ -4,39 +4,72 @@ import {
|
|||||||
BlockWithItems,
|
BlockWithItems,
|
||||||
defaultConditionContent,
|
defaultConditionContent,
|
||||||
ItemType,
|
ItemType,
|
||||||
|
Block,
|
||||||
|
LogicBlockType,
|
||||||
|
InputBlockType,
|
||||||
} from 'models'
|
} from 'models'
|
||||||
import { SetTypebot } from '../TypebotProvider'
|
import { SetTypebot } from '../TypebotProvider'
|
||||||
import produce from 'immer'
|
import produce from 'immer'
|
||||||
import { cleanUpEdgeDraft } from './edges'
|
import { cleanUpEdgeDraft } from './edges'
|
||||||
import { byId, blockHasItems } from 'utils'
|
import { byId, blockHasItems } from 'utils'
|
||||||
import cuid from 'cuid'
|
import cuid from 'cuid'
|
||||||
|
import { WritableDraft } from 'immer/dist/types/types-external'
|
||||||
|
|
||||||
|
type NewItem = Pick<Item, 'blockId' | 'outgoingEdgeId' | 'type'> & Partial<Item>
|
||||||
|
|
||||||
export type ItemsActions = {
|
export type ItemsActions = {
|
||||||
createItem: (item: Item | Omit<Item, 'id'>, indices: ItemIndices) => void
|
createItem: (item: NewItem, indices: ItemIndices) => void
|
||||||
updateItem: (indices: ItemIndices, updates: Partial<Omit<Item, 'id'>>) => void
|
updateItem: (indices: ItemIndices, updates: Partial<Omit<Item, 'id'>>) => void
|
||||||
detachItemFromBlock: (indices: ItemIndices) => void
|
detachItemFromBlock: (indices: ItemIndices) => void
|
||||||
deleteItem: (indices: ItemIndices) => void
|
deleteItem: (indices: ItemIndices) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createItem = (
|
||||||
|
block: WritableDraft<Block>,
|
||||||
|
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 => ({
|
const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({
|
||||||
createItem: (
|
createItem: (
|
||||||
item: Item | Omit<Item, 'id'>,
|
item: NewItem,
|
||||||
{ groupIndex, blockIndex, itemIndex }: ItemIndices
|
{ groupIndex, blockIndex, itemIndex }: ItemIndices
|
||||||
) =>
|
) =>
|
||||||
setTypebot((typebot) =>
|
setTypebot((typebot) =>
|
||||||
produce(typebot, (typebot) => {
|
produce(typebot, (typebot) => {
|
||||||
const block = typebot.groups[groupIndex].blocks[
|
const block = typebot.groups[groupIndex].blocks[blockIndex]
|
||||||
blockIndex
|
|
||||||
] as BlockWithItems
|
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) {
|
if (item.outgoingEdgeId) {
|
||||||
const edgeIndex = typebot.edges.findIndex(byId(item.outgoingEdgeId))
|
const edgeIndex = typebot.edges.findIndex(byId(item.outgoingEdgeId))
|
||||||
edgeIndex !== -1
|
edgeIndex !== -1
|
||||||
@@ -47,7 +80,6 @@ const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({
|
|||||||
})
|
})
|
||||||
: (newItem.outgoingEdgeId = undefined)
|
: (newItem.outgoingEdgeId = undefined)
|
||||||
}
|
}
|
||||||
block.items.splice(itemIndex, 0, newItem)
|
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
updateItem: (
|
updateItem: (
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
Flex,
|
Flex,
|
||||||
|
HStack,
|
||||||
Portal,
|
Portal,
|
||||||
Stack,
|
Stack,
|
||||||
|
Tag,
|
||||||
Text,
|
Text,
|
||||||
useColorModeValue,
|
useColorModeValue,
|
||||||
useEventListener,
|
useEventListener,
|
||||||
@@ -13,7 +15,13 @@ import {
|
|||||||
useGraph,
|
useGraph,
|
||||||
} from '../../../providers'
|
} from '../../../providers'
|
||||||
import { useTypebot } from '@/features/editor'
|
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 React, { useEffect, useRef, useState } from 'react'
|
||||||
import { ItemNode } from './ItemNode'
|
import { ItemNode } from './ItemNode'
|
||||||
import { SourceEndpoint } from '../../Endpoints'
|
import { SourceEndpoint } from '../../Endpoints'
|
||||||
@@ -127,8 +135,16 @@ export const ItemNodesList = ({
|
|||||||
elem && (placeholderRefs.current[idx] = elem)
|
elem && (placeholderRefs.current[idx] = elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const collectedVariableId = 'options' in block && block.options.variableId
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack flex={1} spacing={1} maxW="full" onClick={stopPropagating}>
|
<Stack flex={1} spacing={1} maxW="full" onClick={stopPropagating}>
|
||||||
|
{collectedVariableId && (
|
||||||
|
<CollectVariableLabel
|
||||||
|
variableId={collectedVariableId}
|
||||||
|
variables={typebot?.variables ?? []}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<PlaceholderNode
|
<PlaceholderNode
|
||||||
isVisible={showPlaceholders}
|
isVisible={showPlaceholders}
|
||||||
isExpanded={expandedPlaceholderIndex === 0}
|
isExpanded={expandedPlaceholderIndex === 0}
|
||||||
@@ -202,3 +218,20 @@ const DefaultItemNode = ({ block }: { block: BlockWithItems }) => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CollectVariableLabel = ({
|
||||||
|
variableId,
|
||||||
|
variables,
|
||||||
|
}: {
|
||||||
|
variableId: string
|
||||||
|
variables: Variable[]
|
||||||
|
}) => (
|
||||||
|
<HStack fontStyle="italic" spacing={1}>
|
||||||
|
<Text fontSize="sm" color={useColorModeValue('gray.600', 'gray.400')}>
|
||||||
|
Collects
|
||||||
|
</Text>
|
||||||
|
<Tag bg="orange.400" color="white" size="sm">
|
||||||
|
{variables.find((variable) => variable.id === variableId)?.name}
|
||||||
|
</Tag>
|
||||||
|
</HStack>
|
||||||
|
)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
LogicBlockOptions,
|
LogicBlockOptions,
|
||||||
} from '.'
|
} from '.'
|
||||||
import { BubbleBlock, bubbleBlockSchema } from './bubbles'
|
import { BubbleBlock, bubbleBlockSchema } from './bubbles'
|
||||||
import { InputBlock, inputBlockSchema } from './inputs'
|
import { ChoiceInputBlock, InputBlock, inputBlockSchema } from './inputs'
|
||||||
import { IntegrationBlock, integrationBlockSchema } from './integrations'
|
import { IntegrationBlock, integrationBlockSchema } from './integrations'
|
||||||
import { ConditionBlock, LogicBlock, logicBlockSchema } from './logic'
|
import { ConditionBlock, LogicBlock, logicBlockSchema } from './logic'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
@@ -51,7 +51,7 @@ export type BlockOptions =
|
|||||||
| LogicBlockOptions
|
| LogicBlockOptions
|
||||||
| IntegrationBlockOptions
|
| IntegrationBlockOptions
|
||||||
|
|
||||||
export type BlockWithItems = Omit<Block, 'items'> & { items: Item[] }
|
export type BlockWithItems = ConditionBlock | ChoiceInputBlock
|
||||||
|
|
||||||
export type BlockBase = z.infer<typeof blockBaseSchema>
|
export type BlockBase = z.infer<typeof blockBaseSchema>
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ export const conditionBlockSchema = blockBaseSchema.and(
|
|||||||
z.object({
|
z.object({
|
||||||
type: z.enum([LogicBlockType.CONDITION]),
|
type: z.enum([LogicBlockType.CONDITION]),
|
||||||
items: z.array(conditionItemSchema),
|
items: z.array(conditionItemSchema),
|
||||||
options: z.object({}),
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user