feat: ✨ Add collaboration
This commit is contained in:
@ -12,6 +12,7 @@ import {
|
||||
Wrap,
|
||||
} from '@chakra-ui/react'
|
||||
import { useTypebotDnd } from 'contexts/TypebotDndContext'
|
||||
import { useUser } from 'contexts/UserContext'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { createFolder, useFolders } from 'services/folders'
|
||||
import {
|
||||
@ -19,11 +20,13 @@ import {
|
||||
TypebotInDashboard,
|
||||
useTypebots,
|
||||
} from 'services/typebots'
|
||||
import { useSharedTypebotsCount } from 'services/user/sharedTypebots'
|
||||
import { AnnoucementModal } from './annoucements/AnnoucementModal'
|
||||
import { BackButton } from './FolderContent/BackButton'
|
||||
import { CreateBotButton } from './FolderContent/CreateBotButton'
|
||||
import { CreateFolderButton } from './FolderContent/CreateFolderButton'
|
||||
import { ButtonSkeleton, FolderButton } from './FolderContent/FolderButton'
|
||||
import { SharedTypebotsButton } from './FolderContent/SharedTypebotsButton'
|
||||
import { TypebotButton } from './FolderContent/TypebotButton'
|
||||
import { TypebotCardOverlay } from './FolderContent/TypebotButtonOverlay'
|
||||
|
||||
@ -32,6 +35,7 @@ type Props = { folder: DashboardFolder | null }
|
||||
const dragDistanceTolerance = 20
|
||||
|
||||
export const FolderContent = ({ folder }: Props) => {
|
||||
const { user } = useUser()
|
||||
const [isCreatingFolder, setIsCreatingFolder] = useState(false)
|
||||
const {
|
||||
setDraggedTypebot,
|
||||
@ -75,6 +79,17 @@ export const FolderContent = ({ folder }: Props) => {
|
||||
},
|
||||
})
|
||||
|
||||
const { totalSharedTypebots, isLoading: isSharedTypebotsCountLoading } =
|
||||
useSharedTypebotsCount({
|
||||
userId: folder === null ? user?.id : undefined,
|
||||
onError: (error) => {
|
||||
toast({
|
||||
title: "Couldn't fetch shared typebots",
|
||||
description: error.message,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
typebots &&
|
||||
@ -182,6 +197,8 @@ export const FolderContent = ({ folder }: Props) => {
|
||||
folderId={folder?.id}
|
||||
isLoading={isTypebotLoading}
|
||||
/>
|
||||
{isSharedTypebotsCountLoading && <ButtonSkeleton />}
|
||||
{totalSharedTypebots > 0 && <SharedTypebotsButton />}
|
||||
{isFolderLoading && <ButtonSkeleton />}
|
||||
{folders &&
|
||||
folders.map((folder) => (
|
||||
|
@ -0,0 +1,40 @@
|
||||
import React from 'react'
|
||||
import { Button, Flex, Text, VStack, WrapItem } from '@chakra-ui/react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { UsersIcon } from 'assets/icons'
|
||||
|
||||
export const SharedTypebotsButton = () => {
|
||||
const router = useRouter()
|
||||
|
||||
const handleTypebotClick = () => router.push(`/typebots/shared`)
|
||||
|
||||
return (
|
||||
<Button
|
||||
as={WrapItem}
|
||||
onClick={handleTypebotClick}
|
||||
display="flex"
|
||||
flexDir="column"
|
||||
variant="outline"
|
||||
color="gray.800"
|
||||
w="225px"
|
||||
h="270px"
|
||||
mr={{ sm: 6 }}
|
||||
mb={6}
|
||||
rounded="lg"
|
||||
whiteSpace="normal"
|
||||
cursor="pointer"
|
||||
>
|
||||
<VStack spacing="4">
|
||||
<Flex
|
||||
boxSize="45px"
|
||||
rounded="full"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<UsersIcon fontSize="50" color="orange.300" />
|
||||
</Flex>
|
||||
<Text>Shared with me</Text>
|
||||
</VStack>
|
||||
</Button>
|
||||
)
|
||||
}
|
@ -22,13 +22,15 @@ import { useDebounce } from 'use-debounce'
|
||||
|
||||
type ChatbotCardProps = {
|
||||
typebot: Pick<Typebot, 'id' | 'publishedTypebotId' | 'name'>
|
||||
onTypebotDeleted: () => void
|
||||
onMouseDown: (e: React.MouseEvent<HTMLButtonElement>) => void
|
||||
isReadOnly?: boolean
|
||||
onTypebotDeleted?: () => void
|
||||
onMouseDown?: (e: React.MouseEvent<HTMLButtonElement>) => void
|
||||
}
|
||||
|
||||
export const TypebotButton = ({
|
||||
typebot,
|
||||
onTypebotDeleted,
|
||||
isReadOnly = false,
|
||||
onMouseDown,
|
||||
}: ChatbotCardProps) => {
|
||||
const router = useRouter()
|
||||
@ -55,13 +57,14 @@ export const TypebotButton = ({
|
||||
}
|
||||
|
||||
const handleDeleteTypebotClick = async () => {
|
||||
if (isReadOnly) return
|
||||
const { error } = await deleteTypebot(typebot.id)
|
||||
if (error)
|
||||
return toast({
|
||||
title: "Couldn't delete typebot",
|
||||
description: error.message,
|
||||
})
|
||||
onTypebotDeleted()
|
||||
if (onTypebotDeleted) onTypebotDeleted()
|
||||
}
|
||||
|
||||
const handleDuplicateClick = async (e: React.MouseEvent) => {
|
||||
@ -98,28 +101,32 @@ export const TypebotButton = ({
|
||||
onMouseDown={onMouseDown}
|
||||
cursor="pointer"
|
||||
>
|
||||
<IconButton
|
||||
icon={<GripIcon />}
|
||||
pos="absolute"
|
||||
top="20px"
|
||||
left="20px"
|
||||
aria-label="Drag"
|
||||
cursor="grab"
|
||||
variant="ghost"
|
||||
colorScheme="blue"
|
||||
size="sm"
|
||||
/>
|
||||
<MoreButton
|
||||
pos="absolute"
|
||||
top="20px"
|
||||
right="20px"
|
||||
aria-label={`Show ${typebot.name} menu`}
|
||||
>
|
||||
<MenuItem onClick={handleDuplicateClick}>Duplicate</MenuItem>
|
||||
<MenuItem color="red" onClick={handleDeleteClick}>
|
||||
Delete
|
||||
</MenuItem>
|
||||
</MoreButton>
|
||||
{!isReadOnly && (
|
||||
<>
|
||||
<IconButton
|
||||
icon={<GripIcon />}
|
||||
pos="absolute"
|
||||
top="20px"
|
||||
left="20px"
|
||||
aria-label="Drag"
|
||||
cursor="grab"
|
||||
variant="ghost"
|
||||
colorScheme="blue"
|
||||
size="sm"
|
||||
/>
|
||||
<MoreButton
|
||||
pos="absolute"
|
||||
top="20px"
|
||||
right="20px"
|
||||
aria-label={`Show ${typebot.name} menu`}
|
||||
>
|
||||
<MenuItem onClick={handleDuplicateClick}>Duplicate</MenuItem>
|
||||
<MenuItem color="red" onClick={handleDeleteClick}>
|
||||
Delete
|
||||
</MenuItem>
|
||||
</MoreButton>
|
||||
</>
|
||||
)}
|
||||
<VStack spacing="4">
|
||||
<Flex
|
||||
boxSize="45px"
|
||||
@ -137,20 +144,22 @@ export const TypebotButton = ({
|
||||
</Flex>
|
||||
<Text>{typebot.name}</Text>
|
||||
</VStack>
|
||||
<ConfirmModal
|
||||
message={
|
||||
<Text>
|
||||
Are you sure you want to delete your Typebot "{typebot.name}
|
||||
".
|
||||
<br />
|
||||
All associated data will be lost.
|
||||
</Text>
|
||||
}
|
||||
confirmButtonLabel="Delete"
|
||||
onConfirm={handleDeleteTypebotClick}
|
||||
isOpen={isDeleteOpen}
|
||||
onClose={onDeleteClose}
|
||||
/>
|
||||
{!isReadOnly && (
|
||||
<ConfirmModal
|
||||
message={
|
||||
<Text>
|
||||
Are you sure you want to delete your Typebot "{typebot.name}
|
||||
".
|
||||
<br />
|
||||
All associated data will be lost.
|
||||
</Text>
|
||||
}
|
||||
confirmButtonLabel="Delete"
|
||||
onConfirm={handleDeleteTypebotClick}
|
||||
isOpen={isDeleteOpen}
|
||||
onClose={onDeleteClose}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user