import { Editable, EditableInput, EditablePreview, IconButton, Stack, } from '@chakra-ui/react' import React, { useEffect, useRef, useState } from 'react' import { Block } from 'models' import { useGraph } from 'contexts/GraphContext' import { useStepDnd } from 'contexts/GraphDndContext' import { StepNodesList } from '../StepNode/StepNodesList' import { isDefined, isNotDefined } from 'utils' import { useTypebot } from 'contexts/TypebotContext/TypebotContext' import { ContextMenu } from 'components/shared/ContextMenu' import { BlockNodeContextMenu } from './BlockNodeContextMenu' import { useDebounce } from 'use-debounce' import { setMultipleRefs } from 'services/utils' import { DraggableCore, DraggableData, DraggableEvent } from 'react-draggable' import { PlayIcon } from 'assets/icons' import { RightPanel, useEditor } from 'contexts/EditorContext' type Props = { block: Block blockIndex: number } export const BlockNode = ({ block, blockIndex }: Props) => { const { connectingIds, setConnectingIds, previewingEdge, blocksCoordinates, updateBlockCoordinates, isReadOnly, focusedBlockId, setFocusedBlockId, graphPosition, } = useGraph() const { typebot, updateBlock } = useTypebot() const { setMouseOverBlock, mouseOverBlock } = useStepDnd() const [isMouseDown, setIsMouseDown] = useState(false) const [isConnecting, setIsConnecting] = useState(false) const { setRightPanel, setStartPreviewAtBlock } = useEditor() const isPreviewing = previewingEdge?.from.blockId === block.id || (previewingEdge?.to.blockId === block.id && isNotDefined(previewingEdge.to.stepId)) const isStartBlock = isDefined(block.steps[0]) && block.steps[0].type === 'start' const blockCoordinates = blocksCoordinates[block.id] const blockRef = useRef(null) const [debouncedBlockPosition] = useDebounce(blockCoordinates, 100) useEffect(() => { if (!debouncedBlockPosition || isReadOnly) return if ( debouncedBlockPosition?.x === block.graphCoordinates.x && debouncedBlockPosition.y === block.graphCoordinates.y ) return updateBlock(blockIndex, { graphCoordinates: debouncedBlockPosition }) // eslint-disable-next-line react-hooks/exhaustive-deps }, [debouncedBlockPosition]) useEffect(() => { setIsConnecting( connectingIds?.target?.blockId === block.id && isNotDefined(connectingIds.target?.stepId) ) }, [block.id, connectingIds]) const handleTitleSubmit = (title: string) => updateBlock(blockIndex, { title }) const handleMouseDown = (e: React.MouseEvent) => { e.stopPropagation() } const handleMouseEnter = () => { if (isReadOnly) return if (mouseOverBlock?.id !== block.id && !isStartBlock) setMouseOverBlock({ id: block.id, ref: blockRef }) if (connectingIds) setConnectingIds({ ...connectingIds, target: { blockId: block.id } }) } const handleMouseLeave = () => { if (isReadOnly) return setMouseOverBlock(undefined) if (connectingIds) setConnectingIds({ ...connectingIds, target: undefined }) } const onDrag = (_: DraggableEvent, draggableData: DraggableData) => { const { deltaX, deltaY } = draggableData updateBlockCoordinates(block.id, { x: blockCoordinates.x + deltaX / graphPosition.scale, y: blockCoordinates.y + deltaY / graphPosition.scale, }) } const onDragStart = () => { setFocusedBlockId(block.id) setIsMouseDown(true) } const startPreviewAtThisBlock = () => { setStartPreviewAtBlock(block.id) setRightPanel(RightPanel.PREVIEW) } const onDragStop = () => setIsMouseDown(false) return ( renderMenu={() => } isDisabled={isReadOnly || isStartBlock} > {(ref, isOpened) => ( e.stopPropagation()} > e.stopPropagation()} /> {typebot && ( )} } aria-label={'Preview bot from this group'} pos="absolute" right={2} top={0} size="sm" variant="outline" onClick={startPreviewAtThisBlock} /> )} ) }