mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
feat: copy signing link from avatar stack (#658)
This commit is contained in:
committed by
GitHub
parent
06714a2aeb
commit
8adc44802f
@ -6,8 +6,8 @@ import { Loader } from 'lucide-react';
|
|||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
|
|
||||||
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
|
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
|
||||||
import { FindResultSet } from '@documenso/lib/types/find-result-set';
|
import type { FindResultSet } from '@documenso/lib/types/find-result-set';
|
||||||
import { Document, Recipient, User } from '@documenso/prisma/client';
|
import type { Document, Recipient, User } from '@documenso/prisma/client';
|
||||||
import { DataTable } from '@documenso/ui/primitives/data-table';
|
import { DataTable } from '@documenso/ui/primitives/data-table';
|
||||||
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
|
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
|
||||||
|
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 { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
|
import { StackAvatar } from './stack-avatar';
|
||||||
|
|
||||||
|
export type AvatarWithRecipientProps = {
|
||||||
|
recipient: Recipient;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function AvatarWithRecipient({ recipient }: AvatarWithRecipientProps) {
|
||||||
|
const [, copy] = useCopyToClipboard();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
const onRecipientClick = () => {
|
||||||
|
void copy(`${process.env.NEXT_PUBLIC_WEBAPP_URL}/sign/${recipient.token}`).then(() => {
|
||||||
|
toast({
|
||||||
|
title: 'Copied to clipboard',
|
||||||
|
description: 'The signing link has been copied to your clipboard.',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="my-1 flex cursor-pointer items-center gap-2" onClick={onRecipientClick}>
|
||||||
|
<StackAvatar
|
||||||
|
first={true}
|
||||||
|
key={recipient.id}
|
||||||
|
type={getRecipientType(recipient)}
|
||||||
|
fallbackText={recipientAbbreviation(recipient)}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className="text-muted-foreground text-sm hover:underline"
|
||||||
|
title="Click to copy signing link for sending to recipient"
|
||||||
|
>
|
||||||
|
{recipient.email}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { getRecipientType } from '@documenso/lib/client-only/recipient-type';
|
import { getRecipientType } from '@documenso/lib/client-only/recipient-type';
|
||||||
import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter';
|
import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter';
|
||||||
import { Recipient } from '@documenso/prisma/client';
|
import type { Recipient } from '@documenso/prisma/client';
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
@ -8,6 +8,7 @@ import {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from '@documenso/ui/primitives/tooltip';
|
} from '@documenso/ui/primitives/tooltip';
|
||||||
|
|
||||||
|
import { AvatarWithRecipient } from './avatar-with-recipient';
|
||||||
import { StackAvatar } from './stack-avatar';
|
import { StackAvatar } from './stack-avatar';
|
||||||
import { StackAvatars } from './stack-avatars';
|
import { StackAvatars } from './stack-avatars';
|
||||||
|
|
||||||
@ -85,15 +86,7 @@ export const StackAvatarsWithTooltip = ({
|
|||||||
<div>
|
<div>
|
||||||
<h1 className="text-base font-medium">Opened</h1>
|
<h1 className="text-base font-medium">Opened</h1>
|
||||||
{openedRecipients.map((recipient: Recipient) => (
|
{openedRecipients.map((recipient: Recipient) => (
|
||||||
<div key={recipient.id} className="my-1 flex items-center gap-2">
|
<AvatarWithRecipient key={recipient.id} recipient={recipient} />
|
||||||
<StackAvatar
|
|
||||||
first={true}
|
|
||||||
key={recipient.id}
|
|
||||||
type={getRecipientType(recipient)}
|
|
||||||
fallbackText={recipientAbbreviation(recipient)}
|
|
||||||
/>
|
|
||||||
<span className="text-muted-foreground text-sm">{recipient.email}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -102,15 +95,7 @@ export const StackAvatarsWithTooltip = ({
|
|||||||
<div>
|
<div>
|
||||||
<h1 className="text-base font-medium">Uncompleted</h1>
|
<h1 className="text-base font-medium">Uncompleted</h1>
|
||||||
{uncompletedRecipients.map((recipient: Recipient) => (
|
{uncompletedRecipients.map((recipient: Recipient) => (
|
||||||
<div key={recipient.id} className="my-1 flex items-center gap-2">
|
<AvatarWithRecipient key={recipient.id} recipient={recipient} />
|
||||||
<StackAvatar
|
|
||||||
first={true}
|
|
||||||
key={recipient.id}
|
|
||||||
type={getRecipientType(recipient)}
|
|
||||||
fallbackText={recipientAbbreviation(recipient)}
|
|
||||||
/>
|
|
||||||
<span className="text-muted-foreground text-sm">{recipient.email}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -2,10 +2,11 @@ import { DateTime } from 'luxon';
|
|||||||
import { P, match } from 'ts-pattern';
|
import { P, match } from 'ts-pattern';
|
||||||
|
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
import { Document, Prisma, SigningStatus } from '@documenso/prisma/client';
|
import type { Document, Prisma } from '@documenso/prisma/client';
|
||||||
|
import { SigningStatus } from '@documenso/prisma/client';
|
||||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||||
|
|
||||||
import { FindResultSet } from '../../types/find-result-set';
|
import type { FindResultSet } from '../../types/find-result-set';
|
||||||
|
|
||||||
export interface FindDocumentsOptions {
|
export interface FindDocumentsOptions {
|
||||||
userId: number;
|
userId: number;
|
||||||
@ -160,19 +161,11 @@ export const findDocuments = async ({
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const maskedData = data.map((doc) => ({
|
|
||||||
...doc,
|
|
||||||
Recipient: doc.Recipient.map((recipient) => ({
|
|
||||||
...recipient,
|
|
||||||
token: recipient.email === user.email ? recipient.token : '',
|
|
||||||
})),
|
|
||||||
}));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: maskedData,
|
data,
|
||||||
count,
|
count,
|
||||||
currentPage: Math.max(page, 1),
|
currentPage: Math.max(page, 1),
|
||||||
perPage,
|
perPage,
|
||||||
totalPages: Math.ceil(count / perPage),
|
totalPages: Math.ceil(count / perPage),
|
||||||
} satisfies FindResultSet<typeof maskedData>;
|
} satisfies FindResultSet<typeof data>;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user