@@ -24,6 +24,7 @@ type BlockWithCreatableItems = Extract<Block, { items: DraggabbleItem[] }>
|
||||
|
||||
export type ItemsActions = {
|
||||
createItem: (item: NewItem, indices: ItemIndices) => void
|
||||
duplicateItem: (indices: ItemIndices) => void
|
||||
updateItem: (indices: ItemIndices, updates: Partial<Omit<Item, 'id'>>) => void
|
||||
detachItemFromBlock: (indices: ItemIndices) => void
|
||||
deleteItem: (indices: ItemIndices) => void
|
||||
@@ -67,6 +68,44 @@ const createItem = (
|
||||
}
|
||||
}
|
||||
|
||||
const duplicateItem = (
|
||||
block: Draft<BlockWithCreatableItems>,
|
||||
itemIndex: number
|
||||
): Item => {
|
||||
const item = block.items[itemIndex]
|
||||
switch (block.type) {
|
||||
case LogicBlockType.CONDITION: {
|
||||
const baseItem = item as ConditionItem
|
||||
const newItem = {
|
||||
...baseItem,
|
||||
id: createId(),
|
||||
content: baseItem.content ?? defaultConditionContent,
|
||||
}
|
||||
block.items.splice(itemIndex + 1, 0, newItem)
|
||||
return newItem
|
||||
}
|
||||
case InputBlockType.CHOICE: {
|
||||
const baseItem = item as ButtonItem
|
||||
const newItem = {
|
||||
...baseItem,
|
||||
id: createId(),
|
||||
content: baseItem.content,
|
||||
}
|
||||
block.items.splice(itemIndex + 1, 0, newItem)
|
||||
return newItem
|
||||
}
|
||||
case InputBlockType.PICTURE_CHOICE: {
|
||||
const baseItem = item as PictureChoiceItem
|
||||
const newItem = {
|
||||
...baseItem,
|
||||
id: createId(),
|
||||
}
|
||||
block.items.splice(itemIndex + 1, 0, newItem)
|
||||
return newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({
|
||||
createItem: (
|
||||
item: NewItem,
|
||||
@@ -94,6 +133,15 @@ const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({
|
||||
}
|
||||
})
|
||||
),
|
||||
duplicateItem: ({ groupIndex, blockIndex, itemIndex }: ItemIndices) =>
|
||||
setTypebot((typebot) =>
|
||||
produce(typebot, (typebot) => {
|
||||
const block = typebot.groups[groupIndex].blocks[
|
||||
blockIndex
|
||||
] as BlockWithCreatableItems
|
||||
duplicateItem(block, itemIndex)
|
||||
})
|
||||
),
|
||||
updateItem: (
|
||||
{ groupIndex, blockIndex, itemIndex }: ItemIndices,
|
||||
updates: Partial<Omit<Item, 'id'>>
|
||||
|
||||
@@ -86,13 +86,12 @@ export const ItemNode = ({
|
||||
transition="box-shadow 200ms, border-color 200ms"
|
||||
rounded="md"
|
||||
bg={bg}
|
||||
borderWidth={isContextMenuOpened || isPreviewing ? '2px' : '1px'}
|
||||
borderWidth={1}
|
||||
borderColor={
|
||||
isContextMenuOpened || isPreviewing
|
||||
? previewingBorderColor
|
||||
: borderColor
|
||||
}
|
||||
margin={isContextMenuOpened || isPreviewing ? '-1px' : 0}
|
||||
w="full"
|
||||
>
|
||||
<ItemNodeContent
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MenuList, MenuItem } from '@chakra-ui/react'
|
||||
import { TrashIcon } from '@/components/icons'
|
||||
import { CopyIcon, TrashIcon } from '@/components/icons'
|
||||
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
|
||||
import { ItemIndices } from '@typebot.io/schemas'
|
||||
|
||||
@@ -7,13 +7,14 @@ type Props = {
|
||||
indices: ItemIndices
|
||||
}
|
||||
export const ItemNodeContextMenu = ({ indices }: Props) => {
|
||||
const { deleteItem } = useTypebot()
|
||||
|
||||
const handleDeleteClick = () => deleteItem(indices)
|
||||
const { deleteItem, duplicateItem } = useTypebot()
|
||||
|
||||
return (
|
||||
<MenuList>
|
||||
<MenuItem icon={<TrashIcon />} onClick={handleDeleteClick}>
|
||||
<MenuItem icon={<CopyIcon />} onClick={() => duplicateItem(indices)}>
|
||||
Duplicate
|
||||
</MenuItem>
|
||||
<MenuItem icon={<TrashIcon />} onClick={() => deleteItem(indices)}>
|
||||
Delete
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
|
||||
Reference in New Issue
Block a user