feat: allow editing pending documents (#1346)

## Description

Adds the ability for the document owner to edit recipients and their
fields after the document has been sent.

A recipient can only be updated or deleted if:
- The recipient has not inserted any fields
- Has not completed the document

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

## Release Notes

- **New Features**
- Added new localization messages to clarify user actions regarding
document signing.
  - Enhanced French translations for improved user interaction.

- **Improvements**
- Updated localization strings in German and English for clearer
feedback on signer and recipient statuses.
- Improved overall structure of localization files for better
maintainability.

- **Dependency Updates**
- Upgraded `next-axiom` and `remeda` libraries to their latest versions,
potentially enhancing performance and stability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Mythie <me@lucasjamessmith.me>
This commit is contained in:
David Nguyen
2024-09-20 13:58:21 +10:00
committed by GitHub
parent efb2bc94ab
commit ddee8a8272
21 changed files with 533 additions and 204 deletions

View File

@ -34,7 +34,7 @@
"micro": "^10.0.1", "micro": "^10.0.1",
"next": "14.2.6", "next": "14.2.6",
"next-auth": "4.24.5", "next-auth": "4.24.5",
"next-axiom": "^1.1.1", "next-axiom": "^1.5.1",
"next-contentlayer": "^0.3.4", "next-contentlayer": "^0.3.4",
"next-plausible": "^3.10.1", "next-plausible": "^3.10.1",
"perfect-freehand": "^1.2.0", "perfect-freehand": "^1.2.0",
@ -56,4 +56,4 @@
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18" "@types/react-dom": "^18"
} }
} }

View File

@ -37,7 +37,7 @@
"micro": "^10.0.1", "micro": "^10.0.1",
"next": "14.2.6", "next": "14.2.6",
"next-auth": "4.24.5", "next-auth": "4.24.5",
"next-axiom": "^1.1.1", "next-axiom": "^1.5.1",
"next-plausible": "^3.10.1", "next-plausible": "^3.10.1",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",
"papaparse": "^5.4.1", "papaparse": "^5.4.1",
@ -53,7 +53,7 @@
"react-icons": "^4.11.0", "react-icons": "^4.11.0",
"react-rnd": "^10.4.1", "react-rnd": "^10.4.1",
"recharts": "^2.7.2", "recharts": "^2.7.2",
"remeda": "^1.27.1", "remeda": "^2.12.1",
"sharp": "0.32.6", "sharp": "0.32.6",
"ts-pattern": "^5.0.5", "ts-pattern": "^5.0.5",
"ua-parser-js": "^1.0.37", "ua-parser-js": "^1.0.37",
@ -74,4 +74,4 @@
"@types/ua-parser-js": "^0.7.39", "@types/ua-parser-js": "^0.7.39",
"typescript": "5.2.2" "typescript": "5.2.2"
} }
} }

98
package-lock.json generated
View File

