2
0

feat: Add collaboration

This commit is contained in:
Baptiste Arnaud
2022-02-24 11:13:19 +01:00
parent dd671a5d2c
commit b9dafa611e
63 changed files with 1932 additions and 148 deletions

View File

@ -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) => (

View File

@ -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>
)
}

View File

@ -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 &quot;{typebot.name}
&quot;.
<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 &quot;{typebot.name}
&quot;.
<br />
All associated data will be lost.
</Text>
}
confirmButtonLabel="Delete"
onConfirm={handleDeleteTypebotClick}
isOpen={isDeleteOpen}
onClose={onDeleteClose}
/>
)}
</Button>
)
}