import { DashboardFolder, WorkspaceRole } from '@typebot.io/prisma' import { Flex, Heading, HStack, Portal, Skeleton, Stack, useEventListener, Wrap, } from '@chakra-ui/react' import { useTypebotDnd } from '../TypebotDndProvider' import React, { useEffect, useState } from 'react' import { BackButton } from './BackButton' import { useWorkspace } from '@/features/workspace/WorkspaceProvider' import { useToast } from '@/hooks/useToast' import { CreateBotButton } from './CreateBotButton' import { CreateFolderButton } from './CreateFolderButton' import FolderButton, { ButtonSkeleton } from './FolderButton' import TypebotButton from './TypebotButton' import { TypebotCardOverlay } from './TypebotButtonOverlay' import { useTypebots } from '@/features/dashboard/hooks/useTypebots' import { TypebotInDashboard } from '@/features/dashboard/types' import { trpc } from '@/lib/trpc' import { NodePosition } from '@/features/graph/providers/GraphDndProvider' type Props = { folder: DashboardFolder | null } export const FolderContent = ({ folder }: Props) => { const { workspace, currentRole } = useWorkspace() const [isCreatingFolder, setIsCreatingFolder] = useState(false) const { setDraggedTypebot, draggedTypebot, mouseOverFolderId, setMouseOverFolderId, } = useTypebotDnd() const [draggablePosition, setDraggablePosition] = useState({ x: 0, y: 0 }) const [mousePositionInElement, setMousePositionInElement] = useState({ x: 0, y: 0, }) const { showToast } = useToast() const { data: { folders } = {}, isLoading: isFolderLoading, refetch: refetchFolders, } = trpc.folders.listFolders.useQuery( { workspaceId: workspace?.id as string, parentFolderId: folder?.id, }, { enabled: !!workspace, onError: (error) => { showToast({ description: error.message, }) }, } ) const { mutate: createFolder } = trpc.folders.createFolder.useMutation({ onError: (error) => { showToast({ description: error.message }) }, onSuccess: () => { refetchFolders() }, }) const { mutate: updateTypebot } = trpc.typebot.updateTypebot.useMutation({ onError: (error) => { showToast({ description: error.message }) }, onSuccess: () => { refetchTypebots() }, }) const { typebots, isLoading: isTypebotLoading, refetch: refetchTypebots, } = useTypebots({ workspaceId: workspace?.id, folderId: folder === null ? 'root' : folder.id, onError: (error) => { showToast({ description: error.message, }) }, }) const moveTypebotToFolder = async (typebotId: string, folderId: string) => { if (!typebots) return updateTypebot({ typebotId, typebot: { folderId: folderId === 'root' ? null : folderId, }, }) } const handleCreateFolder = () => { if (!folders || !workspace) return setIsCreatingFolder(true) createFolder({ workspaceId: workspace.id, parentFolderId: folder?.id, }) setIsCreatingFolder(false) } const handleMouseUp = async () => { if (mouseOverFolderId !== undefined && draggedTypebot) await moveTypebotToFolder(draggedTypebot.id, mouseOverFolderId ?? 'root') setMouseOverFolderId(undefined) setDraggedTypebot(undefined) } useEventListener('mouseup', handleMouseUp) const handleTypebotDrag = (typebot: TypebotInDashboard) => ({ absolute, relative }: NodePosition) => { if (draggedTypebot) return setMousePositionInElement(relative) setDraggablePosition({ x: absolute.x - relative.x, y: absolute.y - relative.y, }) setDraggedTypebot(typebot) } const handleMouseMove = (e: MouseEvent) => { if (!draggedTypebot) return const { clientX, clientY } = e setDraggablePosition({ x: clientX - mousePositionInElement.x, y: clientY - mousePositionInElement.y, }) } useEventListener('mousemove', handleMouseMove) useEffect(() => { if (!draggablePosition || !draggedTypebot) return const { innerHeight } = window const scrollSpeed = 10 const scrollMargin = 50 const clientY = draggablePosition.y + mousePositionInElement.y const scrollY = clientY < scrollMargin ? -scrollSpeed : clientY > innerHeight - scrollMargin ? scrollSpeed : 0 window.scrollBy(0, scrollY) const interval = setInterval(() => { window.scrollBy(0, scrollY) }, 5) return () => { clearInterval(interval) } }, [draggablePosition, draggedTypebot, mousePositionInElement]) return ( {folder?.name} {folder && } {currentRole !== WorkspaceRole.GUEST && ( )} {currentRole !== WorkspaceRole.GUEST && ( )} {isFolderLoading && } {folders && folders.map((folder, index) => ( refetchFolders()} /> ))} {isTypebotLoading && } {typebots && typebots.map((typebot) => ( ))} {draggedTypebot && ( )} ) }