@ -103,7 +103,7 @@
"micro": "^10.0.1", "micro": "^10.0.1",
"next": "14.2.6", "next": "14.2.6",
"next-auth": "4.24.5", "next-auth": "4.24.5",
"next-axiom": "^1.1.1", "next-axiom": "^1.5.1",
"next-contentlayer": "^0.3.4", "next-contentlayer": "^0.3.4",
"next-plausible": "^3.10.1", "next-plausible": "^3.10.1",
"perfect-freehand": "^1.2.0", "perfect-freehand": "^1.2.0",
@ -410,6 +410,23 @@
} }
} }
}, },
"apps/marketing/node_modules/next-axiom": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/next-axiom/-/next-axiom-1.5.1.tgz",
"integrity": "sha512-sWxIzuJOex48ugMDlXWzvGvDGv5YHZ3w8gLZbUQ/Yml7oy5jcCItJNws9D0qmASirp2e5/BnvHxs44+9CO0GAQ==",
"license": "MIT",
"dependencies": {
"use-deep-compare": "^1.2.1",
"whatwg-fetch": "^3.6.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"next": ">=14.0",
"react": ">=18.0.0"
}
},
"apps/marketing/node_modules/typescript": { "apps/marketing/node_modules/typescript": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
@ -449,7 +466,7 @@
"micro": "^10.0.1", "micro": "^10.0.1",
"next": "14.2.6", "next": "14.2.6",
"next-auth": "4.24.5", "next-auth": "4.24.5",
"next-axiom": "^1.1.1", "next-axiom": "^1.5.1",
"next-plausible": "^3.10.1", "next-plausible": "^3.10.1",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",
"papaparse": "^5.4.1", "papaparse": "^5.4.1",
@ -465,7 +482,7 @@
"react-icons": "^4.11.0", "react-icons": "^4.11.0",
"react-rnd": "^10.4.1", "react-rnd": "^10.4.1",
"recharts": "^2.7.2", "recharts": "^2.7.2",
"remeda": "^1.27.1", "remeda": "^2.12.1",
"sharp": "0.32.6", "sharp": "0.32.6",
"ts-pattern": "^5.0.5", "ts-pattern": "^5.0.5",
"ua-parser-js": "^1.0.37", "ua-parser-js": "^1.0.37",
@ -493,6 +510,23 @@
"integrity": "sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==", "integrity": "sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==",
"dev": true "dev": true
}, },
"apps/web/node_modules/next-axiom": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/next-axiom/-/next-axiom-1.5.1.tgz",
"integrity": "sha512-sWxIzuJOex48ugMDlXWzvGvDGv5YHZ3w8gLZbUQ/Yml7oy5jcCItJNws9D0qmASirp2e5/BnvHxs44+9CO0GAQ==",
"license": "MIT",
"dependencies": {
"use-deep-compare": "^1.2.1",
"whatwg-fetch": "^3.6.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"next": ">=14.0",
"react": ">=18.0.0"
}
},
"apps/web/node_modules/typescript": { "apps/web/node_modules/typescript": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
@ -24150,22 +24184,6 @@
} }
} }
}, },
"node_modules/next-axiom": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/next-axiom/-/next-axiom-1.1.1.tgz",
"integrity": "sha512-0r/TJ+/zetD+uDc7B+2E7WpC86hEtQ1U+DuWYrP/JNmUz+ZdPFbrZgzOSqaZ6TwYbXP56VVlPfYwq1YsKHTHYQ==",
"dependencies": {
"remeda": "^1.29.0",
"whatwg-fetch": "^3.6.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"next": ">=13.4",
"react": ">=18.0.0"
}
},
"node_modules/next-contentlayer": { "node_modules/next-contentlayer": {
"version": "0.3.4", "version": "0.3.4",
"resolved": "https://registry.npmjs.org/next-contentlayer/-/next-contentlayer-0.3.4.tgz", "resolved": "https://registry.npmjs.org/next-contentlayer/-/next-contentlayer-0.3.4.tgz",
@ -30130,9 +30148,25 @@
} }
}, },
"node_modules/remeda": { "node_modules/remeda": {
"version": "1.29.0", "version": "2.12.1",
"resolved": "https://registry.npmjs.org/remeda/-/remeda-1.29.0.tgz", "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.12.1.tgz",
"integrity": "sha512-M3LQ14KtMdQ1879lj/kKji3zBk158s7Rwg963mEkTfQFMxnKrIEAMxJfo/+0sp/+uGgN/KMVU2MBA4LNjqf8YQ==" "integrity": "sha512-hKFAbxbQe8PMd4+CYO1DYCrCbcZsUSa7e21g7+4co91GBy7BD+Ub6JdaLy76yPOp7PCPTAXRz/9NXtZ9w15jbg==",
"license": "MIT",
"dependencies": {
"type-fest": "^4.26.1"
}
},
"node_modules/remeda/node_modules/type-fest": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz",
"integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==",
"license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}, },
"node_modules/remote-git-tags": { "node_modules/remote-git-tags": {
"version": "3.0.0", "version": "3.0.0",
@ -34195,6 +34229,18 @@
} }
} }
}, },
"node_modules/use-deep-compare": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/use-deep-compare/-/use-deep-compare-1.3.0.tgz",
"integrity": "sha512-94iG+dEdEP/Sl3WWde+w9StIunlV8Dgj+vkt5wTwMoFQLaijiEZSXXy8KtcStpmEDtIptRJiNeD4ACTtVvnIKA==",
"license": "MIT",
"dependencies": {
"dequal": "2.0.3"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/use-memo-one": { "node_modules/use-memo-one": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz",
@ -36751,7 +36797,7 @@
"pg": "^8.11.3", "pg": "^8.11.3",
"playwright": "1.43.0", "playwright": "1.43.0",
"react": "^18", "react": "^18",
"remeda": "^1.27.1", "remeda": "^2.12.1",
"sharp": "0.32.6", "sharp": "0.32.6",
"stripe": "^12.7.0", "stripe": "^12.7.0",
"ts-pattern": "^5.0.5", "ts-pattern": "^5.0.5",
@ -37050,6 +37096,12 @@
"node": ">=6" "node": ">=6"
} }
}, },
"packages/ui/node_modules/remeda": {
"version": "1.61.0",
"resolved": "https://registry.npmjs.org/remeda/-/remeda-1.61.0.tgz",
"integrity": "sha512-caKfSz9rDeSKBQQnlJnVW3mbVdFgxgGWQKq1XlFokqjf+hQD5gxutLGTTY2A/x24UxVyJe9gH5fAkFI63ULw4A==",
"license": "MIT"
},
"packages/ui/node_modules/typescript": { "packages/ui/node_modules/typescript": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",

View File

@ -2,7 +2,7 @@
import { createContext, useCallback, useContext, useEffect, useState } from 'react'; import { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { equals } from 'remeda'; import { isDeepEqual } from 'remeda';
import { getLimits } from '../client'; import { getLimits } from '../client';
import { FREE_PLAN_LIMITS } from '../constants'; import { FREE_PLAN_LIMITS } from '../constants';
@ -42,7 +42,7 @@ export const LimitsProvider = ({
const newLimits = await getLimits({ teamId }); const newLimits = await getLimits({ teamId });
setLimits((oldLimits) => { setLimits((oldLimits) => {
if (equals(oldLimits, newLimits)) { if (isDeepEqual(oldLimits, newLimits)) {
return oldLimits; return oldLimits;
} }

View File

@ -0,0 +1,78 @@
import config from '@documenso/tailwind-config';
import {
Body,
Container,
Head,
Hr,
Html,
Img,
Preview,
Section,
Tailwind,
Text,
} from '../components';
import type { TemplateDocumentCancelProps } from '../template-components/template-document-cancel';
import TemplateDocumentImage from '../template-components/template-document-image';
import { TemplateFooter } from '../template-components/template-footer';
export type DocumentCancelEmailTemplateProps = Partial<TemplateDocumentCancelProps>;
export const RecipientRemovedFromDocumentTemplate = ({
inviterName = 'Lucas Smith',
documentName = 'Open Source Pledge.pdf',
assetBaseUrl = 'http://localhost:3002',
}: DocumentCancelEmailTemplateProps) => {
const previewText = `${inviterName} has removed you from the document ${documentName}.`;
const getAssetUrl = (path: string) => {
return new URL(path, assetBaseUrl).toString();
};
return (
<Html>
<Head />
<Preview>{previewText}</Preview>
<Tailwind
config={{
theme: {
extend: {
colors: config.theme.extend.colors,
},
},
}}
>
<Body className="mx-auto my-auto bg-white font-sans">
<Section>
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
<Section>
<Img
src={getAssetUrl('/static/logo.png')}
alt="Documenso Logo"
className="mb-4 h-6"
/>
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
<Section>
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
{inviterName} has removed you from the document
<br />"{documentName}"
</Text>
</Section>
</Section>
</Container>
<Hr className="mx-auto mt-12 max-w-xl" />
<Container className="mx-auto max-w-xl">
<TemplateFooter />
</Container>
</Section>
</Body>
</Tailwind>
</Html>
);
};
export default RecipientRemovedFromDocumentTemplate;

View File

@ -48,7 +48,7 @@
"pg": "^8.11.3", "pg": "^8.11.3",
"playwright": "1.43.0", "playwright": "1.43.0",
"react": "^18", "react": "^18",
"remeda": "^1.27.1", "remeda": "^2.12.1",
"sharp": "0.32.6", "sharp": "0.32.6",
"stripe": "^12.7.0", "stripe": "^12.7.0",
"ts-pattern": "^5.0.5", "ts-pattern": "^5.0.5",

View File

@ -1,3 +1,5 @@
import { isDeepEqual } from 'remeda';
import { validateCheckboxField } from '@documenso/lib/advanced-fields-validation/validate-checkbox'; import { validateCheckboxField } from '@documenso/lib/advanced-fields-validation/validate-checkbox';
import { validateDropdownField } from '@documenso/lib/advanced-fields-validation/validate-dropdown'; import { validateDropdownField } from '@documenso/lib/advanced-fields-validation/validate-dropdown';
import { validateNumberField } from '@documenso/lib/advanced-fields-validation/validate-number'; import { validateNumberField } from '@documenso/lib/advanced-fields-validation/validate-number';
@ -20,22 +22,15 @@ import {
} from '@documenso/lib/utils/document-audit-logs'; } from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
import type { Field } from '@documenso/prisma/client'; import type { Field } from '@documenso/prisma/client';
import { FieldType, SendStatus, SigningStatus } from '@documenso/prisma/client'; import { FieldType } from '@documenso/prisma/client';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientFieldsBeModified } from '../../utils/recipients';
export interface SetFieldsForDocumentOptions { export interface SetFieldsForDocumentOptions {
userId: number; userId: number;
documentId: number; documentId: number;
fields: { fields: FieldData[];
id?: number | null;
type: FieldType;
signerEmail: string;
pageNumber: number;
pageX: number;
pageY: number;
pageWidth: number;
pageHeight: number;
fieldMeta?: FieldMeta;
}[];
requestMetadata?: RequestMetadata; requestMetadata?: RequestMetadata;
} }
@ -63,6 +58,9 @@ export const setFieldsForDocument = async ({
}, },
], ],
}, },
include: {
Recipient: true,
},
}); });
const user = await prisma.user.findFirstOrThrow({ const user = await prisma.user.findFirstOrThrow({
@ -97,21 +95,36 @@ export const setFieldsForDocument = async ({
(existingField) => !fields.find((field) => field.id === existingField.id), (existingField) => !fields.find((field) => field.id === existingField.id),
); );
const linkedFields = fields const linkedFields = fields.map((field) => {
.map((field) => { const existing = existingFields.find((existingField) => existingField.id === field.id);
const existing = existingFields.find((existingField) => existingField.id === field.id);
return { const recipient = document.Recipient.find(
...field, (recipient) => recipient.email.toLowerCase() === field.signerEmail.toLowerCase(),
_persisted: existing, );
};
}) // Each field MUST have a recipient associated with it.
.filter((field) => { if (!recipient) {
return ( throw new AppError(AppErrorCode.INVALID_REQUEST, `Recipient not found for field ${field.id}`);
field._persisted?.Recipient?.sendStatus !== SendStatus.SENT && }
field._persisted?.Recipient?.signingStatus !== SigningStatus.SIGNED
// Check whether the existing field can be modified.
if (
existing &&
hasFieldBeenChanged(existing, field) &&
!canRecipientFieldsBeModified(recipient, existingFields)
) {
throw new AppError(
AppErrorCode.INVALID_REQUEST,
'Cannot modify a field where the recipient has already interacted with the document',
); );
}); }
return {
...field,
_persisted: existing,
_recipient: recipient,
};
});
const persistedFields = await prisma.$transaction(async (tx) => { const persistedFields = await prisma.$transaction(async (tx) => {
return await Promise.all( return await Promise.all(
@ -322,3 +335,33 @@ export const setFieldsForDocument = async ({
return [...filteredFields, ...persistedFields]; return [...filteredFields, ...persistedFields];
}; };
/**
* If you change this you MUST update the `hasFieldBeenChanged` function.
*/
type FieldData = {
id?: number | null;
type: FieldType;
signerEmail: string;
pageNumber: number;
pageX: number;
pageY: number;
pageWidth: number;
pageHeight: number;
fieldMeta?: FieldMeta;
};
const hasFieldBeenChanged = (field: Field, newFieldData: FieldData) => {
const currentFieldMeta = field.fieldMeta || null;
const newFieldMeta = newFieldData.fieldMeta || null;
return (
field.type !== newFieldData.type ||
field.page !== newFieldData.pageNumber ||
field.positionX.toNumber() !== newFieldData.pageX ||
field.positionY.toNumber() !== newFieldData.pageY ||
field.width.toNumber() !== newFieldData.pageWidth ||
field.height.toNumber() !== newFieldData.pageHeight ||
!isDeepEqual(currentFieldMeta, newFieldMeta)
);
};

View File

@ -1,4 +1,9 @@
import { createElement } from 'react';
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise'; import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
import { mailer } from '@documenso/email/mailer';
import { render } from '@documenso/email/render';
import RecipientRemovedFromDocumentTemplate from '@documenso/email/templates/recipient-removed-from-document';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs'; import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import { import {
type TRecipientActionAuthTypes, type TRecipientActionAuthTypes,
@ -16,20 +21,16 @@ import type { Recipient } from '@documenso/prisma/client';
import { RecipientRole } from '@documenso/prisma/client'; import { RecipientRole } from '@documenso/prisma/client';
import { SendStatus, SigningStatus } from '@documenso/prisma/client'; import { SendStatus, SigningStatus } from '@documenso/prisma/client';
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
import { FROM_ADDRESS, FROM_NAME } from '../../constants/email';
import { AppError, AppErrorCode } from '../../errors/app-error'; import { AppError, AppErrorCode } from '../../errors/app-error';
import { canRecipientBeModified } from '../../utils/recipients';
export interface SetRecipientsForDocumentOptions { export interface SetRecipientsForDocumentOptions {
userId: number; userId: number;
teamId?: number; teamId?: number;
documentId: number; documentId: number;
recipients: { recipients: RecipientData[];
id?: number | null;
email: string;
name: string;
role: RecipientRole;
signingOrder?: number | null;
actionAuth?: TRecipientActionAuthTypes | null;
}[];
requestMetadata?: RequestMetadata; requestMetadata?: RequestMetadata;
} }
@ -59,6 +60,9 @@ export const setRecipientsForDocument = async ({
teamId: null, teamId: null,
}), }),
}, },
include: {
Field: true,
},
}); });
const user = await prisma.user.findFirstOrThrow({ const user = await prisma.user.findFirstOrThrow({
@ -116,25 +120,28 @@ export const setRecipientsForDocument = async ({
), ),
); );
const linkedRecipients = normalizedRecipients const linkedRecipients = normalizedRecipients.map((recipient) => {
.map((recipient) => { const existing = existingRecipients.find(
const existing = existingRecipients.find( (existingRecipient) =>
(existingRecipient) => existingRecipient.id === recipient.id || existingRecipient.email === recipient.email,
existingRecipient.id === recipient.id || existingRecipient.email === recipient.email, );
);
return { if (
...recipient, existing &&
_persisted: existing, hasRecipientBeenChanged(existing, recipient) &&
}; !canRecipientBeModified(existing, document.Field)
}) ) {
.filter((recipient) => { throw new AppError(
return ( AppErrorCode.INVALID_REQUEST,
recipient._persisted?.role === RecipientRole.CC || 'Cannot modify a recipient who has already interacted with the document',
(recipient._persisted?.sendStatus !== SendStatus.SENT &&
recipient._persisted?.signingStatus !== SigningStatus.SIGNED)
); );
}); }
return {
...recipient,
_persisted: existing,
};
});
const persistedRecipients = await prisma.$transaction(async (tx) => { const persistedRecipients = await prisma.$transaction(async (tx) => {
return await Promise.all( return await Promise.all(
@ -268,6 +275,37 @@ export const setRecipientsForDocument = async ({
), ),
}); });
}); });
// Send emails to deleted recipients.
await Promise.all(
removedRecipients.map(async (recipient) => {
if (recipient.sendStatus !== SendStatus.SENT) {
return;
}
const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000';
const template = createElement(RecipientRemovedFromDocumentTemplate, {
documentName: document.title,
inviterName: user.name || undefined,
assetBaseUrl,
});
await mailer.sendMail({
to: {
address: recipient.email,
name: recipient.name,
},
from: {
name: FROM_NAME,
address: FROM_ADDRESS,
},
subject: 'You have been removed from a document',
html: render(template),
text: render(template, { plainText: true }),
});
}),
);
} }
// Filter out recipients that have been removed or have been updated. // Filter out recipients that have been removed or have been updated.
@ -284,3 +322,27 @@ export const setRecipientsForDocument = async ({
return [...filteredRecipients, ...persistedRecipients]; return [...filteredRecipients, ...persistedRecipients];
}; };
/**
* If you change this you MUST update the `hasRecipientBeenChanged` function.
*/
type RecipientData = {
id?: number | null;
email: string;
name: string;
role: RecipientRole;
signingOrder?: number | null;
actionAuth?: TRecipientActionAuthTypes | null;
};
const hasRecipientBeenChanged = (recipient: Recipient, newRecipientData: RecipientData) => {
const authOptions = ZRecipientAuthOptionsSchema.parse(recipient.authOptions);
return (
recipient.email !== newRecipientData.email ||
recipient.name !== newRecipientData.name ||
recipient.role !== newRecipientData.role ||
recipient.signingOrder !== newRecipientData.signingOrder ||
authOptions.actionAuth !== newRecipientData.actionAuth
);
};

