diff --git a/apps/web/src/app/(dashboard)/documents/data-table.tsx b/apps/web/src/app/(dashboard)/documents/data-table.tsx index 1adaace7b..d36860032 100644 --- a/apps/web/src/app/(dashboard)/documents/data-table.tsx +++ b/apps/web/src/app/(dashboard)/documents/data-table.tsx @@ -76,9 +76,7 @@ export const DocumentsDataTable = ({ { header: 'Recipient', accessorKey: 'recipient', - cell: ({ row }) => { - return ; - }, + cell: ({ row }) => , }, { header: 'Status', diff --git a/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx b/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx index bd7bea2b0..10f7d1e6a 100644 --- a/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx +++ b/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx @@ -1,13 +1,12 @@ +'use client'; + +import { useRef, useState } from 'react'; + import { getRecipientType } from '@documenso/lib/client-only/recipient-type'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles'; import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter'; import type { Recipient } from '@documenso/prisma/client'; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from '@documenso/ui/primitives/tooltip'; +import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover'; import { AvatarWithRecipient } from './avatar-with-recipient'; import { StackAvatar } from './stack-avatar'; @@ -24,6 +23,11 @@ export const StackAvatarsWithTooltip = ({ position, children, }: StackAvatarsWithTooltipProps) => { + const [open, setOpen] = useState(false); + + const isControlled = useRef(false); + const isMouseOverTimeout = useRef(null); + const waitingRecipients = recipients.filter( (recipient) => getRecipientType(recipient) === 'waiting', ); @@ -40,66 +44,105 @@ export const StackAvatarsWithTooltip = ({ (recipient) => getRecipientType(recipient) === 'unsigned', ); + const onMouseEnter = () => { + if (isMouseOverTimeout.current) { + clearTimeout(isMouseOverTimeout.current); + } + + if (isControlled.current) { + return; + } + + isMouseOverTimeout.current = setTimeout(() => { + setOpen((o) => (!o ? true : o)); + }, 200); + }; + + const onMouseLeave = () => { + if (isMouseOverTimeout.current) { + clearTimeout(isMouseOverTimeout.current); + } + + if (isControlled.current) { + return; + } + + setTimeout(() => { + setOpen((o) => (o ? false : o)); + }, 200); + }; + + const onOpenChange = (newOpen: boolean) => { + isControlled.current = newOpen; + + setOpen(newOpen); + }; + return ( - - - - {children || } - + + + {children || } + - -
- {completedRecipients.length > 0 && ( -
-

Completed

- {completedRecipients.map((recipient: Recipient) => ( -
- -
-

{recipient.email}

-

- {RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName} -

-
-
- ))} + + {completedRecipients.length > 0 && ( +
+

Completed

+ {completedRecipients.map((recipient: Recipient) => ( +
+ +
+

{recipient.email}

+

+ {RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName} +

+
- )} - - {waitingRecipients.length > 0 && ( -
-

Waiting

- {waitingRecipients.map((recipient: Recipient) => ( - - ))} -
- )} - - {openedRecipients.length > 0 && ( -
-

Opened

- {openedRecipients.map((recipient: Recipient) => ( - - ))} -
- )} - - {uncompletedRecipients.length > 0 && ( -
-

Uncompleted

- {uncompletedRecipients.map((recipient: Recipient) => ( - - ))} -
- )} + ))}
- - - + )} + + {waitingRecipients.length > 0 && ( +
+

Waiting

+ {waitingRecipients.map((recipient: Recipient) => ( + + ))} +
+ )} + + {openedRecipients.length > 0 && ( +
+

Opened

+ {openedRecipients.map((recipient: Recipient) => ( + + ))} +
+ )} + + {uncompletedRecipients.length > 0 && ( +
+

Uncompleted

+ {uncompletedRecipients.map((recipient: Recipient) => ( + + ))} +
+ )} +
+ ); };