From 2a448fe06d29d4a98bbada9d4c373d3ade1c210e Mon Sep 17 00:00:00 2001 From: Ashraf Date: Wed, 20 Dec 2023 17:08:09 +0800 Subject: [PATCH 1/4] fix: fixed the recipients viewing issue on touch screens --- .../app/(dashboard)/documents/[id]/page.tsx | 6 +- .../app/(dashboard)/documents/data-table.tsx | 6 +- .../avatar/stack-avatars-component.tsx | 71 +++++++++++++ .../avatar/stack-avatars-with-tooltip.tsx | 99 ------------------- .../avatar/stack-avatars-with-ui.tsx | 51 ++++++++++ 5 files changed, 127 insertions(+), 106 deletions(-) create mode 100644 apps/web/src/components/(dashboard)/avatar/stack-avatars-component.tsx delete mode 100644 apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx create mode 100644 apps/web/src/components/(dashboard)/avatar/stack-avatars-with-ui.tsx diff --git a/apps/web/src/app/(dashboard)/documents/[id]/page.tsx b/apps/web/src/app/(dashboard)/documents/[id]/page.tsx index b26b6308c..ce18f27b8 100644 --- a/apps/web/src/app/(dashboard)/documents/[id]/page.tsx +++ b/apps/web/src/app/(dashboard)/documents/[id]/page.tsx @@ -11,7 +11,7 @@ import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/clie import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer'; import { EditDocumentForm } from '~/app/(dashboard)/documents/[id]/edit-document'; -import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-avatars-with-tooltip'; +import { StackAvatarsWithUI } from '~/components/(dashboard)/avatar/stack-avatars-with-ui'; import { DocumentStatus } from '~/components/formatter/document-status'; export type DocumentPageProps = { @@ -71,9 +71,9 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
- + {recipients.length} Recipient(s) - +
)} diff --git a/apps/web/src/app/(dashboard)/documents/data-table.tsx b/apps/web/src/app/(dashboard)/documents/data-table.tsx index c8adb1422..a0cc4b8e8 100644 --- a/apps/web/src/app/(dashboard)/documents/data-table.tsx +++ b/apps/web/src/app/(dashboard)/documents/data-table.tsx @@ -12,7 +12,7 @@ import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-documen import { DataTable } from '@documenso/ui/primitives/data-table'; import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination'; -import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-avatars-with-tooltip'; +import { StackAvatarsWithUI } from '~/components/(dashboard)/avatar/stack-avatars-with-ui'; import { DocumentStatus } from '~/components/formatter/document-status'; import { LocaleDate } from '~/components/formatter/locale-date'; @@ -64,9 +64,7 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => { { header: 'Recipient', accessorKey: 'recipient', - cell: ({ row }) => { - return ; - }, + cell: ({ row }) => , }, { header: 'Status', diff --git a/apps/web/src/components/(dashboard)/avatar/stack-avatars-component.tsx b/apps/web/src/components/(dashboard)/avatar/stack-avatars-component.tsx new file mode 100644 index 000000000..d7f3106e6 --- /dev/null +++ b/apps/web/src/components/(dashboard)/avatar/stack-avatars-component.tsx @@ -0,0 +1,71 @@ +import { getRecipientType } from '@documenso/lib/client-only/recipient-type'; +import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter'; +import type { Recipient } from '@documenso/prisma/client'; + +import { AvatarWithRecipient } from './avatar-with-recipient'; +import { StackAvatar } from './stack-avatar'; + +export const StackAvatarsComponent = ({ recipients }: { recipients: Recipient[] }) => { + const waitingRecipients = recipients.filter( + (recipient) => getRecipientType(recipient) === 'waiting', + ); + + const openedRecipients = recipients.filter( + (recipient) => getRecipientType(recipient) === 'opened', + ); + + const completedRecipients = recipients.filter( + (recipient) => getRecipientType(recipient) === 'completed', + ); + + const uncompletedRecipients = recipients.filter( + (recipient) => getRecipientType(recipient) === 'unsigned', + ); + return ( +
+ {completedRecipients.length > 0 && ( +
+

Completed

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

Waiting

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

Opened

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

Uncompleted

+ {uncompletedRecipients.map((recipient: Recipient) => ( + + ))} +
+ )} +
+ ); +}; 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 deleted file mode 100644 index 7429d8ee5..000000000 --- a/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { getRecipientType } from '@documenso/lib/client-only/recipient-type'; -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 { AvatarWithRecipient } from './avatar-with-recipient'; -import { StackAvatar } from './stack-avatar'; -import { StackAvatars } from './stack-avatars'; - -export type StackAvatarsWithTooltipProps = { - recipients: Recipient[]; - position?: 'top' | 'bottom'; - children?: React.ReactNode; -}; - -export const StackAvatarsWithTooltip = ({ - recipients, - position, - children, -}: StackAvatarsWithTooltipProps) => { - const waitingRecipients = recipients.filter( - (recipient) => getRecipientType(recipient) === 'waiting', - ); - - const openedRecipients = recipients.filter( - (recipient) => getRecipientType(recipient) === 'opened', - ); - - const completedRecipients = recipients.filter( - (recipient) => getRecipientType(recipient) === 'completed', - ); - - const uncompletedRecipients = recipients.filter( - (recipient) => getRecipientType(recipient) === 'unsigned', - ); - - return ( - - - - {children || } - - - -
- {completedRecipients.length > 0 && ( -
-

Completed

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

Waiting

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

Opened

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

Uncompleted

- {uncompletedRecipients.map((recipient: Recipient) => ( - - ))} -
- )} -
-
-
-
- ); -}; diff --git a/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-ui.tsx b/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-ui.tsx new file mode 100644 index 000000000..5d5f24413 --- /dev/null +++ b/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-ui.tsx @@ -0,0 +1,51 @@ +'use client'; + +import { useWindowSize } from '@documenso/lib/client-only/hooks/use-window-size'; +import type { Recipient } from '@documenso/prisma/client'; +import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover'; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@documenso/ui/primitives/tooltip'; + +import { StackAvatars } from './stack-avatars'; +import { StackAvatarsComponent } from './stack-avatars-component'; + +export type StackAvatarsWithUIProps = { + recipients: Recipient[]; + position?: 'top' | 'bottom'; + children?: React.ReactNode; +}; + +export const StackAvatarsWithUI = ({ recipients, position, children }: StackAvatarsWithUIProps) => { + const size = useWindowSize(); + return ( + <> + {size.width > 1050 ? ( + + + + {children || } + + + + + + + + ) : ( + + + {children || } + + + + + + + )} + + ); +}; From ce67de9a1cb1ddb5db8092814c08de8f644fe65d Mon Sep 17 00:00:00 2001 From: Ashraf Date: Fri, 29 Dec 2023 19:29:13 +0800 Subject: [PATCH 2/4] refactor: changed component name for better readability --- apps/web/src/app/(dashboard)/documents/[id]/page.tsx | 6 +++--- apps/web/src/app/(dashboard)/documents/data-table.tsx | 4 ++-- .../{stack-avatars-with-ui.tsx => stack-avatars-ui.tsx} | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) rename apps/web/src/components/(dashboard)/avatar/{stack-avatars-with-ui.tsx => stack-avatars-ui.tsx} (91%) diff --git a/apps/web/src/app/(dashboard)/documents/[id]/page.tsx b/apps/web/src/app/(dashboard)/documents/[id]/page.tsx index ce18f27b8..708746af1 100644 --- a/apps/web/src/app/(dashboard)/documents/[id]/page.tsx +++ b/apps/web/src/app/(dashboard)/documents/[id]/page.tsx @@ -11,7 +11,7 @@ import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/clie import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer'; import { EditDocumentForm } from '~/app/(dashboard)/documents/[id]/edit-document'; -import { StackAvatarsWithUI } from '~/components/(dashboard)/avatar/stack-avatars-with-ui'; +import { StackAvatarsUI } from '~/components/(dashboard)/avatar/stack-avatars-ui'; import { DocumentStatus } from '~/components/formatter/document-status'; export type DocumentPageProps = { @@ -71,9 +71,9 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
- + {recipients.length} Recipient(s) - +
)} diff --git a/apps/web/src/app/(dashboard)/documents/data-table.tsx b/apps/web/src/app/(dashboard)/documents/data-table.tsx index a0cc4b8e8..ca2da02d3 100644 --- a/apps/web/src/app/(dashboard)/documents/data-table.tsx +++ b/apps/web/src/app/(dashboard)/documents/data-table.tsx @@ -12,7 +12,7 @@ import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-documen import { DataTable } from '@documenso/ui/primitives/data-table'; import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination'; -import { StackAvatarsWithUI } from '~/components/(dashboard)/avatar/stack-avatars-with-ui'; +import { StackAvatarsUI } from '~/components/(dashboard)/avatar/stack-avatars-ui'; import { DocumentStatus } from '~/components/formatter/document-status'; import { LocaleDate } from '~/components/formatter/locale-date'; @@ -64,7 +64,7 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => { { header: 'Recipient', accessorKey: 'recipient', - cell: ({ row }) => , + cell: ({ row }) => , }, { header: 'Status', diff --git a/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-ui.tsx b/apps/web/src/components/(dashboard)/avatar/stack-avatars-ui.tsx similarity index 91% rename from apps/web/src/components/(dashboard)/avatar/stack-avatars-with-ui.tsx rename to apps/web/src/components/(dashboard)/avatar/stack-avatars-ui.tsx index 5d5f24413..c1c44836a 100644 --- a/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-ui.tsx +++ b/apps/web/src/components/(dashboard)/avatar/stack-avatars-ui.tsx @@ -13,14 +13,15 @@ import { import { StackAvatars } from './stack-avatars'; import { StackAvatarsComponent } from './stack-avatars-component'; -export type StackAvatarsWithUIProps = { +export type StackAvatarsUIProps = { recipients: Recipient[]; position?: 'top' | 'bottom'; children?: React.ReactNode; }; -export const StackAvatarsWithUI = ({ recipients, position, children }: StackAvatarsWithUIProps) => { +export const StackAvatarsUI = ({ recipients, position, children }: StackAvatarsUIProps) => { const size = useWindowSize(); + return ( <> {size.width > 1050 ? ( From 32b0b1bcdaee01cdee9b6ce1b494211263ae487f Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Fri, 8 Mar 2024 12:21:32 +0000 Subject: [PATCH 3/4] fix: revert api change and use mouseenter/mouseleave --- .../app/(dashboard)/documents/[id]/page.tsx | 6 +- .../app/(dashboard)/documents/data-table.tsx | 4 +- .../avatar/stack-avatars-component.tsx | 71 --------- .../(dashboard)/avatar/stack-avatars-ui.tsx | 52 ------- .../avatar/stack-avatars-with-tooltip.tsx | 140 ++++++++++++++++++ 5 files changed, 145 insertions(+), 128 deletions(-) delete mode 100644 apps/web/src/components/(dashboard)/avatar/stack-avatars-component.tsx delete mode 100644 apps/web/src/components/(dashboard)/avatar/stack-avatars-ui.tsx create mode 100644 apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx diff --git a/apps/web/src/app/(dashboard)/documents/[id]/page.tsx b/apps/web/src/app/(dashboard)/documents/[id]/page.tsx index bf58ae36a..44f3991d8 100644 --- a/apps/web/src/app/(dashboard)/documents/[id]/page.tsx +++ b/apps/web/src/app/(dashboard)/documents/[id]/page.tsx @@ -13,7 +13,7 @@ import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/clie import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer'; import { EditDocumentForm } from '~/app/(dashboard)/documents/[id]/edit-document'; -import { StackAvatarsUI } from '~/components/(dashboard)/avatar/stack-avatars-ui'; +import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-avatars-with-tooltip'; import { DocumentStatus } from '~/components/formatter/document-status'; export type DocumentPageProps = { @@ -90,9 +90,9 @@ export default async function DocumentPage({ params }: DocumentPageProps) {
- + {recipients.length} Recipient(s) - +
)} diff --git a/apps/web/src/app/(dashboard)/documents/data-table.tsx b/apps/web/src/app/(dashboard)/documents/data-table.tsx index ca2da02d3..72787714f 100644 --- a/apps/web/src/app/(dashboard)/documents/data-table.tsx +++ b/apps/web/src/app/(dashboard)/documents/data-table.tsx @@ -12,7 +12,7 @@ import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-documen import { DataTable } from '@documenso/ui/primitives/data-table'; import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination'; -import { StackAvatarsUI } from '~/components/(dashboard)/avatar/stack-avatars-ui'; +import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-avatars-with-tooltip'; import { DocumentStatus } from '~/components/formatter/document-status'; import { LocaleDate } from '~/components/formatter/locale-date'; @@ -64,7 +64,7 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => { { header: 'Recipient', accessorKey: 'recipient', - cell: ({ row }) => , + cell: ({ row }) => , }, { header: 'Status', diff --git a/apps/web/src/components/(dashboard)/avatar/stack-avatars-component.tsx b/apps/web/src/components/(dashboard)/avatar/stack-avatars-component.tsx deleted file mode 100644 index d7f3106e6..000000000 --- a/apps/web/src/components/(dashboard)/avatar/stack-avatars-component.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { getRecipientType } from '@documenso/lib/client-only/recipient-type'; -import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter'; -import type { Recipient } from '@documenso/prisma/client'; - -import { AvatarWithRecipient } from './avatar-with-recipient'; -import { StackAvatar } from './stack-avatar'; - -export const StackAvatarsComponent = ({ recipients }: { recipients: Recipient[] }) => { - const waitingRecipients = recipients.filter( - (recipient) => getRecipientType(recipient) === 'waiting', - ); - - const openedRecipients = recipients.filter( - (recipient) => getRecipientType(recipient) === 'opened', - ); - - const completedRecipients = recipients.filter( - (recipient) => getRecipientType(recipient) === 'completed', - ); - - const uncompletedRecipients = recipients.filter( - (recipient) => getRecipientType(recipient) === 'unsigned', - ); - return ( -
- {completedRecipients.length > 0 && ( -
-

Completed

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

Waiting

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

Opened

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

Uncompleted

- {uncompletedRecipients.map((recipient: Recipient) => ( - - ))} -
- )} -
- ); -}; diff --git a/apps/web/src/components/(dashboard)/avatar/stack-avatars-ui.tsx b/apps/web/src/components/(dashboard)/avatar/stack-avatars-ui.tsx deleted file mode 100644 index c1c44836a..000000000 --- a/apps/web/src/components/(dashboard)/avatar/stack-avatars-ui.tsx +++ /dev/null @@ -1,52 +0,0 @@ -'use client'; - -import { useWindowSize } from '@documenso/lib/client-only/hooks/use-window-size'; -import type { Recipient } from '@documenso/prisma/client'; -import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover'; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from '@documenso/ui/primitives/tooltip'; - -import { StackAvatars } from './stack-avatars'; -import { StackAvatarsComponent } from './stack-avatars-component'; - -export type StackAvatarsUIProps = { - recipients: Recipient[]; - position?: 'top' | 'bottom'; - children?: React.ReactNode; -}; - -export const StackAvatarsUI = ({ recipients, position, children }: StackAvatarsUIProps) => { - const size = useWindowSize(); - - return ( - <> - {size.width > 1050 ? ( - - - - {children || } - - - - - - - - ) : ( - - - {children || } - - - - - - - )} - - ); -}; 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 new file mode 100644 index 000000000..51fd9c8cd --- /dev/null +++ b/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx @@ -0,0 +1,140 @@ +import { useRef, useState } from 'react'; + +import { getRecipientType } from '@documenso/lib/client-only/recipient-type'; +import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter'; +import type { Recipient } from '@documenso/prisma/client'; +import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover'; + +import { AvatarWithRecipient } from './avatar-with-recipient'; +import { StackAvatar } from './stack-avatar'; +import { StackAvatars } from './stack-avatars'; + +export type StackAvatarsWithTooltipProps = { + recipients: Recipient[]; + position?: 'top' | 'bottom'; + children?: React.ReactNode; +}; + +export const StackAvatarsWithTooltip = ({ + recipients, + position, + children, +}: StackAvatarsWithTooltipProps) => { + const [open, setOpen] = useState(false); + + const isControlled = useRef(false); + const isMouseOverTimeout = useRef(null); + + const waitingRecipients = recipients.filter( + (recipient) => getRecipientType(recipient) === 'waiting', + ); + + const openedRecipients = recipients.filter( + (recipient) => getRecipientType(recipient) === 'opened', + ); + + const completedRecipients = recipients.filter( + (recipient) => getRecipientType(recipient) === 'completed', + ); + + const uncompletedRecipients = recipients.filter( + (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 || } + + + + {completedRecipients.length > 0 && ( +
+

Completed

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

Waiting

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

Opened

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

Uncompleted

+ {uncompletedRecipients.map((recipient: Recipient) => ( + + ))} +
+ )} +
+
+ ); +}; From 40343d1c7241861ccc59788fef3f47c3b0680f27 Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Fri, 8 Mar 2024 12:34:49 +0000 Subject: [PATCH 4/4] fix: add use client directive --- .../(dashboard)/avatar/stack-avatars-with-tooltip.tsx | 2 ++ 1 file changed, 2 insertions(+) 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 0e6aa0ac8..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,3 +1,5 @@ +'use client'; + import { useRef, useState } from 'react'; import { getRecipientType } from '@documenso/lib/client-only/recipient-type';