From cc05af2062c9f5cdd30d299e8e95f999cc6fd475 Mon Sep 17 00:00:00 2001 From: Ephraim Duncan <55143799+ephraimduncan@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:40:14 +0000 Subject: [PATCH] feat: backport the embedded mobile signing ux to main application (#1919) This PR improves the mobile experience of the document signing page by implementing a collapsible widget design for the signing form. On mobile devices, the form now appears as a fixed bottom sheet that can be expanded/collapsed, while maintaining the sticky sidebar layout on desktop. --- .../document-signing-form.tsx | 169 +++++++----------- .../document-signing-page-view.tsx | 100 ++++++++--- packages/ui/primitives/dialog.tsx | 6 +- 3 files changed, 146 insertions(+), 129 deletions(-) diff --git a/apps/remix/app/components/general/document-signing/document-signing-form.tsx b/apps/remix/app/components/general/document-signing/document-signing-form.tsx index 967c5d725..b3356bee8 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-form.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-form.tsx @@ -16,7 +16,6 @@ import { sortFieldsByPosition, validateFieldsInserted } from '@documenso/lib/uti import type { RecipientWithFields } from '@documenso/prisma/types/recipient-with-fields'; import { trpc } from '@documenso/trpc/react'; import { FieldToolTip } from '@documenso/ui/components/field/field-tooltip'; -import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; import { Input } from '@documenso/ui/primitives/input'; import { Label } from '@documenso/ui/primitives/label'; @@ -177,15 +176,7 @@ export const DocumentSigningForm = ({ }, [document.documentMeta?.signingOrder, allRecipients, recipient.id]); return ( -
+
{validateUninsertedFields && uninsertedFields[0] && ( Click to insert field @@ -194,21 +185,8 @@ export const DocumentSigningForm = ({
-

- {recipient.role === RecipientRole.VIEWER && View Document} - {recipient.role === RecipientRole.SIGNER && Sign Document} - {recipient.role === RecipientRole.APPROVER && Approve Document} - {recipient.role === RecipientRole.ASSISTANT && Assist Document} -

- {recipient.role === RecipientRole.VIEWER ? ( <> -

- Please mark as viewed to complete -

- -
-
@@ -245,15 +223,6 @@ export const DocumentSigningForm = ({ ) : recipient.role === RecipientRole.ASSISTANT ? ( <>
-

- - Complete the fields for the following signers. Once reviewed, they will inform - you if any modifications are needed. - -

- -
-
) : ( <> -
-

- {recipient.role === RecipientRole.APPROVER && !hasSignatureField ? ( - Please review the document before approving. - ) : ( - Please review the document before signing. - )} -

+
+
+
+ -
+ setFullName(e.target.value.trimStart())} + /> +
-
-
+ {hasSignatureField && (
-
- - {hasSignatureField && ( -
- - - setSignature(v ?? '')} - typedSignatureEnabled={document.documentMeta?.typedSignatureEnabled} - uploadSignatureEnabled={document.documentMeta?.uploadSignatureEnabled} - drawSignatureEnabled={document.documentMeta?.drawSignatureEnabled} - /> -
- )} -
-
- -
- - - { - await completeDocument(undefined, nextSigner); - }} - role={recipient.role} - allowDictateNextSigner={ - nextRecipient && document.documentMeta?.allowDictateNextSigner - } - defaultNextSigner={ - nextRecipient - ? { name: nextRecipient.name, email: nextRecipient.email } - : undefined - } - /> + )}
+
+ +
+ + + { + await completeDocument(undefined, nextSigner); + }} + role={recipient.role} + allowDictateNextSigner={ + nextRecipient && document.documentMeta?.allowDictateNextSigner + } + defaultNextSigner={ + nextRecipient + ? { name: nextRecipient.name, email: nextRecipient.email } + : undefined + } + />
)} diff --git a/apps/remix/app/components/general/document-signing/document-signing-page-view.tsx b/apps/remix/app/components/general/document-signing/document-signing-page-view.tsx index e750bae74..a1bf3d24e 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-page-view.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-page-view.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import { Trans } from '@lingui/react/macro'; import type { Field } from '@prisma/client'; import { FieldType, RecipientRole } from '@prisma/client'; +import { LucideChevronDown, LucideChevronUp } from 'lucide-react'; import { match } from 'ts-pattern'; import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats'; @@ -20,6 +21,7 @@ import type { CompletedField } from '@documenso/lib/types/fields'; import type { FieldWithSignatureAndFieldMeta } from '@documenso/prisma/types/field-with-signature-and-fieldmeta'; import type { RecipientWithFields } from '@documenso/prisma/types/recipient-with-fields'; import { DocumentReadOnlyFields } from '@documenso/ui/components/document/document-read-only-fields'; +import { Button } from '@documenso/ui/primitives/button'; import { Card, CardContent } from '@documenso/ui/primitives/card'; import { ElementVisible } from '@documenso/ui/primitives/element-visible'; import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer'; @@ -62,6 +64,7 @@ export const DocumentSigningPageView = ({ const { documentData, documentMeta } = document; const [selectedSignerId, setSelectedSignerId] = useState(allRecipients?.[0]?.id); + const [isExpanded, setIsExpanded] = useState(false); let senderName = document.user.name ?? ''; let senderEmail = `(${document.user.email})`; @@ -77,15 +80,15 @@ export const DocumentSigningPageView = ({ return ( -
+

{document.title}

-
+
{senderName} {senderEmail} @@ -135,26 +138,79 @@ export const DocumentSigningPageView = ({
-
- - - - - +
+
+ + + + + +
-
- +
+
+
+

+ {match(recipient.role) + .with(RecipientRole.VIEWER, () => View Document) + .with(RecipientRole.SIGNER, () => Sign Document) + .with(RecipientRole.APPROVER, () => Approve Document) + .with(RecipientRole.ASSISTANT, () => Assist Document) + .otherwise(() => null)} +

+ + +
+ +
+

+ {match(recipient.role) + .with(RecipientRole.VIEWER, () => ( + Please mark as viewed to complete. + )) + .with(RecipientRole.SIGNER, () => ( + Please review the document before signing. + )) + .with(RecipientRole.APPROVER, () => ( + Please review the document before approving. + )) + .with(RecipientRole.ASSISTANT, () => ( + Complete the fields for the following signers. + )) + .otherwise(() => null)} +

+ +
+
+ +
+ +
+
diff --git a/packages/ui/primitives/dialog.tsx b/packages/ui/primitives/dialog.tsx index 70d3f4afd..59c126fcc 100644 --- a/packages/ui/primitives/dialog.tsx +++ b/packages/ui/primitives/dialog.tsx @@ -65,7 +65,11 @@ const DialogContent = React.forwardRef<