import { Editable, EditableInput, EditablePreview, IconButton, Stack, } from '@chakra-ui/react' import React, { useEffect, useRef, useState } from 'react' import { Group } from 'models' import { useGraph } from 'contexts/GraphContext' import { useBlockDnd } from 'contexts/GraphDndContext' import { BlockNodesList } from '../BlockNode/BlockNodesList' import { isDefined, isNotDefined } from 'utils' import { useTypebot } from 'contexts/TypebotContext/TypebotContext' import { ContextMenu } from 'components/shared/ContextMenu' import { GroupNodeContextMenu } from './GroupNodeContextMenu' 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 = { group: Group groupIndex: number } export const GroupNode = ({ group, groupIndex }: Props) => { const { connectingIds, setConnectingIds, previewingEdge, groupsCoordinates, updateGroupCoordinates, isReadOnly, focusedGroupId, setFocusedGroupId, graphPosition, } = useGraph() const { typebot, updateGroup } = useTypebot() const { setMouseOverGroup, mouseOverGroup } = useBlockDnd() const [isMouseDown, setIsMouseDown] = useState(false) const [isConnecting, setIsConnecting] = useState(false) const { setRightPanel, setStartPreviewAtGroup } = useEditor() const isPreviewing = previewingEdge?.from.groupId === group.id || (previewingEdge?.to.groupId === group.id && isNotDefined(previewingEdge.to.blockId)) const isStartGroup = isDefined(group.blocks[0]) && group.blocks[0].type === 'start' const groupCoordinates = groupsCoordinates[group.id] const groupRef = useRef(null) const [debouncedGroupPosition] = useDebounce(groupCoordinates, 100) useEffect(() => { if (!debouncedGroupPosition || isReadOnly) return if ( debouncedGroupPosition?.x === group.graphCoordinates.x && debouncedGroupPosition.y === group.graphCoordinates.y ) return updateGroup(groupIndex, { graphCoordinates: debouncedGroupPosition }) // eslint-disable-next-line react-hooks/exhaustive-deps }, [debouncedGroupPosition]) useEffect(() => { setIsConnecting( connectingIds?.target?.groupId === group.id && isNotDefined(connectingIds.target?.groupId) ) }, [connectingIds, group.id]) const handleTitleSubmit = (title: string) => updateGroup(groupIndex, { title }) const handleMouseDown = (e: React.MouseEvent) => { e.stopPropagation() } const handleMouseEnter = () => { if (isReadOnly) return if (mouseOverGroup?.id !== group.id && !isStartGroup) setMouseOverGroup({ id: group.id, ref: groupRef }) if (connectingIds) setConnectingIds({ ...connectingIds, target: { groupId: group.id } }) } const handleMouseLeave = () => { if (isReadOnly) return setMouseOverGroup(undefined) if (connectingIds) setConnectingIds({ ...connectingIds, target: undefined }) } const onDrag = (_: DraggableEvent, draggableData: DraggableData) => { const { deltaX, deltaY } = draggableData updateGroupCoordinates(group.id, { x: groupCoordinates.x + deltaX / graphPosition.scale, y: groupCoordinates.y + deltaY / graphPosition.scale, }) } const onDragStart = () => { setFocusedGroupId(group.id) setIsMouseDown(true) } const startPreviewAtThisGroup = () => { setStartPreviewAtGroup(group.id) setRightPanel(RightPanel.PREVIEW) } const onDragStop = () => setIsMouseDown(false) return ( renderMenu={() => } isDisabled={isReadOnly || isStartGroup} > {(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={startPreviewAtThisGroup} /> )} ) }