2
0
Files
bot/apps/builder/components/dashboard/FolderContent.tsx
2021-12-22 14:59:07 +01:00

182 lines
5.5 KiB
TypeScript

import { DashboardFolder } from '.prisma/client'
import { Typebot } from 'bot-engine'
import {
Button,
Flex,
Heading,
HStack,
Skeleton,
Stack,
useToast,
Wrap,
} from '@chakra-ui/react'
import {
DndContext,
DragEndEvent,
DragOverlay,
DragStartEvent,
MouseSensor,
useSensor,
useSensors,
} from '@dnd-kit/core'
import { FolderPlusIcon } from 'assets/icons'
import React, { useState } from 'react'
import { createFolder, useFolders } from 'services/folders'
import { updateTypebot, useTypebots } from 'services/typebots'
import { BackButton } from './FolderContent/BackButton'
import { CreateBotButton } from './FolderContent/CreateBotButton'
import { ButtonSkeleton, FolderButton } from './FolderContent/FolderButton'
import { TypebotButton } from './FolderContent/TypebotButton'
import { TypebotCardOverlay } from './FolderContent/TypebotButtonOverlay'
type Props = { folder: DashboardFolder | null }
export const FolderContent = ({ folder }: Props) => {
const [isCreatingFolder, setIsCreatingFolder] = useState(false)
const [draggedTypebot, setDraggedTypebot] = useState<Typebot | undefined>()
const sensors = useSensors(
useSensor(MouseSensor, {
activationConstraint: {
delay: 100,
tolerance: 300,
},
})
)
const toast = useToast({
position: 'top-right',
status: 'error',
})
const {
folders,
isLoading: isFolderLoading,
mutate: mutateFolders,
} = useFolders({
parentId: folder?.id,
onError: (error) => {
toast({ title: "Couldn't fetch folders", description: error.message })
},
})
const {
typebots,
isLoading: isTypebotLoading,
mutate: mutateTypebots,
} = useTypebots({
folderId: folder?.id,
onError: (error) => {
toast({ title: "Couldn't fetch typebots", description: error.message })
},
})
const handleDragStart = (event: DragStartEvent) => {
if (!typebots) return
setDraggedTypebot(typebots.find((c) => c.id === event.active.id))
}
const handleDragEnd = async (event: DragEndEvent) => {
if (!typebots) return
const { over } = event
if (over?.id && draggedTypebot?.id)
await moveTypebotToFolder(draggedTypebot.id, over.id)
setDraggedTypebot(undefined)
}
const moveTypebotToFolder = async (typebotId: string, folderId: string) => {
if (!typebots) return
const { error } = await updateTypebot(typebotId, {
folderId: folderId === 'root' ? null : folderId,
})
if (error) toast({ description: error.message })
mutateTypebots({ typebots: typebots.filter((t) => t.id !== typebotId) })
}
const handleCreateFolder = async () => {
if (!folders) return
setIsCreatingFolder(true)
const { error, data: newFolder } = await createFolder({
parentFolderId: folder?.id ?? null,
})
setIsCreatingFolder(false)
if (error)
return toast({ title: 'An error occured', description: error.message })
if (newFolder) mutateFolders({ folders: [...folders, newFolder] })
}
const handleTypebotDeleted = (deletedId: string) => {
if (!typebots) return
mutateTypebots({ typebots: typebots.filter((t) => t.id !== deletedId) })
}
const handleFolderDeleted = (deletedId: string) => {
if (!folders) return
mutateFolders({ folders: folders.filter((f) => f.id !== deletedId) })
}
const handleFolderRenamed = (folderId: string, name: string) => {
if (!folders) return
mutateFolders({
folders: folders.map((f) => (f.id === folderId ? { ...f, name } : f)),
})
}
return (
<Flex w="full" justify="center" align="center" pt={4}>
<DndContext
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
sensors={sensors}
>
<Stack w="1000px" spacing={6}>
<Skeleton isLoaded={folder?.name !== undefined}>
<Heading as="h1">{folder?.name}</Heading>
</Skeleton>
<Stack>
<HStack>
{folder && <BackButton id={folder.parentFolderId} />}
<Button
leftIcon={<FolderPlusIcon />}
onClick={handleCreateFolder}
isLoading={isCreatingFolder || isFolderLoading}
>
Create a folder
</Button>
</HStack>
<Wrap spacing={4}>
<CreateBotButton
folderId={folder?.id}
isLoading={isTypebotLoading}
/>
{isFolderLoading && <ButtonSkeleton />}
{folders &&
folders.map((folder) => (
<FolderButton
key={folder.id.toString()}
folder={folder}
onFolderDeleted={() => handleFolderDeleted(folder.id)}
onFolderRenamed={(newName: string) =>
handleFolderRenamed(folder.id, newName)
}
/>
))}
{isTypebotLoading && <ButtonSkeleton />}
{typebots &&
typebots.map((typebot) => (
<TypebotButton
key={typebot.id.toString()}
typebot={typebot}
onTypebotDeleted={() => handleTypebotDeleted(typebot.id)}
/>
))}
<DragOverlay dropAnimation={null}>
{draggedTypebot && (
<TypebotCardOverlay typebot={draggedTypebot} />
)}
</DragOverlay>
</Wrap>
</Stack>
</Stack>
</DndContext>
</Flex>
)
}