Add picture choice block

Closes #476
This commit is contained in:
Baptiste Arnaud
2023-05-04 09:20:30 -04:00
parent 65c6f66a5c
commit 035dded654
54 changed files with 6282 additions and 4938 deletions

View File

@@ -38,6 +38,7 @@ import { RedirectIcon } from '@/features/blocks/logic/redirect/components/Redire
import { SetVariableIcon } from '@/features/blocks/logic/setVariable/components/SetVariableIcon'
import { TypebotLinkIcon } from '@/features/blocks/logic/typebotLink/components/TypebotLinkIcon'
import { AbTestIcon } from '@/features/blocks/logic/abTest/components/AbTestIcon'
import { PictureChoiceIcon } from '@/features/blocks/inputs/pictureChoice/components/PictureChoiceIcon'
type BlockIconProps = { type: BlockType } & IconProps
@@ -72,6 +73,8 @@ export const BlockIcon = ({ type, ...props }: BlockIconProps): JSX.Element => {
return <PhoneInputIcon color={orange} {...props} />
case InputBlockType.CHOICE:
return <ButtonsInputIcon color={orange} {...props} />
case InputBlockType.PICTURE_CHOICE:
return <PictureChoiceIcon color={orange} {...props} />
case InputBlockType.PAYMENT:
return <PaymentInputIcon color={orange} {...props} />
case InputBlockType.RATING:

View File

@@ -13,69 +13,71 @@ type Props = { type: BlockType }
export const BlockLabel = ({ type }: Props): JSX.Element => {
switch (type) {
case 'start':
return <Text>Start</Text>
return <Text fontSize="sm">Start</Text>
case BubbleBlockType.TEXT:
case InputBlockType.TEXT:
return <Text>Text</Text>
return <Text fontSize="sm">Text</Text>
case BubbleBlockType.IMAGE:
return <Text>Image</Text>
return <Text fontSize="sm">Image</Text>
case BubbleBlockType.VIDEO:
return <Text>Video</Text>
return <Text fontSize="sm">Video</Text>
case BubbleBlockType.EMBED:
return <Text>Embed</Text>
return <Text fontSize="sm">Embed</Text>
case BubbleBlockType.AUDIO:
return <Text>Audio</Text>
return <Text fontSize="sm">Audio</Text>
case InputBlockType.NUMBER:
return <Text>Number</Text>
return <Text fontSize="sm">Number</Text>
case InputBlockType.EMAIL:
return <Text>Email</Text>
return <Text fontSize="sm">Email</Text>
case InputBlockType.URL:
return <Text>Website</Text>
return <Text fontSize="sm">Website</Text>
case InputBlockType.DATE:
return <Text>Date</Text>
return <Text fontSize="sm">Date</Text>
case InputBlockType.PHONE:
return <Text>Phone</Text>
return <Text fontSize="sm">Phone</Text>
case InputBlockType.CHOICE:
return <Text>Button</Text>
return <Text fontSize="sm">Button</Text>
case InputBlockType.PICTURE_CHOICE:
return <Text fontSize="sm">Pic choice</Text>
case InputBlockType.PAYMENT:
return <Text>Payment</Text>
return <Text fontSize="sm">Payment</Text>
case InputBlockType.RATING:
return <Text>Rating</Text>
return <Text fontSize="sm">Rating</Text>
case InputBlockType.FILE:
return <Text>File</Text>
return <Text fontSize="sm">File</Text>
case LogicBlockType.SET_VARIABLE:
return <Text>Set variable</Text>
return <Text fontSize="sm">Set variable</Text>
case LogicBlockType.CONDITION:
return <Text>Condition</Text>
return <Text fontSize="sm">Condition</Text>
case LogicBlockType.REDIRECT:
return <Text>Redirect</Text>
return <Text fontSize="sm">Redirect</Text>
case LogicBlockType.SCRIPT:
return <Text>Script</Text>
return <Text fontSize="sm">Script</Text>
case LogicBlockType.TYPEBOT_LINK:
return <Text>Typebot</Text>
return <Text fontSize="sm">Typebot</Text>
case LogicBlockType.WAIT:
return <Text>Wait</Text>
return <Text fontSize="sm">Wait</Text>
case LogicBlockType.JUMP:
return <Text>Jump</Text>
return <Text fontSize="sm">Jump</Text>
case LogicBlockType.AB_TEST:
return <Text>AB Test</Text>
return <Text fontSize="sm">AB Test</Text>
case IntegrationBlockType.GOOGLE_SHEETS:
return <Text>Sheets</Text>
return <Text fontSize="sm">Sheets</Text>
case IntegrationBlockType.GOOGLE_ANALYTICS:
return <Text>Analytics</Text>
return <Text fontSize="sm">Analytics</Text>
case IntegrationBlockType.WEBHOOK:
return <Text>Webhook</Text>
return <Text fontSize="sm">Webhook</Text>
case IntegrationBlockType.ZAPIER:
return <Text>Zapier</Text>
return <Text fontSize="sm">Zapier</Text>
case IntegrationBlockType.MAKE_COM:
return <Text>Make.com</Text>
return <Text fontSize="sm">Make.com</Text>
case IntegrationBlockType.PABBLY_CONNECT:
return <Text>Pabbly</Text>
return <Text fontSize="sm">Pabbly</Text>
case IntegrationBlockType.EMAIL:
return <Text>Email</Text>
return <Text fontSize="sm">Email</Text>
case IntegrationBlockType.CHATWOOT:
return <Text>Chatwoot</Text>
return <Text fontSize="sm">Chatwoot</Text>
case IntegrationBlockType.OPEN_AI:
return <Text>OpenAI</Text>
return <Text fontSize="sm">OpenAI</Text>
}
}

View File

@@ -3,24 +3,24 @@ import {
Item,
BlockWithItems,
defaultConditionContent,
ItemType,
Block,
LogicBlockType,
InputBlockType,
ConditionItem,
ButtonItem,
PictureChoiceItem,
} from '@typebot.io/schemas'
import { SetTypebot } from '../TypebotProvider'
import { Draft, produce } from 'immer'
import { cleanUpEdgeDraft } from './edges'
import { byId, blockHasItems } from '@typebot.io/lib'
import { createId } from '@paralleldrive/cuid2'
import { DraggabbleItem } from '@/features/graph/providers/GraphDndProvider'
type NewItem = Pick<
ConditionItem | ButtonItem,
'blockId' | 'outgoingEdgeId' | 'type'
> &
Partial<ConditionItem | ButtonItem>
type NewItem = Pick<DraggabbleItem, 'blockId' | 'outgoingEdgeId' | 'type'> &
Partial<DraggabbleItem>
type BlockWithCreatableItems = Extract<Block, { items: DraggabbleItem[] }>
export type ItemsActions = {
createItem: (item: NewItem, indices: ItemIndices) => void
@@ -29,31 +29,40 @@ export type ItemsActions = {
deleteItem: (indices: ItemIndices) => void
}
const createItem = (block: Draft<Block>, item: NewItem, itemIndex: number) => {
const createItem = (
block: Draft<BlockWithCreatableItems>,
item: NewItem,
itemIndex: number
): Item => {
switch (block.type) {
case LogicBlockType.CONDITION: {
if (item.type === ItemType.CONDITION) {
const newItem = {
...item,
id: 'id' in item && item.id ? item.id : createId(),
content: item.content ?? defaultConditionContent,
}
block.items.splice(itemIndex, 0, newItem)
return newItem
const baseItem = item as ConditionItem
const newItem = {
...baseItem,
id: 'id' in item && item.id ? item.id : createId(),
content: baseItem.content ?? defaultConditionContent,
}
break
block.items.splice(itemIndex, 0, newItem)
return newItem
}
case InputBlockType.CHOICE: {
if (item.type === ItemType.BUTTON) {
const newItem = {
...item,
id: 'id' in item && item.id ? item.id : createId(),
content: item.content,
}
block.items.splice(itemIndex, 0, newItem)
return newItem
const baseItem = item as ButtonItem
const newItem = {
...baseItem,
id: 'id' in item && item.id ? item.id : createId(),
content: baseItem.content,
}
break
block.items.splice(itemIndex, 0, newItem)
return newItem
}
case InputBlockType.PICTURE_CHOICE: {
const baseItem = item as PictureChoiceItem
const newItem = {
...baseItem,
id: 'id' in baseItem && item.id ? item.id : createId(),
}
block.items.splice(itemIndex, 0, newItem)
return newItem
}
}
}
@@ -65,7 +74,9 @@ const itemsAction = (setTypebot: SetTypebot): ItemsActions => ({
) =>
setTypebot((typebot) =>
produce(typebot, (typebot) => {
const block = typebot.groups[groupIndex].blocks[blockIndex]
const block = typebot.groups[groupIndex].blocks[
blockIndex
] as BlockWithCreatableItems
const newItem = createItem(block, item, itemIndex)