fix(dashboard): 🩹 typebot buttons menu
This commit is contained in:
@@ -10,7 +10,7 @@ import { Block } from 'models'
|
|||||||
import { useGraph } from 'contexts/GraphContext'
|
import { useGraph } from 'contexts/GraphContext'
|
||||||
import { useStepDnd } from 'contexts/StepDndContext'
|
import { useStepDnd } from 'contexts/StepDndContext'
|
||||||
import { StepsList } from './StepsList'
|
import { StepsList } from './StepsList'
|
||||||
import { filterTable, isDefined } from 'utils'
|
import { isDefined } from 'utils'
|
||||||
import { useTypebot } from 'contexts/TypebotContext/TypebotContext'
|
import { useTypebot } from 'contexts/TypebotContext/TypebotContext'
|
||||||
import { ContextMenu } from 'components/shared/ContextMenu'
|
import { ContextMenu } from 'components/shared/ContextMenu'
|
||||||
import { BlockNodeContextMenu } from './BlockNodeContextMenu'
|
import { BlockNodeContextMenu } from './BlockNodeContextMenu'
|
||||||
@@ -114,12 +114,7 @@ export const BlockNode = ({ block }: Props) => {
|
|||||||
/>
|
/>
|
||||||
<EditableInput minW="0" px="1" />
|
<EditableInput minW="0" px="1" />
|
||||||
</Editable>
|
</Editable>
|
||||||
{typebot && (
|
{typebot && <StepsList blockId={block.id} stepIds={block.stepIds} />}
|
||||||
<StepsList
|
|
||||||
blockId={block.id}
|
|
||||||
steps={filterTable(block.stepIds, typebot?.steps)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export const StepNode = ({
|
|||||||
const { query } = useRouter()
|
const { query } = useRouter()
|
||||||
const { setConnectingIds, connectingIds, openedStepId, setOpenedStepId } =
|
const { setConnectingIds, connectingIds, openedStepId, setOpenedStepId } =
|
||||||
useGraph()
|
useGraph()
|
||||||
const { moveStep } = useTypebot()
|
const { detachStepFromBlock } = useTypebot()
|
||||||
const [isConnecting, setIsConnecting] = useState(false)
|
const [isConnecting, setIsConnecting] = useState(false)
|
||||||
const [mouseDownEvent, setMouseDownEvent] =
|
const [mouseDownEvent, setMouseDownEvent] =
|
||||||
useState<{ absolute: Coordinates; relative: Coordinates }>()
|
useState<{ absolute: Coordinates; relative: Coordinates }>()
|
||||||
@@ -116,8 +116,9 @@ export const StepNode = ({
|
|||||||
onMouseDown &&
|
onMouseDown &&
|
||||||
(event.movementX > 0 || event.movementY > 0)
|
(event.movementX > 0 || event.movementY > 0)
|
||||||
if (isMovingAndIsMouseDown && step.type !== 'start') {
|
if (isMovingAndIsMouseDown && step.type !== 'start') {
|
||||||
|
console.log(step)
|
||||||
onMouseDown(mouseDownEvent, step)
|
onMouseDown(mouseDownEvent, step)
|
||||||
moveStep(step.id)
|
detachStepFromBlock(step.id)
|
||||||
setMouseDownEvent(undefined)
|
setMouseDownEvent(undefined)
|
||||||
}
|
}
|
||||||
const element = event.currentTarget as HTMLDivElement
|
const element = event.currentTarget as HTMLDivElement
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Box, Flex, Image, Text } from '@chakra-ui/react'
|
import { Box, Image, Text } from '@chakra-ui/react'
|
||||||
import {
|
import {
|
||||||
Step,
|
Step,
|
||||||
StartStep,
|
StartStep,
|
||||||
@@ -7,9 +7,12 @@ import {
|
|||||||
LogicStepType,
|
LogicStepType,
|
||||||
IntegrationStepType,
|
IntegrationStepType,
|
||||||
} from 'models'
|
} from 'models'
|
||||||
|
import { isInputStep } from 'utils'
|
||||||
import { ChoiceItemsList } from '../ChoiceInputStepNode/ChoiceItemsList'
|
import { ChoiceItemsList } from '../ChoiceInputStepNode/ChoiceItemsList'
|
||||||
import { ConditionNodeContent } from './ConditionNodeContent'
|
import { ConditionNodeContent } from './ConditionNodeContent'
|
||||||
import { SetVariableNodeContent } from './SetVariableNodeContent'
|
import { SetVariableNodeContent } from './SetVariableNodeContent'
|
||||||
|
import { StepNodeContentWithVariable } from './StepNodeContentWithVariable'
|
||||||
|
import { TextBubbleNodeContent } from './TextBubbleNodeContent'
|
||||||
import { VideoStepNodeContent } from './VideoStepNodeContent'
|
import { VideoStepNodeContent } from './VideoStepNodeContent'
|
||||||
import { WebhookContent } from './WebhookContent'
|
import { WebhookContent } from './WebhookContent'
|
||||||
|
|
||||||
@@ -18,21 +21,12 @@ type Props = {
|
|||||||
isConnectable?: boolean
|
isConnectable?: boolean
|
||||||
}
|
}
|
||||||
export const StepNodeContent = ({ step }: Props) => {
|
export const StepNodeContent = ({ step }: Props) => {
|
||||||
|
if (isInputStep(step) && step.options.variableId) {
|
||||||
|
return <StepNodeContentWithVariable step={step} />
|
||||||
|
}
|
||||||
switch (step.type) {
|
switch (step.type) {
|
||||||
case BubbleStepType.TEXT: {
|
case BubbleStepType.TEXT: {
|
||||||
return (
|
return <TextBubbleNodeContent step={step} />
|
||||||
<Flex
|
|
||||||
flexDir={'column'}
|
|
||||||
opacity={step.content.html === '' ? '0.5' : '1'}
|
|
||||||
className="slate-html-container"
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html:
|
|
||||||
step.content.html === ''
|
|
||||||
? `<p>Click to edit...</p>`
|
|
||||||
: step.content.html,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
case BubbleStepType.IMAGE: {
|
case BubbleStepType.IMAGE: {
|
||||||
return !step.content?.url ? (
|
return !step.content?.url ? (
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { InputStep } from 'models'
|
||||||
|
import { chakra, Text } from '@chakra-ui/react'
|
||||||
|
import React from 'react'
|
||||||
|
import { useTypebot } from 'contexts/TypebotContext'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
step: InputStep
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StepNodeContentWithVariable = ({ step }: Props) => {
|
||||||
|
const { typebot } = useTypebot()
|
||||||
|
const variableName =
|
||||||
|
typebot?.variables.byId[step.options.variableId as string].name
|
||||||
|
return (
|
||||||
|
<Text>
|
||||||
|
Collect{' '}
|
||||||
|
<chakra.span
|
||||||
|
bgColor="orange.400"
|
||||||
|
color="white"
|
||||||
|
rounded="md"
|
||||||
|
py="0.5"
|
||||||
|
px="1"
|
||||||
|
>
|
||||||
|
{variableName}
|
||||||
|
</chakra.span>
|
||||||
|
</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react'
|
||||||
|
import { useTypebot } from 'contexts/TypebotContext'
|
||||||
|
import { TextBubbleStep } from 'models'
|
||||||
|
import React from 'react'
|
||||||
|
import { parseVariableHighlight } from 'services/utils'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
step: TextBubbleStep
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TextBubbleNodeContent = ({ step }: Props) => {
|
||||||
|
const { typebot } = useTypebot()
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
flexDir={'column'}
|
||||||
|
opacity={step.content.html === '' ? '0.5' : '1'}
|
||||||
|
className="slate-html-container"
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html:
|
||||||
|
step.content.html === ''
|
||||||
|
? `<p>Click to edit...</p>`
|
||||||
|
: parseVariableHighlight(step.content.html, typebot),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEventListener, Stack, Flex, Portal } from '@chakra-ui/react'
|
import { useEventListener, Stack, Flex, Portal } from '@chakra-ui/react'
|
||||||
import { DraggableStep, Step, Table } from 'models'
|
import { DraggableStep } from 'models'
|
||||||
import { useStepDnd } from 'contexts/StepDndContext'
|
import { useStepDnd } from 'contexts/StepDndContext'
|
||||||
import { Coordinates } from 'contexts/GraphContext'
|
import { Coordinates } from 'contexts/GraphContext'
|
||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
@@ -8,10 +8,10 @@ import { useTypebot } from 'contexts/TypebotContext'
|
|||||||
|
|
||||||
export const StepsList = ({
|
export const StepsList = ({
|
||||||
blockId,
|
blockId,
|
||||||
steps,
|
stepIds,
|
||||||
}: {
|
}: {
|
||||||
blockId: string
|
blockId: string
|
||||||
steps: Table<Step>
|
stepIds: string[]
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
draggedStep,
|
draggedStep,
|
||||||
@@ -21,7 +21,7 @@ export const StepsList = ({
|
|||||||
setDraggedStepType,
|
setDraggedStepType,
|
||||||
setMouseOverBlockId,
|
setMouseOverBlockId,
|
||||||
} = useStepDnd()
|
} = useStepDnd()
|
||||||
const { createStep } = useTypebot()
|
const { typebot, createStep } = useTypebot()
|
||||||
const [expandedPlaceholderIndex, setExpandedPlaceholderIndex] = useState<
|
const [expandedPlaceholderIndex, setExpandedPlaceholderIndex] = useState<
|
||||||
number | undefined
|
number | undefined
|
||||||
>()
|
>()
|
||||||
@@ -59,14 +59,14 @@ export const StepsList = ({
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
setMouseOverBlockId(undefined)
|
setMouseOverBlockId(undefined)
|
||||||
setExpandedPlaceholderIndex(undefined)
|
setExpandedPlaceholderIndex(undefined)
|
||||||
if (draggedStepType) {
|
if (!draggedStep && !draggedStepType) return
|
||||||
createStep(blockId, draggedStepType, expandedPlaceholderIndex)
|
createStep(
|
||||||
setDraggedStepType(undefined)
|
blockId,
|
||||||
}
|
draggedStep || draggedStepType,
|
||||||
if (draggedStep) {
|
expandedPlaceholderIndex
|
||||||
createStep(blockId, draggedStep, expandedPlaceholderIndex)
|
)
|
||||||
setDraggedStep(undefined)
|
setDraggedStep(undefined)
|
||||||
}
|
setDraggedStepType(undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleStepMouseDown = (
|
const handleStepMouseDown = (
|
||||||
@@ -107,31 +107,32 @@ export const StepsList = ({
|
|||||||
rounded="lg"
|
rounded="lg"
|
||||||
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
|
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
|
||||||
/>
|
/>
|
||||||
{steps.allIds.map((stepId, idx) => (
|
{typebot &&
|
||||||
<Stack key={stepId} spacing={1}>
|
stepIds.map((stepId, idx) => (
|
||||||
<StepNode
|
<Stack key={stepId} spacing={1}>
|
||||||
key={stepId}
|
<StepNode
|
||||||
step={steps.byId[stepId]}
|
key={stepId}
|
||||||
isConnectable={steps.allIds.length - 1 === idx}
|
step={typebot?.steps.byId[stepId]}
|
||||||
onMouseMoveTopOfElement={() => handleMouseOnTopOfStep(idx)}
|
isConnectable={stepIds.length - 1 === idx}
|
||||||
onMouseMoveBottomOfElement={() => {
|
onMouseMoveTopOfElement={() => handleMouseOnTopOfStep(idx)}
|
||||||
handleMouseOnBottomOfStep(idx)
|
onMouseMoveBottomOfElement={() => {
|
||||||
}}
|
handleMouseOnBottomOfStep(idx)
|
||||||
onMouseDown={handleStepMouseDown}
|
}}
|
||||||
/>
|
onMouseDown={handleStepMouseDown}
|
||||||
<Flex
|
/>
|
||||||
h={
|
<Flex
|
||||||
showSortPlaceholders && expandedPlaceholderIndex === idx + 1
|
h={
|
||||||
? '50px'
|
showSortPlaceholders && expandedPlaceholderIndex === idx + 1
|
||||||
: '2px'
|
? '50px'
|
||||||
}
|
: '2px'
|
||||||
bgColor={'gray.300'}
|
}
|
||||||
visibility={showSortPlaceholders ? 'visible' : 'hidden'}
|
bgColor={'gray.300'}
|
||||||
rounded="lg"
|
visibility={showSortPlaceholders ? 'visible' : 'hidden'}
|
||||||
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
|
rounded="lg"
|
||||||
/>
|
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
|
||||||
</Stack>
|
/>
|
||||||
))}
|
</Stack>
|
||||||
|
))}
|
||||||
{draggedStep && draggedStep.blockId === blockId && (
|
{draggedStep && draggedStep.blockId === blockId && (
|
||||||
<Portal>
|
<Portal>
|
||||||
<StepNodeOverlay
|
<StepNodeOverlay
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
import { FolderPlusIcon } from 'assets/icons'
|
import { FolderPlusIcon } from 'assets/icons'
|
||||||
import { useTypebotDnd } from 'contexts/TypebotDndContext'
|
import { useTypebotDnd } from 'contexts/TypebotDndContext'
|
||||||
import { Typebot } from 'models'
|
import { Typebot } from 'models'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { createFolder, useFolders } from 'services/folders'
|
import { createFolder, useFolders } from 'services/folders'
|
||||||
import { patchTypebot, useTypebots } from 'services/typebots'
|
import { patchTypebot, useTypebots } from 'services/typebots'
|
||||||
import { BackButton } from './FolderContent/BackButton'
|
import { BackButton } from './FolderContent/BackButton'
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ export const MoreButton = ({ children, ...props }: Props) => {
|
|||||||
<MenuButton
|
<MenuButton
|
||||||
as={IconButton}
|
as={IconButton}
|
||||||
icon={<MoreVerticalIcon />}
|
icon={<MoreVerticalIcon />}
|
||||||
onMouseUp={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
onMouseDown={(e) => e.stopPropagation()}
|
|
||||||
colorScheme="gray"
|
colorScheme="gray"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { GlobeIcon, GripIcon, ToolIcon } from 'assets/icons'
|
|||||||
import { deleteTypebot, duplicateTypebot } from 'services/typebots'
|
import { deleteTypebot, duplicateTypebot } from 'services/typebots'
|
||||||
import { Typebot } from 'models'
|
import { Typebot } from 'models'
|
||||||
import { useTypebotDnd } from 'contexts/TypebotDndContext'
|
import { useTypebotDnd } from 'contexts/TypebotDndContext'
|
||||||
|
import { useDebounce } from 'use-debounce'
|
||||||
|
|
||||||
type ChatbotCardProps = {
|
type ChatbotCardProps = {
|
||||||
typebot: Typebot
|
typebot: Typebot
|
||||||
@@ -32,6 +33,7 @@ export const TypebotButton = ({
|
|||||||
}: ChatbotCardProps) => {
|
}: ChatbotCardProps) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { draggedTypebot } = useTypebotDnd()
|
const { draggedTypebot } = useTypebotDnd()
|
||||||
|
const [draggedTypebotDebounced] = useDebounce(draggedTypebot, 200)
|
||||||
const {
|
const {
|
||||||
isOpen: isDeleteOpen,
|
isOpen: isDeleteOpen,
|
||||||
onOpen: onDeleteOpen,
|
onOpen: onDeleteOpen,
|
||||||
@@ -44,7 +46,7 @@ export const TypebotButton = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const handleTypebotClick = () => {
|
const handleTypebotClick = () => {
|
||||||
if (draggedTypebot) return
|
if (draggedTypebotDebounced) return
|
||||||
router.push(
|
router.push(
|
||||||
isMobile
|
isMobile
|
||||||
? `/typebots/${typebot.id}/results/responses`
|
? `/typebots/${typebot.id}/results/responses`
|
||||||
@@ -72,10 +74,15 @@ export const TypebotButton = ({
|
|||||||
if (createdTypebot) router.push(`/typebots/${createdTypebot?.id}`)
|
if (createdTypebot) router.push(`/typebots/${createdTypebot?.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleDeleteClick = (e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
onDeleteOpen()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
as={WrapItem}
|
as={WrapItem}
|
||||||
onMouseUp={handleTypebotClick}
|
onClick={handleTypebotClick}
|
||||||
display="flex"
|
display="flex"
|
||||||
flexDir="column"
|
flexDir="column"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -108,13 +115,7 @@ export const TypebotButton = ({
|
|||||||
aria-label={`Show ${typebot.name} menu`}
|
aria-label={`Show ${typebot.name} menu`}
|
||||||
>
|
>
|
||||||
<MenuItem onClick={handleDuplicateClick}>Duplicate</MenuItem>
|
<MenuItem onClick={handleDuplicateClick}>Duplicate</MenuItem>
|
||||||
<MenuItem
|
<MenuItem color="red" onClick={handleDeleteClick}>
|
||||||
color="red"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
onDeleteOpen()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Delete
|
Delete
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MoreButton>
|
</MoreButton>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import { edgesAction, EdgesActions } from './actions/edges'
|
|||||||
import { webhooksAction, WebhooksAction } from './actions/webhooks'
|
import { webhooksAction, WebhooksAction } from './actions/webhooks'
|
||||||
import { useDebounce } from 'use-debounce'
|
import { useDebounce } from 'use-debounce'
|
||||||
|
|
||||||
const autoSaveTimeout = 10000
|
const autoSaveTimeout = 40000
|
||||||
|
|
||||||
type UpdateTypebotPayload = Partial<{
|
type UpdateTypebotPayload = Partial<{
|
||||||
theme: Theme
|
theme: Theme
|
||||||
|
|||||||
@@ -17,23 +17,24 @@ import { deleteWebhookDraft } from './webhooks'
|
|||||||
export type StepsActions = {
|
export type StepsActions = {
|
||||||
createStep: (
|
createStep: (
|
||||||
blockId: string,
|
blockId: string,
|
||||||
step: DraggableStep | DraggableStepType,
|
step?: DraggableStep | DraggableStepType,
|
||||||
index?: number
|
index?: number
|
||||||
) => void
|
) => void
|
||||||
updateStep: (
|
updateStep: (
|
||||||
stepId: string,
|
stepId: string,
|
||||||
updates: Partial<Omit<Step, 'id' | 'type'>>
|
updates: Partial<Omit<Step, 'id' | 'type'>>
|
||||||
) => void
|
) => void
|
||||||
moveStep: (stepId: string) => void
|
detachStepFromBlock: (stepId: string) => void
|
||||||
deleteStep: (stepId: string) => void
|
deleteStep: (stepId: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const stepsAction = (setTypebot: Updater<Typebot>): StepsActions => ({
|
export const stepsAction = (setTypebot: Updater<Typebot>): StepsActions => ({
|
||||||
createStep: (
|
createStep: (
|
||||||
blockId: string,
|
blockId: string,
|
||||||
step: DraggableStep | DraggableStepType,
|
step?: DraggableStep | DraggableStepType,
|
||||||
index?: number
|
index?: number
|
||||||
) => {
|
) => {
|
||||||
|
if (!step) return
|
||||||
setTypebot((typebot) => {
|
setTypebot((typebot) => {
|
||||||
createStepDraft(typebot, step, blockId, index)
|
createStepDraft(typebot, step, blockId, index)
|
||||||
removeEmptyBlocks(typebot)
|
removeEmptyBlocks(typebot)
|
||||||
@@ -43,7 +44,7 @@ export const stepsAction = (setTypebot: Updater<Typebot>): StepsActions => ({
|
|||||||
setTypebot((typebot) => {
|
setTypebot((typebot) => {
|
||||||
typebot.steps.byId[stepId] = { ...typebot.steps.byId[stepId], ...updates }
|
typebot.steps.byId[stepId] = { ...typebot.steps.byId[stepId], ...updates }
|
||||||
}),
|
}),
|
||||||
moveStep: (stepId: string) => {
|
detachStepFromBlock: (stepId: string) => {
|
||||||
setTypebot((typebot) => {
|
setTypebot((typebot) => {
|
||||||
removeStepIdFromBlock(typebot, stepId)
|
removeStepIdFromBlock(typebot, stepId)
|
||||||
})
|
})
|
||||||
@@ -54,23 +55,13 @@ export const stepsAction = (setTypebot: Updater<Typebot>): StepsActions => ({
|
|||||||
if (isChoiceInput(step)) deleteChoiceItemsInsideStep(typebot, step)
|
if (isChoiceInput(step)) deleteChoiceItemsInsideStep(typebot, step)
|
||||||
if (isWebhookStep(step))
|
if (isWebhookStep(step))
|
||||||
deleteWebhookDraft(step.options?.webhookId)(typebot)
|
deleteWebhookDraft(step.options?.webhookId)(typebot)
|
||||||
deleteAssociatedEdges(typebot, stepId)
|
deleteEdgeDraft(typebot, step.edgeId)
|
||||||
removeStepIdFromBlock(typebot, stepId)
|
removeStepIdFromBlock(typebot, stepId)
|
||||||
deleteStepDraft(typebot, stepId)
|
deleteStepDraft(typebot, stepId)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const deleteAssociatedEdges = (
|
|
||||||
typebot: WritableDraft<Typebot>,
|
|
||||||
stepId: string
|
|
||||||
) => {
|
|
||||||
typebot.edges.allIds.forEach((edgeId) => {
|
|
||||||
if (typebot.edges.byId[edgeId].from.stepId === stepId)
|
|
||||||
deleteEdgeDraft(typebot, edgeId)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeStepIdFromBlock = (
|
const removeStepIdFromBlock = (
|
||||||
typebot: WritableDraft<Typebot>,
|
typebot: WritableDraft<Typebot>,
|
||||||
stepId: string
|
stepId: string
|
||||||
@@ -93,18 +84,32 @@ export const createStepDraft = (
|
|||||||
step: DraggableStep | DraggableStepType,
|
step: DraggableStep | DraggableStepType,
|
||||||
blockId: string,
|
blockId: string,
|
||||||
index?: number
|
index?: number
|
||||||
|
) =>
|
||||||
|
typeof step === 'string'
|
||||||
|
? createNewStep(typebot, step, blockId, index)
|
||||||
|
: moveStepToBlock(typebot, step, blockId, index)
|
||||||
|
|
||||||
|
const createNewStep = (
|
||||||
|
typebot: WritableDraft<Typebot>,
|
||||||
|
type: DraggableStepType,
|
||||||
|
blockId: string,
|
||||||
|
index?: number
|
||||||
) => {
|
) => {
|
||||||
const newStep =
|
const newStep = parseNewStep(type, blockId)
|
||||||
typeof step === 'string'
|
|
||||||
? parseNewStep(step, blockId)
|
|
||||||
: { ...step, blockId }
|
|
||||||
typebot.steps.byId[newStep.id] = newStep
|
typebot.steps.byId[newStep.id] = newStep
|
||||||
if (isChoiceInput(newStep) && newStep.options.itemIds.length === 0)
|
if (isChoiceInput(newStep))
|
||||||
createChoiceItemDraft(typebot, { stepId: newStep.id })
|
createChoiceItemDraft(typebot, { stepId: newStep.id })
|
||||||
typebot.steps.allIds.push(newStep.id)
|
typebot.steps.allIds.push(newStep.id)
|
||||||
typebot.blocks.byId[blockId].stepIds.splice(index ?? 0, 0, newStep.id)
|
typebot.blocks.byId[blockId].stepIds.splice(index ?? 0, 0, newStep.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const moveStepToBlock = (
|
||||||
|
typebot: WritableDraft<Typebot>,
|
||||||
|
step: DraggableStep,
|
||||||
|
blockId: string,
|
||||||
|
index?: number
|
||||||
|
) => typebot.blocks.byId[blockId].stepIds.splice(index ?? 0, 0, step.id)
|
||||||
|
|
||||||
const deleteChoiceItemsInsideStep = (
|
const deleteChoiceItemsInsideStep = (
|
||||||
typebot: WritableDraft<Typebot>,
|
typebot: WritableDraft<Typebot>,
|
||||||
step: ChoiceInputStep
|
step: ChoiceInputStep
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import imageCompression from 'browser-image-compression'
|
import imageCompression from 'browser-image-compression'
|
||||||
import { Parser } from 'htmlparser2'
|
import { Parser } from 'htmlparser2'
|
||||||
import { Step } from 'models'
|
import { Step, Typebot } from 'models'
|
||||||
|
|
||||||
export const fetcher = async (input: RequestInfo, init?: RequestInit) => {
|
export const fetcher = async (input: RequestInfo, init?: RequestInit) => {
|
||||||
const res = await fetch(input, init)
|
const res = await fetch(input, init)
|
||||||
@@ -99,3 +99,19 @@ export const removeUndefinedFields = <T>(obj: T): T =>
|
|||||||
)
|
)
|
||||||
|
|
||||||
export const stepHasOptions = (step: Step) => 'options' in step
|
export const stepHasOptions = (step: Step) => 'options' in step
|
||||||
|
|
||||||
|
export const parseVariableHighlight = (content: string, typebot?: Typebot) => {
|
||||||
|
if (!typebot) return content
|
||||||
|
const varNames = typebot.variables.allIds.map(
|
||||||
|
(varId) => typebot.variables.byId[varId].name
|
||||||
|
)
|
||||||
|
return content.replace(/\{\{(.*?)\}\}/g, (fullMatch, foundVar) => {
|
||||||
|
if (varNames.some((val) => foundVar.includes(val))) {
|
||||||
|
return `<span style="background-color:#ff8b1a; color:#ffffff; padding: 0.125rem 0.25rem; border-radius: 0.35rem">${fullMatch.replace(
|
||||||
|
/{{|}}/g,
|
||||||
|
''
|
||||||
|
)}</span>`
|
||||||
|
}
|
||||||
|
return fullMatch
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user