feat: add visible completed fields (#1109)

## Description

Added the ability for recipients to see fields from other recipients who
have completed the document when they are signing the document

Added the ability for the document owner to see fields from recipients
who have completed the field on the document page view (only visible
when the document is pending)


## 🚨🚨 Migrations🚨🚨

- Drop all `Fields` that do not have a `Recipient` set (not sure how it
was possible in the first place)
- Remove optional `Recipient` field on `Field` which doesn't make sense 

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
- Enhanced document viewing by adding read-only fields based on document
status.
- Improved signing page by fetching and displaying completed fields for
tokens.
- Updated avatar component to show recipient status with tooltips for
better user interaction.

- **Bug Fixes**
- Made `recipientId` a required field in the database to ensure data
consistency.

- **Refactor**
- Optimized popover functionality in UI components for better
performance and user experience.

- **Documentation**
- Added detailed component and function descriptions for new features in
the system.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Lucas Smith
2024-04-25 20:53:13 +10:00
committed by GitHub
14 changed files with 370 additions and 129 deletions

View File

@ -8,6 +8,7 @@ import { DOCUMENSO_ENCRYPTION_KEY } from '@documenso/lib/constants/crypto';
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
import { getServerComponentFlag } from '@documenso/lib/server-only/feature-flags/get-server-component-feature-flag';
import { getCompletedFieldsForDocument } from '@documenso/lib/server-only/field/get-completed-fields-for-document';
import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document';
import { symmetricDecrypt } from '@documenso/lib/universal/crypto';
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
@ -20,6 +21,7 @@ import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-avatars-with-tooltip';
import { DocumentHistorySheet } from '~/components/document/document-history-sheet';
import { DocumentReadOnlyFields } from '~/components/document/document-read-only-fields';
import {
DocumentStatus as DocumentStatusComponent,
FRIENDLY_STATUS_MAP,
@ -84,11 +86,16 @@ export const DocumentPageView = async ({ params, team }: DocumentPageViewProps)
documentMeta.password = securePassword;
}
const recipients = await getRecipientsForDocument({
documentId,
teamId: team?.id,
userId: user.id,
});
const [recipients, completedFields] = await Promise.all([
getRecipientsForDocument({
documentId,
teamId: team?.id,
userId: user.id,
}),
getCompletedFieldsForDocument({
documentId,
}),
]);
const documentWithRecipients = {
...document,
@ -155,6 +162,13 @@ export const DocumentPageView = async ({ params, team }: DocumentPageViewProps)
</CardContent>
</Card>
{document.status === DocumentStatus.PENDING && (
<DocumentReadOnlyFields
fields={completedFields}
documentMeta={document.documentMeta || undefined}
/>
)}
<div className="col-span-12 lg:col-span-6 xl:col-span-5">
<div className="space-y-6">
<section className="border-border bg-widget flex flex-col rounded-xl border pb-4 pt-6">

View File

@ -6,6 +6,7 @@ import { getServerComponentSession } from '@documenso/lib/next-auth/get-server-c
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
import { isRecipientAuthorized } from '@documenso/lib/server-only/document/is-recipient-authorized';
import { viewedDocument } from '@documenso/lib/server-only/document/viewed-document';
import { getCompletedFieldsForToken } from '@documenso/lib/server-only/field/get-completed-fields-for-token';
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
import { getRecipientSignatures } from '@documenso/lib/server-only/recipient/get-recipient-signatures';
@ -37,7 +38,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
const requestMetadata = extractNextHeaderRequestMetadata(requestHeaders);
const [document, fields, recipient] = await Promise.all([
const [document, fields, recipient, completedFields] = await Promise.all([
getDocumentAndSenderByToken({
token,
userId: user?.id,
@ -45,6 +46,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
}).catch(() => null),
getFieldsForToken({ token }),
getRecipientByToken({ token }).catch(() => null),
getCompletedFieldsForToken({ token }),
]);
if (
@ -125,7 +127,12 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
signature={user?.email === recipient.email ? user.signature : undefined}
>
<DocumentAuthProvider document={document} recipient={recipient} user={user}>
<SigningPageView recipient={recipient} document={document} fields={fields} />
<SigningPageView
recipient={recipient}
document={document}
fields={fields}
completedFields={completedFields}
/>
</DocumentAuthProvider>
</SigningProvider>
);

View File

@ -4,12 +4,14 @@ import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-form
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
import type { DocumentAndSender } from '@documenso/lib/server-only/document/get-document-by-token';
import type { CompletedField } from '@documenso/lib/types/fields';
import type { Field, Recipient } from '@documenso/prisma/client';
import { FieldType, RecipientRole } from '@documenso/prisma/client';
import { Card, CardContent } from '@documenso/ui/primitives/card';
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
import { DocumentReadOnlyFields } from '~/components/document/document-read-only-fields';
import { truncateTitle } from '~/helpers/truncate-title';
import { DateField } from './date-field';
@ -23,9 +25,15 @@ export type SigningPageViewProps = {
document: DocumentAndSender;
recipient: Recipient;
fields: Field[];
completedFields: CompletedField[];
};
export const SigningPageView = ({ document, recipient, fields }: SigningPageViewProps) => {
export const SigningPageView = ({
document,
recipient,
fields,
completedFields,
}: SigningPageViewProps) => {
const truncatedTitle = truncateTitle(document.title);
const { documentData, documentMeta } = document;
@ -70,6 +78,8 @@ export const SigningPageView = ({ document, recipient, fields }: SigningPageView
</div>
</div>
<DocumentReadOnlyFields fields={completedFields} />
<ElementVisible target={PDF_VIEWER_PAGE_SELECTOR}>
{fields.map((field) =>
match(field.type)