diff --git a/apps/builder/src/features/editor/components/BlockLabel.tsx b/apps/builder/src/features/editor/components/BlockLabel.tsx index 35baa6f34..b1053584b 100644 --- a/apps/builder/src/features/editor/components/BlockLabel.tsx +++ b/apps/builder/src/features/editor/components/BlockLabel.tsx @@ -1,225 +1,97 @@ import { Text, TextProps } from '@chakra-ui/react' import React from 'react' -import { useTranslate } from '@tolgee/react' +import { TFnType, useTranslate } from '@tolgee/react' import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants' import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants' import { IntegrationBlockType } from '@typebot.io/schemas/features/blocks/integrations/constants' import { LogicBlockType } from '@typebot.io/schemas/features/blocks/logic/constants' import { Block } from '@typebot.io/schemas' import { ForgedBlockLabel } from '@/features/forge/ForgedBlockLabel' +import { isForgedBlockType } from '@typebot.io/schemas/features/blocks/forged/helpers' +import { + isBubbleBlockType, + isInputBlockType, + isIntegrationBlockType, + isLogicBlockType, +} from '@typebot.io/schemas/helpers' type Props = { type: Block['type'] } & TextProps export const BlockLabel = ({ type, ...props }: Props): JSX.Element => { const { t } = useTranslate() - switch (type) { - case 'start': - return ( - - {t('editor.sidebarBlock.start.label')} - - ) - case BubbleBlockType.TEXT: - case InputBlockType.TEXT: - return ( - - {t('editor.sidebarBlock.text.label')} - - ) - case BubbleBlockType.IMAGE: - return ( - - {t('editor.sidebarBlock.image.label')} - - ) - case BubbleBlockType.VIDEO: - return ( - - {t('editor.sidebarBlock.video.label')} - - ) - case BubbleBlockType.EMBED: - return ( - - {t('editor.sidebarBlock.embed.label')} - - ) - case BubbleBlockType.AUDIO: - return ( - - {t('editor.sidebarBlock.audio.label')} - - ) - case InputBlockType.NUMBER: - return ( - - {t('editor.sidebarBlock.number.label')} - - ) - case InputBlockType.EMAIL: - return ( - - {t('editor.sidebarBlock.email.label')} - - ) - case InputBlockType.URL: - return ( - - {t('editor.sidebarBlock.website.label')} - - ) - case InputBlockType.DATE: - return ( - - {t('editor.sidebarBlock.date.label')} - - ) - case InputBlockType.PHONE: - return ( - - {t('editor.sidebarBlock.phone.label')} - - ) - case InputBlockType.CHOICE: - return ( - - {t('editor.sidebarBlock.button.label')} - - ) - case InputBlockType.PICTURE_CHOICE: - return ( - - {t('editor.sidebarBlock.picChoice.label')} - - ) - case InputBlockType.PAYMENT: - return ( - - {t('editor.sidebarBlock.payment.label')} - - ) - case InputBlockType.RATING: - return ( - - {t('editor.sidebarBlock.rating.label')} - - ) - case InputBlockType.FILE: - return ( - - {t('editor.sidebarBlock.file.label')} - - ) - case LogicBlockType.SET_VARIABLE: - return ( - - {t('editor.sidebarBlock.setVariable.label')} - - ) - case LogicBlockType.CONDITION: - return ( - - {t('editor.sidebarBlock.condition.label')} - - ) - case LogicBlockType.REDIRECT: - return ( - - {t('editor.sidebarBlock.redirect.label')} - - ) - case LogicBlockType.SCRIPT: - return ( - - {t('editor.sidebarBlock.script.label')} - - ) - case LogicBlockType.TYPEBOT_LINK: - return ( - - {t('editor.sidebarBlock.typebot.label')} - - ) - case LogicBlockType.WAIT: - return ( - - {t('editor.sidebarBlock.wait.label')} - - ) - case LogicBlockType.JUMP: - return ( - - {t('editor.sidebarBlock.jump.label')} - - ) - case LogicBlockType.AB_TEST: - return ( - - {t('editor.sidebarBlock.abTest.label')} - - ) - case IntegrationBlockType.GOOGLE_SHEETS: - return ( - - {t('editor.sidebarBlock.sheets.label')} - - ) - case IntegrationBlockType.GOOGLE_ANALYTICS: - return ( - - {t('editor.sidebarBlock.analytics.label')} - - ) - case IntegrationBlockType.WEBHOOK: - return ( - - HTTP request - - ) - case IntegrationBlockType.ZAPIER: - return ( - - {t('editor.sidebarBlock.zapier.label')} - - ) - case IntegrationBlockType.MAKE_COM: - return ( - - {t('editor.sidebarBlock.makecom.label')} - - ) - case IntegrationBlockType.PABBLY_CONNECT: - return ( - - {t('editor.sidebarBlock.pabbly.label')} - - ) - case IntegrationBlockType.EMAIL: - return ( - - {t('editor.sidebarBlock.email.label')} - - ) - case IntegrationBlockType.CHATWOOT: - return ( - - {t('editor.sidebarBlock.chatwoot.label')} - - ) - case IntegrationBlockType.OPEN_AI: - return ( - - {t('editor.sidebarBlock.openai.label')} - - ) - case IntegrationBlockType.PIXEL: - return ( - - {t('editor.sidebarBlock.pixel.label')} - - ) - default: - return - } + if (isForgedBlockType(type)) + return + + const label = isBubbleBlockType(type) + ? getBubbleBlockLabel(t)[type] + : isInputBlockType(type) + ? getInputBlockLabel(t)[type] + : isLogicBlockType(type) + ? getLogicBlockLabel(t)[type] + : isIntegrationBlockType(type) + ? getIntegrationBlockLabel(t)[type] + : t('editor.sidebarBlock.start.label') + + return ( + + {label} + + ) } + +export const getBubbleBlockLabel = ( + t: TFnType +): Record => ({ + [BubbleBlockType.TEXT]: t('editor.sidebarBlock.text.label'), + [BubbleBlockType.IMAGE]: t('editor.sidebarBlock.image.label'), + [BubbleBlockType.VIDEO]: t('editor.sidebarBlock.video.label'), + [BubbleBlockType.EMBED]: t('editor.sidebarBlock.embed.label'), + [BubbleBlockType.AUDIO]: t('editor.sidebarBlock.audio.label'), +}) + +export const getInputBlockLabel = ( + t: TFnType +): Record => ({ + [InputBlockType.NUMBER]: t('editor.sidebarBlock.number.label'), + [InputBlockType.EMAIL]: t('editor.sidebarBlock.email.label'), + [InputBlockType.TEXT]: t('editor.sidebarBlock.text.label'), + [InputBlockType.URL]: t('editor.sidebarBlock.website.label'), + [InputBlockType.DATE]: t('editor.sidebarBlock.date.label'), + [InputBlockType.PHONE]: t('editor.sidebarBlock.phone.label'), + [InputBlockType.CHOICE]: t('editor.sidebarBlock.button.label'), + [InputBlockType.PICTURE_CHOICE]: t('editor.sidebarBlock.picChoice.label'), + [InputBlockType.PAYMENT]: t('editor.sidebarBlock.payment.label'), + [InputBlockType.RATING]: t('editor.sidebarBlock.rating.label'), + [InputBlockType.FILE]: t('editor.sidebarBlock.file.label'), +}) + +export const getLogicBlockLabel = ( + t: TFnType +): Record => ({ + [LogicBlockType.SET_VARIABLE]: t('editor.sidebarBlock.setVariable.label'), + [LogicBlockType.CONDITION]: t('editor.sidebarBlock.condition.label'), + [LogicBlockType.REDIRECT]: t('editor.sidebarBlock.redirect.label'), + [LogicBlockType.SCRIPT]: t('editor.sidebarBlock.script.label'), + [LogicBlockType.TYPEBOT_LINK]: t('editor.sidebarBlock.typebot.label'), + [LogicBlockType.WAIT]: t('editor.sidebarBlock.wait.label'), + [LogicBlockType.JUMP]: t('editor.sidebarBlock.jump.label'), + [LogicBlockType.AB_TEST]: t('editor.sidebarBlock.abTest.label'), +}) + +export const getIntegrationBlockLabel = ( + t: TFnType +): Record => ({ + [IntegrationBlockType.GOOGLE_SHEETS]: t('editor.sidebarBlock.sheets.label'), + [IntegrationBlockType.GOOGLE_ANALYTICS]: t( + 'editor.sidebarBlock.analytics.label' + ), + [IntegrationBlockType.WEBHOOK]: 'HTTP request', + [IntegrationBlockType.ZAPIER]: t('editor.sidebarBlock.zapier.label'), + [IntegrationBlockType.MAKE_COM]: t('editor.sidebarBlock.makecom.label'), + [IntegrationBlockType.PABBLY_CONNECT]: t('editor.sidebarBlock.pabbly.label'), + [IntegrationBlockType.EMAIL]: t('editor.sidebarBlock.email.label'), + [IntegrationBlockType.CHATWOOT]: t('editor.sidebarBlock.chatwoot.label'), + [IntegrationBlockType.OPEN_AI]: t('editor.sidebarBlock.openai.label'), + [IntegrationBlockType.PIXEL]: t('editor.sidebarBlock.pixel.label'), +}) diff --git a/apps/builder/src/features/editor/components/BlocksSideBar.tsx b/apps/builder/src/features/editor/components/BlocksSideBar.tsx index d9689e243..263de2962 100644 --- a/apps/builder/src/features/editor/components/BlocksSideBar.tsx +++ b/apps/builder/src/features/editor/components/BlocksSideBar.tsx @@ -19,13 +19,19 @@ import { LockedIcon, UnlockedIcon } from '@/components/icons' import { BlockCardOverlay } from './BlockCardOverlay' import { headerHeight } from '../constants' import { useTranslate } from '@tolgee/react' -import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants' import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants' import { IntegrationBlockType } from '@typebot.io/schemas/features/blocks/integrations/constants' import { LogicBlockType } from '@typebot.io/schemas/features/blocks/logic/constants' import { BlockV6 } from '@typebot.io/schemas' import { useDebouncedCallback } from 'use-debounce' import { forgedBlocks } from '@typebot.io/forge-repository/definitions' +import { + getBubbleBlockLabel, + getInputBlockLabel, + getIntegrationBlockLabel, + getLogicBlockLabel, +} from './BlockLabel' +import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants' // Integration blocks migrated to forged blocks const legacyIntegrationBlocks = [IntegrationBlockType.OPEN_AI] @@ -92,9 +98,8 @@ export const BlocksSideBar = () => { }) => { setSearchInput(event.target.value) } - const blocksArray = Object.values(forgedBlocks) - const filteredForgedBlockIds = blocksArray + const filteredForgedBlockIds = Object.values(forgedBlocks) .filter((block) => { return ( block.id.toLowerCase().includes(searchInput.toLowerCase()) || @@ -107,6 +112,35 @@ export const BlocksSideBar = () => { }) .map((block) => block.id) + const filteredBubbleBlockTypes = Object.values(BubbleBlockType).filter( + (type) => + getBubbleBlockLabel(t) + [type].toLowerCase() + .includes(searchInput.toLowerCase()) + ) + + const filteredInputBlockTypes = Object.values(InputBlockType).filter((type) => + getInputBlockLabel(t) + [type].toLowerCase() + .includes(searchInput.toLowerCase()) + ) + + const filteredLogicBlockTypes = Object.values(LogicBlockType).filter((type) => + getLogicBlockLabel(t) + [type].toLowerCase() + .includes(searchInput.toLowerCase()) + ) + + const filteredIntegrationBlockTypes = Object.values( + IntegrationBlockType + ).filter( + (type) => + getIntegrationBlockLabel(t) + [type].toLowerCase() + .includes(searchInput.toLowerCase()) && + !legacyIntegrationBlocks.includes(type) + ) + return ( { {t('editor.sidebarBlocks.blockType.bubbles.heading')} - {Object.values(BubbleBlockType) - .filter((type) => - type.toLowerCase().includes(searchInput.toLowerCase()) - ) - .map((type) => ( - - ))} + {filteredBubbleBlockTypes.map((type) => ( + + ))} @@ -188,17 +214,9 @@ export const BlocksSideBar = () => { {t('editor.sidebarBlocks.blockType.inputs.heading')} - {Object.values(InputBlockType) - .filter((type) => - type.toLowerCase().includes(searchInput.toLowerCase()) - ) - .map((type) => ( - - ))} + {filteredInputBlockTypes.map((type) => ( + + ))} @@ -207,17 +225,9 @@ export const BlocksSideBar = () => { {t('editor.sidebarBlocks.blockType.logic.heading')} - {Object.values(LogicBlockType) - .filter((type) => - type.toLowerCase().includes(searchInput.toLowerCase()) - ) - .map((type) => ( - - ))} + {filteredLogicBlockTypes.map((type) => ( + + ))} @@ -226,12 +236,8 @@ export const BlocksSideBar = () => { {t('editor.sidebarBlocks.blockType.integrations.heading')} - {Object.values(IntegrationBlockType) - .filter((type) => - type.toLowerCase().includes(searchInput.toLowerCase()) - ) + {filteredIntegrationBlockTypes .concat(filteredForgedBlockIds as any) - .filter((type) => !legacyIntegrationBlocks.includes(type)) .map((type) => ( (Object.values(BubbleBlockType) as string[]).includes(type) +export const isInputBlockType = (type: Block['type']): type is InputBlockType => + (Object.values(InputBlockType) as string[]).includes(type) + +export const isIntegrationBlockType = ( + type: Block['type'] +): type is IntegrationBlockType => + (Object.values(IntegrationBlockType) as string[]).includes(type) + +export const isLogicBlockType = (type: Block['type']): type is LogicBlockType => + (Object.values(LogicBlockType) as string[]).includes(type) + export const blockHasOptions = (block: Block): block is BlockWithOptions => 'options' in block