View File

@ -82,7 +82,7 @@ msgstr "Weitere Option hinzufügen"
msgid "Add another value" msgid "Add another value"
msgstr "Weiteren Wert hinzufügen" msgstr "Weiteren Wert hinzufügen"
#: packages/ui/primitives/document-flow/add-signers.tsx:653 #: packages/ui/primitives/document-flow/add-signers.tsx:662
msgid "Add myself" msgid "Add myself"
msgstr "Mich selbst hinzufügen" msgstr "Mich selbst hinzufügen"
@ -94,7 +94,7 @@ msgstr "Mich hinzufügen"
msgid "Add Placeholder Recipient" msgid "Add Placeholder Recipient"
msgstr "Platzhalterempfänger hinzufügen" msgstr "Platzhalterempfänger hinzufügen"
#: packages/ui/primitives/document-flow/add-signers.tsx:642 #: packages/ui/primitives/document-flow/add-signers.tsx:651
msgid "Add Signer" msgid "Add Signer"
msgstr "Unterzeichner hinzufügen" msgstr "Unterzeichner hinzufügen"
@ -115,7 +115,7 @@ msgstr "Admin"
msgid "Advanced Options" msgid "Advanced Options"
msgstr "Erweiterte Optionen" msgstr "Erweiterte Optionen"
#: packages/ui/primitives/document-flow/add-fields.tsx:522 #: packages/ui/primitives/document-flow/add-fields.tsx:527
#: packages/ui/primitives/template-flow/add-template-fields.tsx:402 #: packages/ui/primitives/template-flow/add-template-fields.tsx:402
msgid "Advanced settings" msgid "Advanced settings"
msgstr "Erweiterte Einstellungen" msgstr "Erweiterte Einstellungen"
@ -153,10 +153,14 @@ msgstr "Blau"
msgid "Cancel" msgid "Cancel"
msgstr "Abbrechen" msgstr "Abbrechen"
#: packages/ui/primitives/document-flow/add-signers.tsx:194 #: packages/ui/primitives/document-flow/add-signers.tsx:193
msgid "Cannot remove signer" msgid "Cannot remove signer"
msgstr "Unterzeichner kann nicht entfernt werden" msgstr "Unterzeichner kann nicht entfernt werden"
#: packages/ui/primitives/document-flow/add-signers.tsx:221
#~ msgid "Cannot update signer because they have already signed a field"
#~ msgstr ""
#: packages/lib/constants/recipient-roles.ts:17 #: packages/lib/constants/recipient-roles.ts:17
msgid "Cc" msgid "Cc"
msgstr "Cc" msgstr "Cc"
@ -174,7 +178,7 @@ msgstr "CC'd"
msgid "Character Limit" msgid "Character Limit"
msgstr "Zeichenbeschränkung" msgstr "Zeichenbeschränkung"
#: packages/ui/primitives/document-flow/add-fields.tsx:944 #: packages/ui/primitives/document-flow/add-fields.tsx:950
#: packages/ui/primitives/template-flow/add-template-fields.tsx:788 #: packages/ui/primitives/template-flow/add-template-fields.tsx:788
msgid "Checkbox" msgid "Checkbox"
msgstr "Checkbox" msgstr "Checkbox"
@ -203,7 +207,7 @@ msgstr "Schließen"
msgid "Configure Direct Recipient" msgid "Configure Direct Recipient"
msgstr "Direkten Empfänger konfigurieren" msgstr "Direkten Empfänger konfigurieren"
#: packages/ui/primitives/document-flow/add-fields.tsx:523 #: packages/ui/primitives/document-flow/add-fields.tsx:528
#: packages/ui/primitives/template-flow/add-template-fields.tsx:403 #: packages/ui/primitives/template-flow/add-template-fields.tsx:403
msgid "Configure the {0} field" msgid "Configure the {0} field"
msgstr "Konfigurieren Sie das Feld {0}" msgstr "Konfigurieren Sie das Feld {0}"
@ -220,7 +224,7 @@ msgstr "In die Zwischenablage kopiert"
msgid "Custom Text" msgid "Custom Text"
msgstr "Benutzerdefinierter Text" msgstr "Benutzerdefinierter Text"
#: packages/ui/primitives/document-flow/add-fields.tsx:840 #: packages/ui/primitives/document-flow/add-fields.tsx:846
#: packages/ui/primitives/template-flow/add-template-fields.tsx:684 #: packages/ui/primitives/template-flow/add-template-fields.tsx:684
msgid "Date" msgid "Date"
msgstr "Datum" msgstr "Datum"
@ -252,7 +256,7 @@ msgstr "Herunterladen"
msgid "Drag & drop your PDF here." msgid "Drag & drop your PDF here."
msgstr "Ziehen Sie Ihr PDF hierher." msgstr "Ziehen Sie Ihr PDF hierher."
#: packages/ui/primitives/document-flow/add-fields.tsx:970 #: packages/ui/primitives/document-flow/add-fields.tsx:976
#: packages/ui/primitives/template-flow/add-template-fields.tsx:814 #: packages/ui/primitives/template-flow/add-template-fields.tsx:814
msgid "Dropdown" msgid "Dropdown"
msgstr "Dropdown" msgstr "Dropdown"
@ -261,9 +265,9 @@ msgstr "Dropdown"
msgid "Dropdown options" msgid "Dropdown options"
msgstr "Dropdown-Optionen" msgstr "Dropdown-Optionen"
#: packages/ui/primitives/document-flow/add-fields.tsx:788 #: packages/ui/primitives/document-flow/add-fields.tsx:794
#: packages/ui/primitives/document-flow/add-signature.tsx:272 #: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:491 #: packages/ui/primitives/document-flow/add-signers.tsx:500
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632 #: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470
@ -278,7 +282,7 @@ msgstr "E-Mail-Optionen"
msgid "Enable Direct Link Signing" msgid "Enable Direct Link Signing"
msgstr "Direktlink-Signierung aktivieren" msgstr "Direktlink-Signierung aktivieren"
#: packages/ui/primitives/document-flow/add-signers.tsx:392 #: packages/ui/primitives/document-flow/add-signers.tsx:401
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362
msgid "Enable signing order" msgid "Enable signing order"
msgstr "Aktiviere die Signaturreihenfolge" msgstr "Aktiviere die Signaturreihenfolge"
@ -380,10 +384,10 @@ msgstr "Nachricht <0>(Optional)</0>"
msgid "Min" msgid "Min"
msgstr "Min" msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:814 #: packages/ui/primitives/document-flow/add-fields.tsx:820
#: packages/ui/primitives/document-flow/add-signature.tsx:298 #: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:526 #: packages/ui/primitives/document-flow/add-signers.tsx:535
#: packages/ui/primitives/document-flow/add-signers.tsx:532 #: packages/ui/primitives/document-flow/add-signers.tsx:541
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658 #: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504
@ -402,12 +406,12 @@ msgstr "Muss unterzeichnen"
msgid "Needs to view" msgid "Needs to view"
msgstr "Muss sehen" msgstr "Muss sehen"
#: packages/ui/primitives/document-flow/add-fields.tsx:625 #: packages/ui/primitives/document-flow/add-fields.tsx:631
#: packages/ui/primitives/template-flow/add-template-fields.tsx:497 #: packages/ui/primitives/template-flow/add-template-fields.tsx:497
msgid "No recipient matching this description was found." msgid "No recipient matching this description was found."
msgstr "Kein passender Empfänger mit dieser Beschreibung gefunden." msgstr "Kein passender Empfänger mit dieser Beschreibung gefunden."
#: packages/ui/primitives/document-flow/add-fields.tsx:641 #: packages/ui/primitives/document-flow/add-fields.tsx:647
#: packages/ui/primitives/template-flow/add-template-fields.tsx:513 #: packages/ui/primitives/template-flow/add-template-fields.tsx:513
msgid "No recipients with this role" msgid "No recipients with this role"
msgstr "Keine Empfänger mit dieser Rolle" msgstr "Keine Empfänger mit dieser Rolle"
@ -432,7 +436,7 @@ msgstr "Kein Unterschriftsfeld gefunden"
msgid "No value found." msgid "No value found."
msgstr "Kein Wert gefunden." msgstr "Kein Wert gefunden."
#: packages/ui/primitives/document-flow/add-fields.tsx:892 #: packages/ui/primitives/document-flow/add-fields.tsx:898
#: packages/ui/primitives/template-flow/add-template-fields.tsx:736 #: packages/ui/primitives/template-flow/add-template-fields.tsx:736
msgid "Number" msgid "Number"
msgstr "Nummer" msgstr "Nummer"
@ -467,7 +471,7 @@ msgstr "Wählen Sie eine Zahl"
msgid "Placeholder" msgid "Placeholder"
msgstr "Platzhalter" msgstr "Platzhalter"
#: packages/ui/primitives/document-flow/add-fields.tsx:918 #: packages/ui/primitives/document-flow/add-fields.tsx:924
#: packages/ui/primitives/template-flow/add-template-fields.tsx:762 #: packages/ui/primitives/template-flow/add-template-fields.tsx:762
msgid "Radio" msgid "Radio"
msgstr "Radio" msgstr "Radio"
@ -503,7 +507,7 @@ msgstr "Rot"
msgid "Redirect URL" msgid "Redirect URL"
msgstr "Weiterleitungs-URL" msgstr "Weiterleitungs-URL"
#: packages/ui/primitives/document-flow/add-fields.tsx:1008 #: packages/ui/primitives/document-flow/add-fields.tsx:1027
msgid "Remove" msgid "Remove"
msgstr "Entfernen" msgstr "Entfernen"
@ -565,7 +569,7 @@ msgstr "Unterschriftenkarte teilen"
msgid "Share the Link" msgid "Share the Link"
msgstr "Link teilen" msgstr "Link teilen"
#: packages/ui/primitives/document-flow/add-signers.tsx:671 #: packages/ui/primitives/document-flow/add-signers.tsx:680
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655
msgid "Show advanced settings" msgid "Show advanced settings"
msgstr "Erweiterte Einstellungen anzeigen" msgstr "Erweiterte Einstellungen anzeigen"
@ -574,7 +578,7 @@ msgstr "Erweiterte Einstellungen anzeigen"
msgid "Sign" msgid "Sign"
msgstr "Unterschreiben" msgstr "Unterschreiben"
#: packages/ui/primitives/document-flow/add-fields.tsx:736 #: packages/ui/primitives/document-flow/add-fields.tsx:742
#: packages/ui/primitives/document-flow/add-signature.tsx:323 #: packages/ui/primitives/document-flow/add-signature.tsx:323
#: packages/ui/primitives/document-flow/field-icon.tsx:52 #: packages/ui/primitives/document-flow/field-icon.tsx:52
#: packages/ui/primitives/template-flow/add-template-fields.tsx:580 #: packages/ui/primitives/template-flow/add-template-fields.tsx:580
@ -622,7 +626,7 @@ msgstr "Einreichen"
msgid "Template title" msgid "Template title"
msgstr "Vorlagentitel" msgstr "Vorlagentitel"
#: packages/ui/primitives/document-flow/add-fields.tsx:866 #: packages/ui/primitives/document-flow/add-fields.tsx:872
#: packages/ui/primitives/template-flow/add-template-fields.tsx:710 #: packages/ui/primitives/template-flow/add-template-fields.tsx:710
msgid "Text" msgid "Text"
msgstr "Text" msgstr "Text"
@ -683,7 +687,7 @@ msgstr "Der Name des Unterzeichners"
msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step." msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
msgstr "Dies kann überschrieben werden, indem die Authentifizierungsanforderungen im nächsten Schritt direkt für jeden Empfänger festgelegt werden." msgstr "Dies kann überschrieben werden, indem die Authentifizierungsanforderungen im nächsten Schritt direkt für jeden Empfänger festgelegt werden."
#: packages/ui/primitives/document-flow/add-fields.tsx:697 #: packages/ui/primitives/document-flow/add-fields.tsx:703
msgid "This document has already been sent to this recipient. You can no longer edit this recipient." msgid "This document has already been sent to this recipient. You can no longer edit this recipient."
msgstr "Dieses Dokument wurde bereits an diesen Empfänger gesendet. Sie können diesen Empfänger nicht mehr bearbeiten." msgstr "Dieses Dokument wurde bereits an diesen Empfänger gesendet. Sie können diesen Empfänger nicht mehr bearbeiten."
@ -695,9 +699,17 @@ msgstr "Dieses Dokument ist durch ein Passwort geschützt. Bitte geben Sie das P
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them." msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
msgstr "Dieses Feld kann nicht geändert oder gelöscht werden. Wenn Sie den direkten Link dieser Vorlage teilen oder zu Ihrem öffentlichen Profil hinzufügen, kann jeder, der darauf zugreift, seinen Namen und seine E-Mail-Adresse eingeben und die ihm zugewiesenen Felder ausfüllen." msgstr "Dieses Feld kann nicht geändert oder gelöscht werden. Wenn Sie den direkten Link dieser Vorlage teilen oder zu Ihrem öffentlichen Profil hinzufügen, kann jeder, der darauf zugreift, seinen Namen und seine E-Mail-Adresse eingeben und die ihm zugewiesenen Felder ausfüllen."
#: packages/ui/primitives/document-flow/add-fields.tsx:1007
msgid "This recipient can no longer be modified as they have signed a field, or completed the document."
msgstr ""
#: packages/ui/primitives/document-flow/add-signers.tsx:195 #: packages/ui/primitives/document-flow/add-signers.tsx:195
msgid "This signer has already received the document." #~ msgid "This signer has already received the document."
msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten." #~ msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
#: packages/ui/primitives/document-flow/add-signers.tsx:194
msgid "This signer has already signed the document."
msgstr ""
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48 #: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings." msgid "This will override any global settings."
@ -712,7 +724,7 @@ msgstr "Zeitzone"
msgid "Title" msgid "Title"
msgstr "Titel" msgstr "Titel"
#: packages/ui/primitives/document-flow/add-fields.tsx:983 #: packages/ui/primitives/document-flow/add-fields.tsx:990
#: packages/ui/primitives/template-flow/add-template-fields.tsx:828 #: packages/ui/primitives/template-flow/add-template-fields.tsx:828
msgid "To proceed further, please set at least one value for the {0} field." msgid "To proceed further, please set at least one value for the {0} field."
msgstr "Um fortzufahren, legen Sie bitte mindestens einen Wert für das Feld {0} fest." msgstr "Um fortzufahren, legen Sie bitte mindestens einen Wert für das Feld {0} fest."

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -77,7 +77,7 @@ msgstr "Add another option"
msgid "Add another value" msgid "Add another value"
msgstr "Add another value" msgstr "Add another value"
#: packages/ui/primitives/document-flow/add-signers.tsx:653 #: packages/ui/primitives/document-flow/add-signers.tsx:662
msgid "Add myself" msgid "Add myself"
msgstr "Add myself" msgstr "Add myself"
@ -89,7 +89,7 @@ msgstr "Add Myself"
msgid "Add Placeholder Recipient" msgid "Add Placeholder Recipient"
msgstr "Add Placeholder Recipient" msgstr "Add Placeholder Recipient"
#: packages/ui/primitives/document-flow/add-signers.tsx:642 #: packages/ui/primitives/document-flow/add-signers.tsx:651
msgid "Add Signer" msgid "Add Signer"
msgstr "Add Signer" msgstr "Add Signer"
@ -110,7 +110,7 @@ msgstr "Admin"
msgid "Advanced Options" msgid "Advanced Options"
msgstr "Advanced Options" msgstr "Advanced Options"
#: packages/ui/primitives/document-flow/add-fields.tsx:522 #: packages/ui/primitives/document-flow/add-fields.tsx:527
#: packages/ui/primitives/template-flow/add-template-fields.tsx:402 #: packages/ui/primitives/template-flow/add-template-fields.tsx:402
msgid "Advanced settings" msgid "Advanced settings"
msgstr "Advanced settings" msgstr "Advanced settings"
@ -148,10 +148,14 @@ msgstr "Blue"
msgid "Cancel" msgid "Cancel"
msgstr "Cancel" msgstr "Cancel"
#: packages/ui/primitives/document-flow/add-signers.tsx:194 #: packages/ui/primitives/document-flow/add-signers.tsx:193
msgid "Cannot remove signer" msgid "Cannot remove signer"
msgstr "Cannot remove signer" msgstr "Cannot remove signer"
#: packages/ui/primitives/document-flow/add-signers.tsx:221
#~ msgid "Cannot update signer because they have already signed a field"
#~ msgstr "Cannot update signer because they have already signed a field"
#: packages/lib/constants/recipient-roles.ts:17 #: packages/lib/constants/recipient-roles.ts:17
msgid "Cc" msgid "Cc"
msgstr "Cc" msgstr "Cc"
@ -169,7 +173,7 @@ msgstr "CC'd"
msgid "Character Limit" msgid "Character Limit"
msgstr "Character Limit" msgstr "Character Limit"
#: packages/ui/primitives/document-flow/add-fields.tsx:944 #: packages/ui/primitives/document-flow/add-fields.tsx:950
#: packages/ui/primitives/template-flow/add-template-fields.tsx:788 #: packages/ui/primitives/template-flow/add-template-fields.tsx:788
msgid "Checkbox" msgid "Checkbox"
msgstr "Checkbox" msgstr "Checkbox"
@ -198,7 +202,7 @@ msgstr "Close"
msgid "Configure Direct Recipient" msgid "Configure Direct Recipient"
msgstr "Configure Direct Recipient" msgstr "Configure Direct Recipient"
#: packages/ui/primitives/document-flow/add-fields.tsx:523 #: packages/ui/primitives/document-flow/add-fields.tsx:528
#: packages/ui/primitives/template-flow/add-template-fields.tsx:403 #: packages/ui/primitives/template-flow/add-template-fields.tsx:403
msgid "Configure the {0} field" msgid "Configure the {0} field"
msgstr "Configure the {0} field" msgstr "Configure the {0} field"
@ -215,7 +219,7 @@ msgstr "Copied to clipboard"
msgid "Custom Text" msgid "Custom Text"
msgstr "Custom Text" msgstr "Custom Text"
#: packages/ui/primitives/document-flow/add-fields.tsx:840 #: packages/ui/primitives/document-flow/add-fields.tsx:846
#: packages/ui/primitives/template-flow/add-template-fields.tsx:684 #: packages/ui/primitives/template-flow/add-template-fields.tsx:684
msgid "Date" msgid "Date"
msgstr "Date" msgstr "Date"
@ -247,7 +251,7 @@ msgstr "Download"
msgid "Drag & drop your PDF here." msgid "Drag & drop your PDF here."
msgstr "Drag & drop your PDF here." msgstr "Drag & drop your PDF here."
#: packages/ui/primitives/document-flow/add-fields.tsx:970 #: packages/ui/primitives/document-flow/add-fields.tsx:976
#: packages/ui/primitives/template-flow/add-template-fields.tsx:814 #: packages/ui/primitives/template-flow/add-template-fields.tsx:814
msgid "Dropdown" msgid "Dropdown"
msgstr "Dropdown" msgstr "Dropdown"
@ -256,9 +260,9 @@ msgstr "Dropdown"
msgid "Dropdown options" msgid "Dropdown options"
msgstr "Dropdown options" msgstr "Dropdown options"
#: packages/ui/primitives/document-flow/add-fields.tsx:788 #: packages/ui/primitives/document-flow/add-fields.tsx:794
#: packages/ui/primitives/document-flow/add-signature.tsx:272 #: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:491 #: packages/ui/primitives/document-flow/add-signers.tsx:500
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632 #: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470
@ -273,7 +277,7 @@ msgstr "Email Options"
msgid "Enable Direct Link Signing" msgid "Enable Direct Link Signing"
msgstr "Enable Direct Link Signing" msgstr "Enable Direct Link Signing"
#: packages/ui/primitives/document-flow/add-signers.tsx:392 #: packages/ui/primitives/document-flow/add-signers.tsx:401
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362
msgid "Enable signing order" msgid "Enable signing order"
msgstr "Enable signing order" msgstr "Enable signing order"
@ -375,10 +379,10 @@ msgstr "Message <0>(Optional)</0>"
msgid "Min" msgid "Min"
msgstr "Min" msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:814 #: packages/ui/primitives/document-flow/add-fields.tsx:820
#: packages/ui/primitives/document-flow/add-signature.tsx:298 #: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:526 #: packages/ui/primitives/document-flow/add-signers.tsx:535
#: packages/ui/primitives/document-flow/add-signers.tsx:532 #: packages/ui/primitives/document-flow/add-signers.tsx:541
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658 #: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504
@ -397,12 +401,12 @@ msgstr "Needs to sign"
msgid "Needs to view" msgid "Needs to view"
msgstr "Needs to view" msgstr "Needs to view"
#: packages/ui/primitives/document-flow/add-fields.tsx:625 #: packages/ui/primitives/document-flow/add-fields.tsx:631
#: packages/ui/primitives/template-flow/add-template-fields.tsx:497 #: packages/ui/primitives/template-flow/add-template-fields.tsx:497
msgid "No recipient matching this description was found." msgid "No recipient matching this description was found."
msgstr "No recipient matching this description was found." msgstr "No recipient matching this description was found."
#: packages/ui/primitives/document-flow/add-fields.tsx:641 #: packages/ui/primitives/document-flow/add-fields.tsx:647
#: packages/ui/primitives/template-flow/add-template-fields.tsx:513 #: packages/ui/primitives/template-flow/add-template-fields.tsx:513
msgid "No recipients with this role" msgid "No recipients with this role"
msgstr "No recipients with this role" msgstr "No recipients with this role"
@ -427,7 +431,7 @@ msgstr "No signature field found"
msgid "No value found." msgid "No value found."
msgstr "No value found." msgstr "No value found."
#: packages/ui/primitives/document-flow/add-fields.tsx:892 #: packages/ui/primitives/document-flow/add-fields.tsx:898
#: packages/ui/primitives/template-flow/add-template-fields.tsx:736 #: packages/ui/primitives/template-flow/add-template-fields.tsx:736
msgid "Number" msgid "Number"
msgstr "Number" msgstr "Number"
@ -462,7 +466,7 @@ msgstr "Pick a number"
msgid "Placeholder" msgid "Placeholder"
msgstr "Placeholder" msgstr "Placeholder"
#: packages/ui/primitives/document-flow/add-fields.tsx:918 #: packages/ui/primitives/document-flow/add-fields.tsx:924
#: packages/ui/primitives/template-flow/add-template-fields.tsx:762 #: packages/ui/primitives/template-flow/add-template-fields.tsx:762
msgid "Radio" msgid "Radio"
msgstr "Radio" msgstr "Radio"
@ -498,7 +502,7 @@ msgstr "Red"
msgid "Redirect URL" msgid "Redirect URL"
msgstr "Redirect URL" msgstr "Redirect URL"
#: packages/ui/primitives/document-flow/add-fields.tsx:1008 #: packages/ui/primitives/document-flow/add-fields.tsx:1027
msgid "Remove" msgid "Remove"
msgstr "Remove" msgstr "Remove"
@ -560,7 +564,7 @@ msgstr "Share Signature Card"
msgid "Share the Link" msgid "Share the Link"
msgstr "Share the Link" msgstr "Share the Link"
#: packages/ui/primitives/document-flow/add-signers.tsx:671 #: packages/ui/primitives/document-flow/add-signers.tsx:680
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655
msgid "Show advanced settings" msgid "Show advanced settings"
msgstr "Show advanced settings" msgstr "Show advanced settings"
@ -569,7 +573,7 @@ msgstr "Show advanced settings"
msgid "Sign" msgid "Sign"
msgstr "Sign" msgstr "Sign"
#: packages/ui/primitives/document-flow/add-fields.tsx:736 #: packages/ui/primitives/document-flow/add-fields.tsx:742
#: packages/ui/primitives/document-flow/add-signature.tsx:323 #: packages/ui/primitives/document-flow/add-signature.tsx:323
#: packages/ui/primitives/document-flow/field-icon.tsx:52 #: packages/ui/primitives/document-flow/field-icon.tsx:52
#: packages/ui/primitives/template-flow/add-template-fields.tsx:580 #: packages/ui/primitives/template-flow/add-template-fields.tsx:580
@ -617,7 +621,7 @@ msgstr "Submit"
msgid "Template title" msgid "Template title"
msgstr "Template title" msgstr "Template title"
#: packages/ui/primitives/document-flow/add-fields.tsx:866 #: packages/ui/primitives/document-flow/add-fields.tsx:872
#: packages/ui/primitives/template-flow/add-template-fields.tsx:710 #: packages/ui/primitives/template-flow/add-template-fields.tsx:710
msgid "Text" msgid "Text"
msgstr "Text" msgstr "Text"
@ -678,7 +682,7 @@ msgstr "The signer's name"
msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step." msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
msgstr "This can be overriden by setting the authentication requirements directly on each recipient in the next step." msgstr "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
#: packages/ui/primitives/document-flow/add-fields.tsx:697 #: packages/ui/primitives/document-flow/add-fields.tsx:703
msgid "This document has already been sent to this recipient. You can no longer edit this recipient." msgid "This document has already been sent to this recipient. You can no longer edit this recipient."
msgstr "This document has already been sent to this recipient. You can no longer edit this recipient." msgstr "This document has already been sent to this recipient. You can no longer edit this recipient."
@ -690,9 +694,17 @@ msgstr "This document is password protected. Please enter the password to view t
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them." msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
msgstr "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them." msgstr "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
#: packages/ui/primitives/document-flow/add-signers.tsx:195 #: packages/ui/primitives/document-flow/add-fields.tsx:1007
msgid "This signer has already received the document." msgid "This recipient can no longer be modified as they have signed a field, or completed the document."
msgstr "This signer has already received the document." msgstr "This recipient can no longer be modified as they have signed a field, or completed the document."
#: packages/ui/primitives/document-flow/add-signers.tsx:165
#~ msgid "This signer has already received the document."
#~ msgstr "This signer has already received the document."
#: packages/ui/primitives/document-flow/add-signers.tsx:194
msgid "This signer has already signed the document."
msgstr "This signer has already signed the document."
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48 #: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings." msgid "This will override any global settings."
@ -707,7 +719,7 @@ msgstr "Time Zone"
msgid "Title" msgid "Title"
msgstr "Title" msgstr "Title"
#: packages/ui/primitives/document-flow/add-fields.tsx:983 #: packages/ui/primitives/document-flow/add-fields.tsx:990
#: packages/ui/primitives/template-flow/add-template-fields.tsx:828 #: packages/ui/primitives/template-flow/add-template-fields.tsx:828
msgid "To proceed further, please set at least one value for the {0} field." msgid "To proceed further, please set at least one value for the {0} field."
msgstr "To proceed further, please set at least one value for the {0} field." msgstr "To proceed further, please set at least one value for the {0} field."

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -82,7 +82,7 @@ msgstr "Ajouter une autre option"
msgid "Add another value" msgid "Add another value"
msgstr "Ajouter une autre valeur" msgstr "Ajouter une autre valeur"
#: packages/ui/primitives/document-flow/add-signers.tsx:653 #: packages/ui/primitives/document-flow/add-signers.tsx:662
msgid "Add myself" msgid "Add myself"
msgstr "Ajoutez-moi" msgstr "Ajoutez-moi"
@ -94,7 +94,7 @@ msgstr "Ajoutez-moi"
msgid "Add Placeholder Recipient" msgid "Add Placeholder Recipient"
msgstr "Ajouter un destinataire de substitution" msgstr "Ajouter un destinataire de substitution"
#: packages/ui/primitives/document-flow/add-signers.tsx:642 #: packages/ui/primitives/document-flow/add-signers.tsx:651
msgid "Add Signer" msgid "Add Signer"
msgstr "Ajouter un signataire" msgstr "Ajouter un signataire"
@ -115,7 +115,7 @@ msgstr "Administrateur"
msgid "Advanced Options" msgid "Advanced Options"
msgstr "Options avancées" msgstr "Options avancées"
#: packages/ui/primitives/document-flow/add-fields.tsx:522 #: packages/ui/primitives/document-flow/add-fields.tsx:527
#: packages/ui/primitives/template-flow/add-template-fields.tsx:402 #: packages/ui/primitives/template-flow/add-template-fields.tsx:402
msgid "Advanced settings" msgid "Advanced settings"
msgstr "Paramètres avancés" msgstr "Paramètres avancés"
@ -153,7 +153,7 @@ msgstr "Bleu"
msgid "Cancel" msgid "Cancel"
msgstr "Annuler" msgstr "Annuler"
#: packages/ui/primitives/document-flow/add-signers.tsx:194 #: packages/ui/primitives/document-flow/add-signers.tsx:193
msgid "Cannot remove signer" msgid "Cannot remove signer"
msgstr "Impossible de retirer le signataire" msgstr "Impossible de retirer le signataire"
@ -174,7 +174,7 @@ msgstr "CC'd"
msgid "Character Limit" msgid "Character Limit"
msgstr "Limite de caractères" msgstr "Limite de caractères"
#: packages/ui/primitives/document-flow/add-fields.tsx:944 #: packages/ui/primitives/document-flow/add-fields.tsx:950
#: packages/ui/primitives/template-flow/add-template-fields.tsx:788 #: packages/ui/primitives/template-flow/add-template-fields.tsx:788
msgid "Checkbox" msgid "Checkbox"
msgstr "Case à cocher" msgstr "Case à cocher"
@ -203,7 +203,7 @@ msgstr "Fermer"
msgid "Configure Direct Recipient" msgid "Configure Direct Recipient"
msgstr "Configurer le destinataire direct" msgstr "Configurer le destinataire direct"
#: packages/ui/primitives/document-flow/add-fields.tsx:523 #: packages/ui/primitives/document-flow/add-fields.tsx:528
#: packages/ui/primitives/template-flow/add-template-fields.tsx:403 #: packages/ui/primitives/template-flow/add-template-fields.tsx:403
msgid "Configure the {0} field" msgid "Configure the {0} field"
msgstr "Configurer le champ {0}" msgstr "Configurer le champ {0}"
@ -220,7 +220,7 @@ msgstr "Copié dans le presse-papiers"
msgid "Custom Text" msgid "Custom Text"
msgstr "Texte personnalisé" msgstr "Texte personnalisé"
#: packages/ui/primitives/document-flow/add-fields.tsx:840 #: packages/ui/primitives/document-flow/add-fields.tsx:846
#: packages/ui/primitives/template-flow/add-template-fields.tsx:684 #: packages/ui/primitives/template-flow/add-template-fields.tsx:684
msgid "Date" msgid "Date"
msgstr "Date" msgstr "Date"
@ -252,7 +252,7 @@ msgstr "Télécharger"
msgid "Drag & drop your PDF here." msgid "Drag & drop your PDF here."
msgstr "Faites glisser et déposez votre PDF ici." msgstr "Faites glisser et déposez votre PDF ici."
#: packages/ui/primitives/document-flow/add-fields.tsx:970 #: packages/ui/primitives/document-flow/add-fields.tsx:976
#: packages/ui/primitives/template-flow/add-template-fields.tsx:814 #: packages/ui/primitives/template-flow/add-template-fields.tsx:814
msgid "Dropdown" msgid "Dropdown"
msgstr "Liste déroulante" msgstr "Liste déroulante"
@ -261,9 +261,9 @@ msgstr "Liste déroulante"
msgid "Dropdown options" msgid "Dropdown options"
msgstr "Options de liste déroulante" msgstr "Options de liste déroulante"
#: packages/ui/primitives/document-flow/add-fields.tsx:788 #: packages/ui/primitives/document-flow/add-fields.tsx:794
#: packages/ui/primitives/document-flow/add-signature.tsx:272 #: packages/ui/primitives/document-flow/add-signature.tsx:272
#: packages/ui/primitives/document-flow/add-signers.tsx:491 #: packages/ui/primitives/document-flow/add-signers.tsx:500
#: packages/ui/primitives/template-flow/add-template-fields.tsx:632 #: packages/ui/primitives/template-flow/add-template-fields.tsx:632
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470
@ -278,7 +278,7 @@ msgstr "Options d'email"
msgid "Enable Direct Link Signing" msgid "Enable Direct Link Signing"
msgstr "Activer la signature de lien direct" msgstr "Activer la signature de lien direct"
#: packages/ui/primitives/document-flow/add-signers.tsx:392 #: packages/ui/primitives/document-flow/add-signers.tsx:401
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362
msgid "Enable signing order" msgid "Enable signing order"
msgstr "Activer l'ordre de signature" msgstr "Activer l'ordre de signature"
@ -380,10 +380,10 @@ msgstr "Message <0>(Optionnel)</0>"
msgid "Min" msgid "Min"
msgstr "Min" msgstr "Min"
#: packages/ui/primitives/document-flow/add-fields.tsx:814 #: packages/ui/primitives/document-flow/add-fields.tsx:820
#: packages/ui/primitives/document-flow/add-signature.tsx:298 #: packages/ui/primitives/document-flow/add-signature.tsx:298
#: packages/ui/primitives/document-flow/add-signers.tsx:526 #: packages/ui/primitives/document-flow/add-signers.tsx:535
#: packages/ui/primitives/document-flow/add-signers.tsx:532 #: packages/ui/primitives/document-flow/add-signers.tsx:541
#: packages/ui/primitives/template-flow/add-template-fields.tsx:658 #: packages/ui/primitives/template-flow/add-template-fields.tsx:658
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504
@ -402,12 +402,12 @@ msgstr "Nécessite une signature"
msgid "Needs to view" msgid "Needs to view"
msgstr "Nécessite une visualisation" msgstr "Nécessite une visualisation"
#: packages/ui/primitives/document-flow/add-fields.tsx:625 #: packages/ui/primitives/document-flow/add-fields.tsx:631
#: packages/ui/primitives/template-flow/add-template-fields.tsx:497 #: packages/ui/primitives/template-flow/add-template-fields.tsx:497
msgid "No recipient matching this description was found." msgid "No recipient matching this description was found."
msgstr "Aucun destinataire correspondant à cette description n'a été trouvé." msgstr "Aucun destinataire correspondant à cette description n'a été trouvé."
#: packages/ui/primitives/document-flow/add-fields.tsx:641 #: packages/ui/primitives/document-flow/add-fields.tsx:647
#: packages/ui/primitives/template-flow/add-template-fields.tsx:513 #: packages/ui/primitives/template-flow/add-template-fields.tsx:513
msgid "No recipients with this role" msgid "No recipients with this role"
msgstr "Aucun destinataire avec ce rôle" msgstr "Aucun destinataire avec ce rôle"
@ -432,7 +432,7 @@ msgstr "Aucun champ de signature trouvé"
msgid "No value found." msgid "No value found."
msgstr "Aucune valeur trouvée." msgstr "Aucune valeur trouvée."
#: packages/ui/primitives/document-flow/add-fields.tsx:892 #: packages/ui/primitives/document-flow/add-fields.tsx:898
#: packages/ui/primitives/template-flow/add-template-fields.tsx:736 #: packages/ui/primitives/template-flow/add-template-fields.tsx:736
msgid "Number" msgid "Number"
msgstr "Numéro" msgstr "Numéro"
@ -467,7 +467,7 @@ msgstr "Choisissez un numéro"
msgid "Placeholder" msgid "Placeholder"
msgstr "Espace réservé" msgstr "Espace réservé"
#: packages/ui/primitives/document-flow/add-fields.tsx:918 #: packages/ui/primitives/document-flow/add-fields.tsx:924
#: packages/ui/primitives/template-flow/add-template-fields.tsx:762 #: packages/ui/primitives/template-flow/add-template-fields.tsx:762
msgid "Radio" msgid "Radio"
msgstr "Radio" msgstr "Radio"
@ -503,7 +503,7 @@ msgstr "Rouge"
msgid "Redirect URL" msgid "Redirect URL"
msgstr "URL de redirection" msgstr "URL de redirection"
#: packages/ui/primitives/document-flow/add-fields.tsx:1008 #: packages/ui/primitives/document-flow/add-fields.tsx:1027
msgid "Remove" msgid "Remove"
msgstr "Retirer" msgstr "Retirer"
@ -565,7 +565,7 @@ msgstr "Partager la carte de signature"
msgid "Share the Link" msgid "Share the Link"
msgstr "Partager le lien" msgstr "Partager le lien"
#: packages/ui/primitives/document-flow/add-signers.tsx:671 #: packages/ui/primitives/document-flow/add-signers.tsx:680
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655 #: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655
msgid "Show advanced settings" msgid "Show advanced settings"
msgstr "Afficher les paramètres avancés" msgstr "Afficher les paramètres avancés"
@ -574,7 +574,7 @@ msgstr "Afficher les paramètres avancés"
msgid "Sign" msgid "Sign"
msgstr "Signer" msgstr "Signer"
#: packages/ui/primitives/document-flow/add-fields.tsx:736 #: packages/ui/primitives/document-flow/add-fields.tsx:742
#: packages/ui/primitives/document-flow/add-signature.tsx:323 #: packages/ui/primitives/document-flow/add-signature.tsx:323
#: packages/ui/primitives/document-flow/field-icon.tsx:52 #: packages/ui/primitives/document-flow/field-icon.tsx:52
#: packages/ui/primitives/template-flow/add-template-fields.tsx:580 #: packages/ui/primitives/template-flow/add-template-fields.tsx:580
@ -622,7 +622,7 @@ msgstr "Soumettre"
msgid "Template title" msgid "Template title"
msgstr "Titre du modèle" msgstr "Titre du modèle"
#: packages/ui/primitives/document-flow/add-fields.tsx:866 #: packages/ui/primitives/document-flow/add-fields.tsx:872
#: packages/ui/primitives/template-flow/add-template-fields.tsx:710 #: packages/ui/primitives/template-flow/add-template-fields.tsx:710
msgid "Text" msgid "Text"
msgstr "Texte" msgstr "Texte"
@ -683,7 +683,7 @@ msgstr "Le nom du signataire"
msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step." msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
msgstr "Cela peut être remplacé par le paramétrage direct des exigences d'authentification pour chaque destinataire à l'étape suivante." msgstr "Cela peut être remplacé par le paramétrage direct des exigences d'authentification pour chaque destinataire à l'étape suivante."
#: packages/ui/primitives/document-flow/add-fields.tsx:697 #: packages/ui/primitives/document-flow/add-fields.tsx:703
msgid "This document has already been sent to this recipient. You can no longer edit this recipient." msgid "This document has already been sent to this recipient. You can no longer edit this recipient."
msgstr "Ce document a déjà été envoyé à ce destinataire. Vous ne pouvez plus modifier ce destinataire." msgstr "Ce document a déjà été envoyé à ce destinataire. Vous ne pouvez plus modifier ce destinataire."
@ -695,9 +695,17 @@ msgstr "Ce document est protégé par mot de passe. Veuillez entrer le mot de pa
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them." msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
msgstr "Ce champ ne peut pas être modifié ou supprimé. Lorsque vous partagez le lien direct de ce modèle ou l'ajoutez à votre profil public, toute personne qui y accède peut saisir son nom et son email, et remplir les champs qui lui sont attribués." msgstr "Ce champ ne peut pas être modifié ou supprimé. Lorsque vous partagez le lien direct de ce modèle ou l'ajoutez à votre profil public, toute personne qui y accède peut saisir son nom et son email, et remplir les champs qui lui sont attribués."
#: packages/ui/primitives/document-flow/add-fields.tsx:1007
msgid "This recipient can no longer be modified as they have signed a field, or completed the document."
msgstr ""
#: packages/ui/primitives/document-flow/add-signers.tsx:195 #: packages/ui/primitives/document-flow/add-signers.tsx:195
msgid "This signer has already received the document." #~ msgid "This signer has already received the document."
msgstr "Ce signataire a déjà reçu le document." #~ msgstr "Ce signataire a déjà reçu le document."
#: packages/ui/primitives/document-flow/add-signers.tsx:194
msgid "This signer has already signed the document."
msgstr ""
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48 #: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
msgid "This will override any global settings." msgid "This will override any global settings."
@ -712,7 +720,7 @@ msgstr "Fuseau horaire"
msgid "Title" msgid "Title"
msgstr "Titre" msgstr "Titre"
#: packages/ui/primitives/document-flow/add-fields.tsx:983 #: packages/ui/primitives/document-flow/add-fields.tsx:990
#: packages/ui/primitives/template-flow/add-template-fields.tsx:828 #: packages/ui/primitives/template-flow/add-template-fields.tsx:828
msgid "To proceed further, please set at least one value for the {0} field." msgid "To proceed further, please set at least one value for the {0} field."
msgstr "Pour continuer, veuillez définir au moins une valeur pour le champ {0}." msgstr "Pour continuer, veuillez définir au moins une valeur pour le champ {0}."

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,33 @@
import { type Field, type Recipient, RecipientRole, SigningStatus } from '@documenso/prisma/client';
/**
* Whether a recipient can be modified by the document owner.
*/
export const canRecipientBeModified = (recipient: Recipient, fields: Field[]) => {
// Deny if the recipient has already signed the document.
if (!recipient || recipient.signingStatus === SigningStatus.SIGNED) {
return false;
}
// Deny if the recipient has inserted any fields.
if (fields.some((field) => field.recipientId === recipient.id && field.inserted)) {
return false;
}
return true;
};
/**
* Whether a recipient can have their fields modified by the document owner.
*
* A recipient can their fields modified if all the conditions are met:
* - They are not a Viewer or CCer
* - They can be modified (canRecipientBeModified)
*/
export const canRecipientFieldsBeModified = (recipient: Recipient, fields: Field[]) => {
if (!canRecipientBeModified(recipient, fields)) {
return false;
}
return recipient.role !== RecipientRole.VIEWER && recipient.role !== RecipientRole.CC;
};

