mirror of
https://github.com/documenso/documenso.git
synced 2026-09-29 16:24:30 +10:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02166af7eb | ||
|
|
a3fbd791de | ||
|
|
5874b8f8c4 | ||
|
|
c66270ad9d |
@@ -120,25 +120,20 @@ Specific parts of the embed can be targeted with CSS classes for granular stylin
|
||||
|
||||
### Component Classes
|
||||
|
||||
| Class | Description |
|
||||
| ---------------------------------------- | --------------------------------------------- |
|
||||
| `.embed--Root` | Main container for the embedded experience |
|
||||
| `.embed--DocumentContainer` | Container for the document and signing widget |
|
||||
| `.embed--DocumentViewer` | Container for the document viewer |
|
||||
| `.embed--DocumentWidget` | The signing widget container |
|
||||
| `.embed--DocumentWidgetContainer` | Outer container for the signing widget |
|
||||
| `.embed--DocumentWidgetHeader` | Header section of the signing widget |
|
||||
| `.embed--DocumentWidgetContent` | Main content area of the signing widget |
|
||||
| `.embed--DocumentWidgetForm` | Form section within the signing widget |
|
||||
| `.embed--DocumentWidgetFooter` | Footer section of the signing widget |
|
||||
| `.embed--WaitingForTurn` | Waiting screen when it is not the user's turn |
|
||||
| `.embed--DocumentCompleted` | Completion screen after signing |
|
||||
| `.embed--DocumentCompletedCard` | Signature card on the completion screen |
|
||||
| `.embed--DocumentCompletedTitle` | Title on the completion screen |
|
||||
| `.embed--DocumentCompletedStatus` | Status line on the completion screen |
|
||||
| `.embed--DocumentCompletedDescription` | Description text on the completion screen |
|
||||
| `.embed--DocumentRejected` | Rejection screen after rejecting the document |
|
||||
| `.field--FieldRootContainer` | Base container for document fields |
|
||||
| Class | Description |
|
||||
| --------------------------------- | --------------------------------------------- |
|
||||
| `.embed--Root` | Main container for the embedded experience |
|
||||
| `.embed--DocumentContainer` | Container for the document and signing widget |
|
||||
| `.embed--DocumentViewer` | Container for the document viewer |
|
||||
| `.embed--DocumentWidget` | The signing widget container |
|
||||
| `.embed--DocumentWidgetContainer` | Outer container for the signing widget |
|
||||
| `.embed--DocumentWidgetHeader` | Header section of the signing widget |
|
||||
| `.embed--DocumentWidgetContent` | Main content area of the signing widget |
|
||||
| `.embed--DocumentWidgetForm` | Form section within the signing widget |
|
||||
| `.embed--DocumentWidgetFooter` | Footer section of the signing widget |
|
||||
| `.embed--WaitingForTurn` | Waiting screen when it is not the user's turn |
|
||||
| `.embed--DocumentCompleted` | Completion screen after signing |
|
||||
| `.field--FieldRootContainer` | Base container for document fields |
|
||||
|
||||
### Field Data Attributes
|
||||
|
||||
|
||||
@@ -191,9 +191,6 @@ For manual deployments or troubleshooting:
|
||||
```bash
|
||||
# Apply pending migrations
|
||||
npm run prisma:migrate-deploy
|
||||
|
||||
# Or using npx directly
|
||||
npx prisma migrate deploy
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
|
||||
@@ -426,8 +426,9 @@ docker pull documenso/documenso:<version>
|
||||
# Run migrations only
|
||||
docker run --rm \
|
||||
-e NEXT_PRIVATE_DATABASE_URL="postgresql://user:password@host:5432/documenso" \
|
||||
-e NEXT_PRIVATE_DIRECT_DATABASE_URL="postgresql://user:password@host:5432/documenso" \
|
||||
documenso/documenso:<version> \
|
||||
npx prisma migrate deploy
|
||||
npx prisma migrate deploy --schema ../../packages/prisma/schema.prisma
|
||||
```
|
||||
|
||||
<Callout type="warn">
|
||||
|
||||
@@ -2,7 +2,6 @@ import signingCelebration from '@documenso/assets/images/signing-celebration.png
|
||||
import { SigningCard3D } from '@documenso/ui/components/signing-card';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { Signature } from '@prisma/client';
|
||||
import { CheckCircle2Icon } from 'lucide-react';
|
||||
|
||||
export type EmbedDocumentCompletedPageProps = {
|
||||
name?: string;
|
||||
@@ -11,8 +10,12 @@ export type EmbedDocumentCompletedPageProps = {
|
||||
|
||||
export const EmbedDocumentCompleted = ({ name, signature }: EmbedDocumentCompletedPageProps) => {
|
||||
return (
|
||||
<div className="embed--DocumentCompleted relative mx-auto flex min-h-[100dvh] max-w-screen-lg flex-col items-center justify-center overflow-hidden p-6">
|
||||
<div className="embed--DocumentCompletedCard w-full max-w-sm md:max-w-md">
|
||||
<div className="embed--DocumentCompleted relative mx-auto flex min-h-[100dvh] max-w-screen-lg flex-col items-center justify-center p-6">
|
||||
<h3 className="font-semibold text-2xl text-foreground">
|
||||
<Trans>Document Completed!</Trans>
|
||||
</h3>
|
||||
|
||||
<div className="mt-8 w-full max-w-md">
|
||||
<SigningCard3D
|
||||
className="mx-auto w-full"
|
||||
name={name || 'Documenso'}
|
||||
@@ -21,19 +24,10 @@ export const EmbedDocumentCompleted = ({ name, signature }: EmbedDocumentComplet
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h2 className="embed--DocumentCompletedTitle mt-8 max-w-[35ch] text-center font-semibold text-2xl text-foreground leading-normal md:text-3xl">
|
||||
<Trans>Document Completed</Trans>
|
||||
</h2>
|
||||
|
||||
<div className="embed--DocumentCompletedStatus mt-4 flex items-center text-center text-documenso-700">
|
||||
<CheckCircle2Icon className="mr-2 h-5 w-5" />
|
||||
<span className="text-sm">
|
||||
<Trans>No further action is required</Trans>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p className="embed--DocumentCompletedDescription mt-2.5 max-w-[50ch] text-center font-medium text-muted-foreground/60 text-sm md:text-base">
|
||||
<Trans>Please follow any instructions provided within the parent application.</Trans>
|
||||
<p className="mt-8 max-w-[50ch] text-center text-muted-foreground text-sm">
|
||||
<Trans>
|
||||
The document is now completed, please follow any instructions provided within the parent application.
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -55,7 +55,6 @@ export type EmbedSignDocumentV1ClientPageProps = {
|
||||
completedFields: DocumentField[];
|
||||
metadata?: DocumentMeta | null;
|
||||
isCompleted?: boolean;
|
||||
isRejected?: boolean;
|
||||
hidePoweredBy?: boolean;
|
||||
allowWhitelabelling?: boolean;
|
||||
allRecipients?: RecipientWithFields[];
|
||||
@@ -71,7 +70,6 @@ export const EmbedSignDocumentV1ClientPage = ({
|
||||
completedFields,
|
||||
metadata,
|
||||
isCompleted,
|
||||
isRejected,
|
||||
hidePoweredBy = false,
|
||||
allowWhitelabelling = false,
|
||||
allRecipients = [],
|
||||
@@ -85,9 +83,7 @@ export const EmbedSignDocumentV1ClientPage = ({
|
||||
const [hasFinishedInit, setHasFinishedInit] = useState(false);
|
||||
const [hasDocumentLoaded, setHasDocumentLoaded] = useState(false);
|
||||
const [hasCompletedDocument, setHasCompletedDocument] = useState(isCompleted);
|
||||
const [hasRejectedDocument, setHasRejectedDocument] = useState(
|
||||
isRejected ?? recipient.signingStatus === SigningStatus.REJECTED,
|
||||
);
|
||||
const [hasRejectedDocument, setHasRejectedDocument] = useState(recipient.signingStatus === SigningStatus.REJECTED);
|
||||
const [selectedSignerId, setSelectedSignerId] = useState<number | null>(
|
||||
allRecipients.length > 0 ? allRecipients[0].id : null,
|
||||
);
|
||||
@@ -267,44 +263,6 @@ export const EmbedSignDocumentV1ClientPage = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!window.parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasRejectedDocument) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
action: 'document-rejected',
|
||||
data: {
|
||||
token,
|
||||
documentId,
|
||||
recipientId: recipient.id,
|
||||
},
|
||||
},
|
||||
'*',
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasCompletedDocument) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
action: 'document-completed',
|
||||
data: {
|
||||
token,
|
||||
documentId,
|
||||
recipientId: recipient.id,
|
||||
},
|
||||
},
|
||||
'*',
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasFinishedInit && hasDocumentLoaded && window.parent) {
|
||||
window.parent.postMessage(
|
||||
|
||||
@@ -40,18 +40,12 @@ export const EmbedSignDocumentV2ClientPage = ({
|
||||
const [isNameLocked, setIsNameLocked] = useState(false);
|
||||
const [isEmailLocked, setIsEmailLocked] = useState(envelope.type === EnvelopeType.DOCUMENT && !!email);
|
||||
|
||||
// The signing provider's envelope data isn't refreshed on revalidation.
|
||||
const [hasCompletedDocument, setHasCompletedDocument] = useState(isCompleted);
|
||||
const [hasRejectedDocument, setHasRejectedDocument] = useState(isRejected);
|
||||
|
||||
const onDocumentCompleted = (data: {
|
||||
token: string;
|
||||
documentId: number;
|
||||
envelopeId: string;
|
||||
recipientId: number;
|
||||
}) => {
|
||||
setHasCompletedDocument(true);
|
||||
|
||||
if (window.parent) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
@@ -118,8 +112,6 @@ export const EmbedSignDocumentV2ClientPage = ({
|
||||
recipientId: number;
|
||||
reason?: string;
|
||||
}) => {
|
||||
setHasRejectedDocument(true);
|
||||
|
||||
if (window.parent) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
@@ -227,26 +219,23 @@ export const EmbedSignDocumentV2ClientPage = ({
|
||||
}
|
||||
}, [isRejected, envelope.id, recipient.id, recipient.token]);
|
||||
|
||||
if (hasRejectedDocument) {
|
||||
if (isRejected) {
|
||||
return <EmbedDocumentRejected />;
|
||||
}
|
||||
|
||||
if (hasCompletedDocument) {
|
||||
const completedSignature =
|
||||
recipient.fields.find((field) => field.signature)?.signature ?? recipientSignature ?? null;
|
||||
|
||||
if (isCompleted) {
|
||||
return (
|
||||
<EmbedDocumentCompleted
|
||||
name={fullName}
|
||||
signature={
|
||||
completedSignature
|
||||
recipientSignature
|
||||
? {
|
||||
id: 1,
|
||||
fieldId: 1,
|
||||
recipientId: recipient.id,
|
||||
created: new Date(),
|
||||
signatureImageAsBase64: completedSignature.signatureImageAsBase64,
|
||||
typedSignature: completedSignature.typedSignature,
|
||||
signatureImageAsBase64: recipientSignature.signatureImageAsBase64,
|
||||
typedSignature: recipientSignature.typedSignature,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import { cn } from '@documenso/ui/lib/utils';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import pMap from 'p-map';
|
||||
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs';
|
||||
import pdfjsWorker from 'pdfjs-dist/legacy/build/pdf.worker.mjs?url';
|
||||
import * as pdfjsLib from 'pdfjs-dist';
|
||||
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker?url';
|
||||
import type React from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { isDocumentCompleted } from '@documenso/lib/utils/document';
|
||||
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
|
||||
import { isRecipientExpired } from '@documenso/lib/utils/recipients';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { RecipientRole, SigningStatus } from '@prisma/client';
|
||||
import { RecipientRole } from '@prisma/client';
|
||||
import { data } from 'react-router';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
@@ -80,11 +80,7 @@ async function handleV1Loader({ params, request }: Route.LoaderArgs) {
|
||||
);
|
||||
}
|
||||
|
||||
const isCompleted = recipient.signingStatus === SigningStatus.SIGNED || isDocumentCompleted(document.status);
|
||||
const isRejected = recipient.signingStatus === SigningStatus.REJECTED;
|
||||
const hasRecipientActioned = isCompleted || isRejected;
|
||||
|
||||
if (!hasRecipientActioned && isRecipientExpired(recipient)) {
|
||||
if (isRecipientExpired(recipient)) {
|
||||
throw data(
|
||||
{
|
||||
type: 'embed-recipient-expired',
|
||||
@@ -119,7 +115,7 @@ async function handleV1Loader({ params, request }: Route.LoaderArgs) {
|
||||
);
|
||||
}
|
||||
|
||||
const isRecipientsTurnToSign = hasRecipientActioned || (await getIsRecipientsTurnToSign({ token }));
|
||||
const isRecipientsTurnToSign = await getIsRecipientsTurnToSign({ token });
|
||||
|
||||
if (!isRecipientsTurnToSign) {
|
||||
throw data(
|
||||
@@ -177,8 +173,6 @@ async function handleV1Loader({ params, request }: Route.LoaderArgs) {
|
||||
recipient,
|
||||
fields,
|
||||
completedFields,
|
||||
isCompleted,
|
||||
isRejected,
|
||||
hidePoweredBy,
|
||||
allowEmbedSigningWhitelabel,
|
||||
};
|
||||
@@ -398,8 +392,6 @@ const EmbedSignDocumentPageV1 = ({ data }: { data: Awaited<ReturnType<typeof han
|
||||
recipient,
|
||||
fields,
|
||||
completedFields,
|
||||
isCompleted,
|
||||
isRejected,
|
||||
hidePoweredBy,
|
||||
allowEmbedSigningWhitelabel,
|
||||
} = data;
|
||||
@@ -423,8 +415,7 @@ const EmbedSignDocumentPageV1 = ({ data }: { data: Awaited<ReturnType<typeof han
|
||||
fields={fields}
|
||||
completedFields={completedFields}
|
||||
metadata={document.documentMeta}
|
||||
isCompleted={isCompleted}
|
||||
isRejected={isRejected}
|
||||
isCompleted={isDocumentCompleted(document.status)}
|
||||
hidePoweredBy={hidePoweredBy}
|
||||
allowWhitelabelling={allowEmbedSigningWhitelabel}
|
||||
allRecipients={allRecipients}
|
||||
|
||||
@@ -106,5 +106,5 @@
|
||||
"vite-plugin-babel-macros": "^1.0.6",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
},
|
||||
"version": "2.19.0"
|
||||
"version": "2.18.0"
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ printf "🏥 Health check: http://localhost:3000/api/health\n"
|
||||
printf "📊 Certificate status: http://localhost:3000/api/certificate-status\n"
|
||||
printf "👥 Community: https://github.com/documenso/documenso\n\n"
|
||||
|
||||
# The Prisma schema requires a direct URL. Without a connection pooler, it is the same as the database URL.
|
||||
export NEXT_PRIVATE_DIRECT_DATABASE_URL="${NEXT_PRIVATE_DIRECT_DATABASE_URL:-$NEXT_PRIVATE_DATABASE_URL}"
|
||||
|
||||
printf "🗄️ Running database migrations...\n"
|
||||
npx prisma migrate deploy --schema ../../packages/prisma/schema.prisma
|
||||
|
||||
|
||||
Generated
+3
-3
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@documenso/root",
|
||||
"version": "2.19.0",
|
||||
"version": "2.18.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@documenso/root",
|
||||
"version": "2.19.0",
|
||||
"version": "2.18.0",
|
||||
"hasInstallScript": true,
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
@@ -193,7 +193,7 @@
|
||||
},
|
||||
"apps/remix": {
|
||||
"name": "@documenso/remix",
|
||||
"version": "2.19.0",
|
||||
"version": "2.18.0",
|
||||
"dependencies": {
|
||||
"@cantoo/pdf-lib": "^2.5.3",
|
||||
"@documenso/api": "*",
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "2.19.0",
|
||||
"version": "2.18.0",
|
||||
"scripts": {
|
||||
"postinstall": "patch-package",
|
||||
"build": "turbo run build",
|
||||
|
||||
Reference in New Issue
Block a user