@@ -24,6 +24,7 @@ type BlockWithCreatableItems = Extract<Block, { items: DraggabbleItem[] }>
|
|||||||
|
|
||||||
export type ItemsActions = {
|
export type ItemsActions = {
|
||||||
createItem: (item: NewItem, indices: ItemIndices) => void
|
createItem: (item: NewItem, indices: ItemIndices) => void
|
||||||
|
duplicateItem: (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
|
||||||
@@ -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 => ({
|
const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({
|
||||||
createItem: (
|
createItem: (
|
||||||
item: NewItem,
|
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: (
|
updateItem: (
|
||||||
{ groupIndex, blockIndex, itemIndex }: ItemIndices,
|
{ groupIndex, blockIndex, itemIndex }: ItemIndices,
|
||||||
updates: Partial<Omit<Item, 'id'>>
|
updates: Partial<Omit<Item, 'id'>>
|
||||||
|
|||||||
@@ -86,13 +86,12 @@ export const ItemNode = ({
|
|||||||
transition="box-shadow 200ms, border-color 200ms"
|
transition="box-shadow 200ms, border-color 200ms"
|
||||||
rounded="md"
|
rounded="md"
|
||||||
bg={bg}
|
bg={bg}
|
||||||
borderWidth={isContextMenuOpened || isPreviewing ? '2px' : '1px'}
|
borderWidth={1}
|
||||||
borderColor={
|
borderColor={
|
||||||
isContextMenuOpened || isPreviewing
|
isContextMenuOpened || isPreviewing
|
||||||
? previewingBorderColor
|
? previewingBorderColor
|
||||||
: borderColor
|
: borderColor
|
||||||
}
|
}
|
||||||
margin={isContextMenuOpened || isPreviewing ? '-1px' : 0}
|
|
||||||
w="full"
|
w="full"
|
||||||
>
|
>
|
||||||
<ItemNodeContent
|
<ItemNodeContent
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { MenuList, MenuItem } from '@chakra-ui/react'
|
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 { useTypebot } from '@/features/editor/providers/TypebotProvider'
|
||||||
import { ItemIndices } from '@typebot.io/schemas'
|
import { ItemIndices } from '@typebot.io/schemas'
|
||||||
|
|
||||||
@@ -7,13 +7,14 @@ type Props = {
|
|||||||
indices: ItemIndices
|
indices: ItemIndices
|
||||||
}
|
}
|
||||||
export const ItemNodeContextMenu = ({ indices }: Props) => {
|
export const ItemNodeContextMenu = ({ indices }: Props) => {
|
||||||
const { deleteItem } = useTypebot()
|
const { deleteItem, duplicateItem } = useTypebot()
|
||||||
|
|
||||||
const handleDeleteClick = () => deleteItem(indices)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuList>
|
<MenuList>
|
||||||
<MenuItem icon={<TrashIcon />} onClick={handleDeleteClick}>
|
<MenuItem icon={<CopyIcon />} onClick={() => duplicateItem(indices)}>
|
||||||
|
Duplicate
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem icon={<TrashIcon />} onClick={() => deleteItem(indices)}>
|
||||||
Delete
|
Delete
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuList>
|
</MenuList>
|
||||||
|
|||||||
Reference in New Issue
Block a user