View File

@ -32,11 +32,16 @@ import {
ZFieldMetaSchema, ZFieldMetaSchema,
} from '@documenso/lib/types/field-meta'; } from '@documenso/lib/types/field-meta';
import { nanoid } from '@documenso/lib/universal/id'; import { nanoid } from '@documenso/lib/universal/id';
import {
canRecipientBeModified,
canRecipientFieldsBeModified,
} from '@documenso/lib/utils/recipients';
import type { Field, Recipient } from '@documenso/prisma/client'; import type { Field, Recipient } from '@documenso/prisma/client';
import { FieldType, RecipientRole, SendStatus } from '@documenso/prisma/client'; import { FieldType, RecipientRole, SendStatus } from '@documenso/prisma/client';
import { getSignerColorStyles, useSignerColors } from '../../lib/signer-colors'; import { getSignerColorStyles, useSignerColors } from '../../lib/signer-colors';
import { cn } from '../../lib/utils'; import { cn } from '../../lib/utils';
import { Alert, AlertDescription } from '../alert';
import { Button } from '../button'; import { Button } from '../button';
import { Card, CardContent } from '../card'; import { Card, CardContent } from '../card';
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from '../command'; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from '../command';
@ -191,8 +196,6 @@ export const AddFieldsFormPartial = ({
selectedSignerIndex === -1 ? 0 : selectedSignerIndex, selectedSignerIndex === -1 ? 0 : selectedSignerIndex,
); );
const hasSelectedSignerBeenSent = selectedSigner?.sendStatus === SendStatus.SENT;
const filterFieldsWithEmptyValues = (fields: typeof localFields, fieldType: string) => const filterFieldsWithEmptyValues = (fields: typeof localFields, fieldType: string) =>
fields fields
.filter((field) => field.type === fieldType) .filter((field) => field.type === fieldType)
@ -225,11 +228,13 @@ export const AddFieldsFormPartial = ({
const hasErrors = const hasErrors =
emptyCheckboxFields.length > 0 || emptyRadioFields.length > 0 || emptySelectFields.length > 0; emptyCheckboxFields.length > 0 || emptyRadioFields.length > 0 || emptySelectFields.length > 0;
const isFieldsDisabled = const isFieldsDisabled = useMemo(() => {
!selectedSigner || if (!selectedSigner) {
hasSelectedSignerBeenSent || return true;
selectedSigner?.role === RecipientRole.VIEWER || }
selectedSigner?.role === RecipientRole.CC;
return !canRecipientFieldsBeModified(selectedSigner, fields);
}, [selectedSigner, fields]);
const [isFieldWithinBounds, setIsFieldWithinBounds] = useState(false); const [isFieldWithinBounds, setIsFieldWithinBounds] = useState(false);
const [coords, setCoords] = useState({ const [coords, setCoords] = useState({
@ -568,7 +573,8 @@ export const AddFieldsFormPartial = ({
recipientIndex={recipientIndex === -1 ? 0 : recipientIndex} recipientIndex={recipientIndex === -1 ? 0 : recipientIndex}
field={field} field={field}
disabled={ disabled={
selectedSigner?.email !== field.signerEmail || hasSelectedSignerBeenSent selectedSigner?.email !== field.signerEmail ||
!canRecipientBeModified(selectedSigner, fields)
} }
minHeight={fieldBounds.current.height} minHeight={fieldBounds.current.height}
minWidth={fieldBounds.current.width} minWidth={fieldBounds.current.width}
@ -976,6 +982,7 @@ export const AddFieldsFormPartial = ({
</div> </div>
</div> </div>
</DocumentFlowFormContainerContent> </DocumentFlowFormContainerContent>
{hasErrors && ( {hasErrors && (
<div className="mt-4"> <div className="mt-4">
<ul> <ul>
@ -993,6 +1000,18 @@ export const AddFieldsFormPartial = ({
</ul> </ul>
</div> </div>
)} )}
{selectedSigner && !canRecipientFieldsBeModified(selectedSigner, fields) && (
<Alert variant="warning">
<AlertDescription>
<Trans>
This recipient can no longer be modified as they have signed a field, or completed
the document.
</Trans>
</AlertDescription>
</Alert>
)}
<DocumentFlowFormContainerFooter> <DocumentFlowFormContainerFooter>
<DocumentFlowFormContainerStep step={currentStep} maxStep={totalSteps} /> <DocumentFlowFormContainerStep step={currentStep} maxStep={totalSteps} />

View File

@ -16,6 +16,7 @@ import { prop, sortBy } from 'remeda';
import { useLimits } from '@documenso/ee/server-only/limits/provider/client'; import { useLimits } from '@documenso/ee/server-only/limits/provider/client';
import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth'; import { ZRecipientAuthOptionsSchema } from '@documenso/lib/types/document-auth';
import { nanoid } from '@documenso/lib/universal/id'; import { nanoid } from '@documenso/lib/universal/id';
import { canRecipientBeModified as utilCanRecipientBeModified } from '@documenso/lib/utils/recipients';
import type { Field, Recipient } from '@documenso/prisma/client'; import type { Field, Recipient } from '@documenso/prisma/client';
import { DocumentSigningOrder, RecipientRole, SendStatus } from '@documenso/prisma/client'; import { DocumentSigningOrder, RecipientRole, SendStatus } from '@documenso/prisma/client';
import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out'; import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
@ -159,21 +160,19 @@ export const AddSignersFormPartial = ({
(recipient) => recipient.sendStatus === SendStatus.SENT, (recipient) => recipient.sendStatus === SendStatus.SENT,
); );
const hasBeenSentToRecipientId = useCallback( const canRecipientBeModified = (recipientId?: number) => {
(id?: number) => { if (recipientId === undefined) {
if (!id) { return true;
return false; }
}
return recipients.some( const recipient = recipients.find((recipient) => recipient.id === recipientId);
(recipient) =>
recipient.id === id && if (!recipient) {
recipient.sendStatus === SendStatus.SENT && return false;
recipient.role !== RecipientRole.CC, }
);
}, return utilCanRecipientBeModified(recipient, fields);
[recipients], };
);
const onAddSigner = () => { const onAddSigner = () => {
appendSigner({ appendSigner({
@ -189,10 +188,10 @@ export const AddSignersFormPartial = ({
const onRemoveSigner = (index: number) => { const onRemoveSigner = (index: number) => {
const signer = signers[index]; const signer = signers[index];
if (hasBeenSentToRecipientId(signer.nativeId)) { if (!canRecipientBeModified(signer.nativeId)) {
toast({ toast({
title: _(msg`Cannot remove signer`), title: _(msg`Cannot remove signer`),
description: _(msg`This signer has already received the document.`), description: _(msg`This signer has already signed the document.`),
variant: 'destructive', variant: 'destructive',
}); });
@ -235,7 +234,7 @@ export const AddSignersFormPartial = ({
const [reorderedSigner] = items.splice(result.source.index, 1); const [reorderedSigner] = items.splice(result.source.index, 1);
let insertIndex = result.destination.index; let insertIndex = result.destination.index;
while (insertIndex < items.length && hasBeenSentToRecipientId(items[insertIndex].nativeId)) { while (insertIndex < items.length && !canRecipientBeModified(items[insertIndex].nativeId)) {
insertIndex++; insertIndex++;
} }
@ -243,7 +242,7 @@ export const AddSignersFormPartial = ({
const updatedSigners = items.map((item, index) => ({ const updatedSigners = items.map((item, index) => ({
...item, ...item,
signingOrder: hasBeenSentToRecipientId(item.nativeId) ? item.signingOrder : index + 1, signingOrder: !canRecipientBeModified(item.nativeId) ? item.signingOrder : index + 1,
})); }));
updatedSigners.forEach((item, index) => { updatedSigners.forEach((item, index) => {
@ -270,7 +269,7 @@ export const AddSignersFormPartial = ({
await form.trigger('signers'); await form.trigger('signers');
}, },
[form, hasBeenSentToRecipientId, watchedSigners], [form, canRecipientBeModified, watchedSigners],
); );
const triggerDragAndDrop = useCallback( const triggerDragAndDrop = useCallback(
@ -315,9 +314,19 @@ export const AddSignersFormPartial = ({
if (index === oldIndex) { if (index === oldIndex) {
return { ...signer, signingOrder: newIndex + 1 }; return { ...signer, signingOrder: newIndex + 1 };
} else if (index >= newIndex && index < oldIndex) { } else if (index >= newIndex && index < oldIndex) {
return { ...signer, signingOrder: (signer.signingOrder ?? index + 1) + 1 }; return {
...signer,
signingOrder: !canRecipientBeModified(signer.nativeId)
? signer.signingOrder
: (signer.signingOrder ?? index + 1) + 1,
};
} else if (index <= newIndex && index > oldIndex) { } else if (index <= newIndex && index > oldIndex) {
return { ...signer, signingOrder: Math.max(1, (signer.signingOrder ?? index + 1) - 1) }; return {
...signer,
signingOrder: !canRecipientBeModified(signer.nativeId)
? signer.signingOrder
: Math.max(1, (signer.signingOrder ?? index + 1) - 1),
};
} }
return signer; return signer;
}); });
@ -326,7 +335,7 @@ export const AddSignersFormPartial = ({
form.setValue(`signers.${index}.signingOrder`, signer.signingOrder); form.setValue(`signers.${index}.signingOrder`, signer.signingOrder);
}); });
}, },
[form], [form, canRecipientBeModified],
); );
const handleSigningOrderChange = useCallback( const handleSigningOrderChange = useCallback(
@ -417,7 +426,7 @@ export const AddSignersFormPartial = ({
isDragDisabled={ isDragDisabled={
!isSigningOrderSequential || !isSigningOrderSequential ||
isSubmitting || isSubmitting ||
hasBeenSentToRecipientId(signer.nativeId) || !canRecipientBeModified(signer.nativeId) ||
!signer.signingOrder !signer.signingOrder
} }
> >
@ -433,7 +442,7 @@ export const AddSignersFormPartial = ({
> >
<motion.fieldset <motion.fieldset
data-native-id={signer.nativeId} data-native-id={signer.nativeId}
disabled={isSubmitting || hasBeenSentToRecipientId(signer.nativeId)} disabled={isSubmitting || !canRecipientBeModified(signer.nativeId)}
className={cn('grid grid-cols-10 items-end gap-2 pb-2', { className={cn('grid grid-cols-10 items-end gap-2 pb-2', {
'border-b pt-2': showAdvancedSettings, 'border-b pt-2': showAdvancedSettings,
'grid-cols-12 pr-3': isSigningOrderSequential, 'grid-cols-12 pr-3': isSigningOrderSequential,
@ -466,7 +475,7 @@ export const AddSignersFormPartial = ({
disabled={ disabled={
snapshot.isDragging || snapshot.isDragging ||
isSubmitting || isSubmitting ||
hasBeenSentToRecipientId(signer.nativeId) !canRecipientBeModified(signer.nativeId)
} }
/> />
</FormControl> </FormControl>
@ -500,7 +509,7 @@ export const AddSignersFormPartial = ({
disabled={ disabled={
snapshot.isDragging || snapshot.isDragging ||
isSubmitting || isSubmitting ||
hasBeenSentToRecipientId(signer.nativeId) !canRecipientBeModified(signer.nativeId)
} }
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
/> />
@ -534,7 +543,7 @@ export const AddSignersFormPartial = ({
disabled={ disabled={
snapshot.isDragging || snapshot.isDragging ||
isSubmitting || isSubmitting ||
hasBeenSentToRecipientId(signer.nativeId) !canRecipientBeModified(signer.nativeId)
} }
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
/> />
@ -562,7 +571,7 @@ export const AddSignersFormPartial = ({
disabled={ disabled={
snapshot.isDragging || snapshot.isDragging ||
isSubmitting || isSubmitting ||
hasBeenSentToRecipientId(signer.nativeId) !canRecipientBeModified(signer.nativeId)
} }
/> />
</FormControl> </FormControl>
@ -585,7 +594,7 @@ export const AddSignersFormPartial = ({
disabled={ disabled={
snapshot.isDragging || snapshot.isDragging ||
isSubmitting || isSubmitting ||
hasBeenSentToRecipientId(signer.nativeId) !canRecipientBeModified(signer.nativeId)
} }
/> />
</FormControl> </FormControl>
@ -601,7 +610,7 @@ export const AddSignersFormPartial = ({
disabled={ disabled={
snapshot.isDragging || snapshot.isDragging ||
isSubmitting || isSubmitting ||
hasBeenSentToRecipientId(signer.nativeId) || !canRecipientBeModified(signer.nativeId) ||
signers.length === 1 signers.length === 1
} }
onClick={() => onRemoveSigner(index)} onClick={() => onRemoveSigner(index)}

View File

@ -210,6 +210,7 @@ export const FieldItem = ({
onFocus?.(); onFocus?.();
}} }}
ref={$el} ref={$el}
data-field-id={field.nativeId}
> >
{match(field.type) {match(field.type)
.with('CHECKBOX', () => <CheckboxField field={field} />) .with('CHECKBOX', () => <CheckboxField field={field} />)