diff --git a/apps/remix/app/components/general/envelope-editor/envelope-editor-preview-page.tsx b/apps/remix/app/components/general/envelope-editor/envelope-editor-preview-page.tsx
index e57740cd1..43d40d41c 100644
--- a/apps/remix/app/components/general/envelope-editor/envelope-editor-preview-page.tsx
+++ b/apps/remix/app/components/general/envelope-editor/envelope-editor-preview-page.tsx
@@ -1,10 +1,20 @@
-import { lazy, useEffect, useState } from 'react';
+import { lazy, useEffect, useMemo, useState } from 'react';
+import { faker } from '@faker-js/faker/locale/en';
import { Trans } from '@lingui/react/macro';
-import { ConstructionIcon, FileTextIcon } from 'lucide-react';
+import { FieldType } from '@prisma/client';
+import { FileTextIcon } from 'lucide-react';
+import { match } from 'ts-pattern';
import { useCurrentEnvelopeEditor } from '@documenso/lib/client-only/providers/envelope-editor-provider';
-import { useCurrentEnvelopeRender } from '@documenso/lib/client-only/providers/envelope-render-provider';
+import {
+ EnvelopeRenderProvider,
+ useCurrentEnvelopeRender,
+} from '@documenso/lib/client-only/providers/envelope-render-provider';
+import { ZFieldAndMetaSchema } from '@documenso/lib/types/field-meta';
+import { extractFieldInsertionValues } from '@documenso/lib/utils/envelope-signing';
+import { toCheckboxCustomText } from '@documenso/lib/utils/fields';
+import { extractInitials } from '@documenso/lib/utils/recipient-formatter';
import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
import PDFViewerKonvaLazy from '@documenso/ui/components/pdf-viewer/pdf-viewer-konva-lazy';
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
@@ -15,15 +25,169 @@ import { EnvelopeRendererFileSelector } from './envelope-file-selector';
const EnvelopeGenericPageRenderer = lazy(async () => import('./envelope-generic-page-renderer'));
+// Todo: Envelopes - Dynamically import faker
export const EnvelopeEditorPreviewPage = () => {
const { envelope, editorFields } = useCurrentEnvelopeEditor();
- const { currentEnvelopeItem } = useCurrentEnvelopeRender();
+ const { currentEnvelopeItem, fields } = useCurrentEnvelopeRender();
const [selectedPreviewMode, setSelectedPreviewMode] = useState<'recipient' | 'signed'>(
'recipient',
);
+ const fieldsWithPlaceholders = useMemo(() => {
+ return fields.map((field) => {
+ const fieldMeta = ZFieldAndMetaSchema.parse(field);
+
+ const recipient = envelope.recipients.find((recipient) => recipient.id === field.recipientId);
+
+ if (!recipient) {
+ throw new Error('Recipient not found');
+ }
+
+ faker.seed(recipient.id);
+
+ const recipientName = recipient.name || faker.person.fullName();
+ const recipientEmail = recipient.email || faker.internet.email();
+
+ faker.seed(recipient.id + field.id);
+
+ return {
+ ...field,
+ inserted: true,
+ ...match(fieldMeta)
+ .with({ type: FieldType.TEXT }, ({ fieldMeta }) => {
+ let text = fieldMeta?.text || faker.lorem.words(5);
+
+ if (fieldMeta?.characterLimit) {
+ text = text.slice(0, fieldMeta?.characterLimit);
+ }
+
+ return {
+ customText: text,
+ };
+ })
+ .with({ type: FieldType.NUMBER }, ({ fieldMeta }) => {
+ let number = fieldMeta?.value ?? '';
+
+ if (number === '') {
+ number = faker.number
+ .int({
+ min: fieldMeta?.minValue ?? 0,
+ max: fieldMeta?.maxValue ?? 1000,
+ })
+ .toString();
+ }
+
+ return {
+ customText: number,
+ };
+ })
+ .with({ type: FieldType.DATE }, () => {
+ const date = extractFieldInsertionValues({
+ fieldValue: {
+ type: FieldType.DATE,
+ value: true,
+ },
+ field,
+ documentMeta: envelope.documentMeta,
+ });
+
+ return {
+ customText: date.customText,
+ };
+ })
+ .with({ type: FieldType.EMAIL }, () => {
+ return {
+ customText: recipientEmail,
+ };
+ })
+ .with({ type: FieldType.NAME }, () => {
+ return {
+ customText: recipientName,
+ };
+ })
+ .with({ type: FieldType.INITIALS }, () => {
+ return {
+ customText: extractInitials(recipientName),
+ };
+ })
+ .with({ type: FieldType.RADIO }, ({ fieldMeta }) => {
+ const values = fieldMeta?.values ?? [];
+
+ if (values.length === 0) {
+ return '';
+ }
+
+ let customText = '';
+
+ const preselectedValue = values.findIndex((value) => value.checked);
+
+ if (preselectedValue !== -1) {
+ customText = preselectedValue.toString();
+ } else {
+ const randomIndex = faker.number.int({ min: 0, max: values.length - 1 });
+ customText = randomIndex.toString();
+ }
+
+ return {
+ customText,
+ };
+ })
+ .with({ type: FieldType.CHECKBOX }, ({ fieldMeta }) => {
+ let checkedValues: number[] = [];
+
+ const values = fieldMeta?.values ?? [];
+
+ values.forEach((value, index) => {
+ if (value.checked) {
+ checkedValues.push(index);
+ }
+ });
+
+ if (checkedValues.length === 0 && values.length > 0) {
+ const numberOfValues = fieldMeta?.validationLength || 1;
+
+ checkedValues = Array.from({ length: numberOfValues }, (_, index) => index);
+ }
+
+ return {
+ customText: toCheckboxCustomText(checkedValues),
+ };
+ })
+ .with({ type: FieldType.DROPDOWN }, ({ fieldMeta }) => {
+ const values = fieldMeta?.values ?? [];
+
+ let customText = fieldMeta?.defaultValue || '';
+
+ if (!customText && values.length > 0) {
+ const randomIndex = faker.number.int({ min: 0, max: values.length - 1 });
+ customText = values[randomIndex].value;
+ }
+
+ return {
+ customText,
+ };
+ })
+ .with({ type: FieldType.SIGNATURE }, () => {
+ return {
+ customText: '',
+ signature: {
+ signatureImageAsBase64: '',
+ typedSignature: recipientName,
+ },
+ };
+ })
+ .with({ type: FieldType.FREE_SIGNATURE }, () => {
+ return {
+ customText: '',
+ };
+ })
+ .exhaustive(),
+ };
+ });
+ }, [fields, envelope, envelope.recipients, envelope.documentMeta]);
+
/**
* Set the selected recipient to the first recipient in the envelope.
*/
@@ -31,40 +195,38 @@ export const EnvelopeEditorPreviewPage = () => {
editorFields.setSelectedRecipient(envelope.recipients[0]?.id ?? null);
}, []);
+ // Override the parent renderer provider so we can inject custom fields.
return (
-
-
- {/* Horizontal envelope item selector */}
-
+
recipient.id)}
+ overrideSettings={{
+ mode: 'export',
+ }}
+ >
+
+
+ {/* Horizontal envelope item selector */}
+
- {/* Document View */}
-
-
-
- Preview Mode
-
-
- Preview what the signed document will look like with placeholder data
-
-
+ {/* Document View */}
+
+
+
+ Preview Mode
+
+
+ Preview what the signed document will look like with placeholder data
+
+
- {/* Coming soon section */}
-
-
-
-
- Coming soon
-
-
- This feature is coming soon
-
-
-
-
- {/* Todo: Envelopes - Remove div after preview mode is implemented */}
-
{currentEnvelopeItem !== null ? (
-
+
) : (
@@ -78,27 +240,28 @@ export const EnvelopeEditorPreviewPage = () => {
)}
-
- {/* Right Section - Form Fields Panel */}
- {currentEnvelopeItem && false && (
-
- {/* Add fields section. */}
-
- {/*
+ {/* Right Section - Form Fields Panel */}
+ {currentEnvelopeItem && false && (
+
+ {/* Add fields section. */}
+
+ {/*
Preivew Mode
*/}
-
-
- Preview Mode
-
-
- Preview what the signed document will look like with placeholder data
-
-
+
+
+ Preview Mode
+
+
+
+ Preview what the signed document will look like with placeholder data
+
+
+
- {/*
+ {/*
{
Preview what a recipient will see
Preview the signed document
*/}
-
+
- {false && (
-
- {selectedPreviewMode === 'recipient' && (
- <>
-
+ {false && (
+
+ {selectedPreviewMode === 'recipient' && (
+ <>
+
- {/* Recipient selector section. */}
-
-
- Selected Recipient
-
+ {/* Recipient selector section. */}
+
+
+ Selected Recipient
+
-
- editorFields.setSelectedRecipient(recipient.id)
- }
- recipients={envelope.recipients}
- className="w-full"
- align="end"
- />
-
- >
- )}
-
- )}
-
- )}
-
+
+ editorFields.setSelectedRecipient(recipient.id)
+ }
+ recipients={envelope.recipients}
+ className="w-full"
+ align="end"
+ />
+
+ >
+ )}
+
+ )}
+
+ )}
+
+
);
};
diff --git a/apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx b/apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
index e30c33c15..6593609f5 100644
--- a/apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
+++ b/apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
@@ -174,7 +174,7 @@ export const EnvelopeEditorSettingsDialog = ({
const { t, i18n } = useLingui();
const { toast } = useToast();
- const { envelope } = useCurrentEnvelopeEditor();
+ const { envelope, updateEnvelopeAsync } = useCurrentEnvelopeEditor();
const team = useCurrentTeam();
const organisation = useCurrentOrganisation();
@@ -186,14 +186,12 @@ export const EnvelopeEditorSettingsDialog = ({
documentAuth: envelope.authOptions,
});
- const form = useForm
({
- resolver: zodResolver(ZAddSettingsFormSchema),
- defaultValues: {
- externalId: envelope.externalId || '', // Todo: String or undefined?
+ const createDefaultValues = () => {
+ return {
+ externalId: envelope.externalId || '',
visibility: envelope.visibility || '',
globalAccessAuth: documentAuthOption?.globalAccessAuth || [],
globalActionAuth: documentAuthOption?.globalActionAuth || [],
-
meta: {
subject: envelope.documentMeta.subject ?? '',
message: envelope.documentMeta.message ?? '',
@@ -210,10 +208,13 @@ export const EnvelopeEditorSettingsDialog = ({
emailSettings: ZDocumentEmailSettingsSchema.parse(envelope.documentMeta.emailSettings),
signatureTypes: extractTeamSignatureSettings(envelope.documentMeta),
},
- },
- });
+ };
+ };
- const { mutateAsync: updateEnvelope } = trpc.envelope.update.useMutation();
+ const form = useForm({
+ resolver: zodResolver(ZAddSettingsFormSchema),
+ defaultValues: createDefaultValues(),
+ });
const envelopeHasBeenSent =
envelope.type === EnvelopeType.DOCUMENT &&
@@ -239,8 +240,7 @@ export const EnvelopeEditorSettingsDialog = ({
.safeParse(data.globalAccessAuth);
try {
- await updateEnvelope({
- envelopeId: envelope.id,
+ await updateEnvelopeAsync({
data: {
externalId: data.externalId || null,
visibility: data.visibility,
@@ -295,7 +295,7 @@ export const EnvelopeEditorSettingsDialog = ({
]);
useEffect(() => {
- form.reset();
+ form.reset(createDefaultValues());
setActiveTab('general');
}, [open, form]);
diff --git a/apps/remix/app/components/general/envelope-editor/envelope-generic-page-renderer.tsx b/apps/remix/app/components/general/envelope-editor/envelope-generic-page-renderer.tsx
index 74635816b..37f7cd5b6 100644
--- a/apps/remix/app/components/general/envelope-editor/envelope-generic-page-renderer.tsx
+++ b/apps/remix/app/components/general/envelope-editor/envelope-generic-page-renderer.tsx
@@ -12,7 +12,7 @@ import { getClientSideFieldTranslations } from '@documenso/lib/utils/fields';
export default function EnvelopeGenericPageRenderer() {
const { i18n } = useLingui();
- const { currentEnvelopeItem, fields, getRecipientColorKey, setRenderError } =
+ const { currentEnvelopeItem, fields, getRecipientColorKey, setRenderError, overrideSettings } =
useCurrentEnvelopeRender();
const {
@@ -50,12 +50,11 @@ export default function EnvelopeGenericPageRenderer() {
field: {
renderId: field.id.toString(),
...field,
- customText: '',
width: Number(field.width),
height: Number(field.height),
positionX: Number(field.positionX),
positionY: Number(field.positionY),
- inserted: false,
+ customText: field.inserted ? field.customText : '',
fieldMeta: field.fieldMeta,
},
translations: getClientSideFieldTranslations(i18n),
@@ -63,7 +62,7 @@ export default function EnvelopeGenericPageRenderer() {
pageHeight: unscaledViewport.height,
color: getRecipientColorKey(field.recipientId),
editable: false,
- mode: 'sign',
+ mode: overrideSettings?.mode ?? 'sign',
});
};
diff --git a/apps/remix/package.json b/apps/remix/package.json
index 7e3c00771..3454f3285 100644
--- a/apps/remix/package.json
+++ b/apps/remix/package.json
@@ -25,6 +25,7 @@
"@documenso/trpc": "*",
"@documenso/ui": "*",
"@epic-web/remember": "^1.1.0",
+ "@faker-js/faker": "^10.1.0",
"@hono/node-server": "^1.13.7",
"@hono/trpc-server": "^0.3.4",
"@hookform/resolvers": "^3.1.0",
@@ -104,4 +105,4 @@
"vite-tsconfig-paths": "^5.1.4"
},
"version": "1.13.1"
-}
\ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index e0d18f26d..783d6865f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -113,6 +113,7 @@
"@documenso/trpc": "*",
"@documenso/ui": "*",
"@epic-web/remember": "^1.1.0",
+ "@faker-js/faker": "^10.1.0",
"@hono/node-server": "^1.13.7",
"@hono/trpc-server": "^0.3.4",
"@hookform/resolvers": "^3.1.0",
@@ -3512,6 +3513,22 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@faker-js/faker": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.1.0.tgz",
+ "integrity": "sha512-C3mrr3b5dRVlKPJdfrAXS8+dq+rq8Qm5SNRazca0JKgw1HQERFmrVb0towvMmw5uu8hHKNiQasMaR/tydf3Zsg==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fakerjs"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0",
+ "npm": ">=10"
+ }
+ },
"node_modules/@floating-ui/core": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.0.tgz",
diff --git a/packages/app-tests/e2e/envelopes/envelope-alignment.spec.ts b/packages/app-tests/e2e/envelopes/envelope-alignment.spec.ts
index 4644be247..a2a1bb2b1 100644
--- a/packages/app-tests/e2e/envelopes/envelope-alignment.spec.ts
+++ b/packages/app-tests/e2e/envelopes/envelope-alignment.spec.ts
@@ -25,8 +25,7 @@ import { DocumentStatus } from '@prisma/client';
import fs from 'node:fs';
import path from 'node:path';
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.js';
-
-import { getFile } from '@documenso/lib/universal/upload/get-file';
+import { getEnvelopeDownloadUrl } from '@documenso/lib/utils/envelope-download';
import { prisma } from '@documenso/prisma';
import { seedAlignmentTestDocument } from '@documenso/prisma/seed/initial-seed';
import { seedUser } from '@documenso/prisma/seed/users';
@@ -95,7 +94,13 @@ test('field placement visual regression', async ({ page }, testInfo) => {
await Promise.all(
completedDocument.envelopeItems.map(async (item) => {
- const pdfData = await getFile(item.documentData);
+ const documentUrl = getEnvelopeDownloadUrl({
+ envelopeItem: item,
+ token,
+ version: 'signed',
+ });
+
+ const pdfData = await fetch(documentUrl).then(async (res) => await res.arrayBuffer());
const loadedImages = storedImages
.filter((image) => image.includes(item.title))
@@ -103,7 +108,7 @@ test('field placement visual regression', async ({ page }, testInfo) => {
await compareSignedPdfWithImages({
id: item.title.replaceAll(' ', '-').toLowerCase(),
- pdfData,
+ pdfData: new Uint8Array(pdfData),
images: loadedImages,
testInfo,
});
@@ -174,9 +179,15 @@ test.skip('download envelope images', async ({ page }) => {
await Promise.all(
completedDocument.envelopeItems.map(async (item) => {
- const pdfData = await getFile(item.documentData);
+ const documentUrl = getEnvelopeDownloadUrl({
+ envelopeItem: item,
+ token,
+ version: 'signed',
+ });
- const pdfImages = await renderPdfToImage(pdfData);
+ const pdfData = await fetch(documentUrl).then(async (res) => await res.arrayBuffer());
+
+ const pdfImages = await renderPdfToImage(new Uint8Array(pdfData));
for (const [index, { image }] of pdfImages.entries()) {
fs.writeFileSync(
diff --git a/packages/app-tests/e2e/features/include-document-certificate.spec.ts b/packages/app-tests/e2e/features/include-document-certificate.spec.ts
index 961c6fb3e..ec5ee5fda 100644
--- a/packages/app-tests/e2e/features/include-document-certificate.spec.ts
+++ b/packages/app-tests/e2e/features/include-document-certificate.spec.ts
@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
import { DocumentStatus, FieldType } from '@prisma/client';
import { getDocumentByToken } from '@documenso/lib/server-only/document/get-document-by-token';
-import { getFile } from '@documenso/lib/universal/upload/get-file';
+import { getEnvelopeDownloadUrl } from '@documenso/lib/utils/envelope-download';
import { prisma } from '@documenso/prisma';
import { seedPendingDocumentWithFullFields } from '@documenso/prisma/seed/documents';
import { seedTeam } from '@documenso/prisma/seed/teams';
@@ -25,20 +25,25 @@ test.describe('Signing Certificate Tests', () => {
teamId: team.id,
});
- const documentData = await prisma.documentData
+ const recipient = recipients[0];
+
+ const documentData = await prisma.envelopeItem
.findFirstOrThrow({
where: {
- envelopeItem: {
- envelopeId: document.id,
- },
+ envelopeId: document.id,
},
})
- .then(async (data) => getFile(data));
+ .then(async (data) => {
+ const documentUrl = getEnvelopeDownloadUrl({
+ envelopeItem: data,
+ token: recipient.token,
+ version: 'signed',
+ });
+ return fetch(documentUrl).then(async (res) => await res.arrayBuffer());
+ });
const originalPdf = await PDFDocument.load(documentData);
- const recipient = recipients[0];
-
// Sign the document
await page.goto(`/sign/${recipient.token}`);
@@ -78,9 +83,17 @@ test.describe('Signing Certificate Tests', () => {
},
});
- const firstDocumentData = completedDocument.envelopeItems[0].documentData;
+ const firstDocumentData = completedDocument.envelopeItems[0];
- const completedDocumentData = await getFile(firstDocumentData);
+ const documentUrl = getEnvelopeDownloadUrl({
+ envelopeItem: firstDocumentData,
+ token: recipient.token,
+ version: 'signed',
+ });
+
+ const pdfData = await fetch(documentUrl).then(async (res) => await res.arrayBuffer());
+
+ const completedDocumentData = new Uint8Array(pdfData);
// Load the PDF and check number of pages
const pdfDoc = await PDFDocument.load(completedDocumentData);
@@ -117,20 +130,25 @@ test.describe('Signing Certificate Tests', () => {
},
});
- const documentData = await prisma.documentData
+ const recipient = recipients[0];
+
+ const documentData = await prisma.envelopeItem
.findFirstOrThrow({
where: {
- envelopeItem: {
- envelopeId: document.id,
- },
+ envelopeId: document.id,
},
})
- .then(async (data) => getFile(data));
+ .then(async (data) => {
+ const documentUrl = getEnvelopeDownloadUrl({
+ envelopeItem: data,
+ token: recipient.token,
+ version: 'signed',
+ });
+ return fetch(documentUrl).then(async (res) => await res.arrayBuffer());
+ });
const originalPdf = await PDFDocument.load(documentData);
- const recipient = recipients[0];
-
// Sign the document
await page.goto(`/sign/${recipient.token}`);
@@ -168,9 +186,17 @@ test.describe('Signing Certificate Tests', () => {
},
});
- const firstDocumentData = completedDocument.envelopeItems[0].documentData;
+ const firstDocumentData = completedDocument.envelopeItems[0];
- const completedDocumentData = await getFile(firstDocumentData);
+ const documentUrl = getEnvelopeDownloadUrl({
+ envelopeItem: firstDocumentData,
+ token: recipient.token,
+ version: 'signed',
+ });
+
+ const pdfData = await fetch(documentUrl).then(async (res) => await res.arrayBuffer());
+
+ const completedDocumentData = new Uint8Array(pdfData);
// Load the PDF and check number of pages
const completedPdf = await PDFDocument.load(completedDocumentData);
@@ -207,19 +233,24 @@ test.describe('Signing Certificate Tests', () => {
},
});
- const documentData = await prisma.documentData
+ const recipient = recipients[0];
+
+ const documentData = await prisma.envelopeItem
.findFirstOrThrow({
where: {
- envelopeItem: {
- envelopeId: document.id,
- },
+ envelopeId: document.id,
},
})
- .then(async (data) => getFile(data));
+ .then(async (data) => {
+ const documentUrl = getEnvelopeDownloadUrl({
+ envelopeItem: data,
+ token: recipient.token,
+ version: 'signed',
+ });
+ return fetch(documentUrl).then(async (res) => await res.arrayBuffer());
+ });
- const originalPdf = await PDFDocument.load(documentData);
-
- const recipient = recipients[0];
+ const originalPdf = await PDFDocument.load(new Uint8Array(documentData));
// Sign the document
await page.goto(`/sign/${recipient.token}`);
@@ -258,7 +289,15 @@ test.describe('Signing Certificate Tests', () => {
},
});
- const completedDocumentData = await getFile(completedDocument.envelopeItems[0].documentData);
+ const documentUrl = getEnvelopeDownloadUrl({
+ envelopeItem: completedDocument.envelopeItems[0],
+ token: recipient.token,
+ version: 'signed',
+ });
+
+ const completedDocumentData = await fetch(documentUrl).then(
+ async (res) => await res.arrayBuffer(),
+ );
// Load the PDF and check number of pages
const completedPdf = await PDFDocument.load(completedDocumentData);
diff --git a/packages/lib/client-only/providers/envelope-editor-provider.tsx b/packages/lib/client-only/providers/envelope-editor-provider.tsx
index baf216ac3..dca7c68bc 100644
--- a/packages/lib/client-only/providers/envelope-editor-provider.tsx
+++ b/packages/lib/client-only/providers/envelope-editor-provider.tsx
@@ -46,6 +46,7 @@ type EnvelopeEditorProviderValue = {
setLocalEnvelope: (localEnvelope: Partial) => void;
updateEnvelope: (envelopeUpdates: UpdateEnvelopePayload) => void;
+ updateEnvelopeAsync: (envelopeUpdates: UpdateEnvelopePayload) => Promise;
setRecipientsDebounced: (recipients: TSetEnvelopeRecipientsRequest['recipients']) => void;
setRecipientsAsync: (recipients: TSetEnvelopeRecipientsRequest['recipients']) => Promise;
@@ -66,8 +67,6 @@ type EnvelopeEditorProviderValue = {
};
syncEnvelope: () => Promise;
- // refetchEnvelope: () => Promise;
- // updateEnvelope: (envelope: TEnvelope) => Promise;
};
interface EnvelopeEditorProviderProps {
@@ -236,6 +235,13 @@ export const EnvelopeEditorProvider = ({
setEnvelopeDebounced(envelopeUpdates);
};
+ const updateEnvelopeAsync = async (envelopeUpdates: UpdateEnvelopePayload) => {
+ await envelopeUpdateMutationQuery.mutateAsync({
+ envelopeId: envelope.id,
+ ...envelopeUpdates,
+ });
+ };
+
const getRecipientColorKey = useCallback(
(recipientId: number) => {
const recipientIndex = envelope.recipients.findIndex(
@@ -323,6 +329,7 @@ export const EnvelopeEditorProvider = ({
setLocalEnvelope,
getRecipientColorKey,
updateEnvelope,
+ updateEnvelopeAsync,
setRecipientsDebounced,
setRecipientsAsync,
editorFields,
diff --git a/packages/lib/client-only/providers/envelope-render-provider.tsx b/packages/lib/client-only/providers/envelope-render-provider.tsx
index 0523678e4..12fa53003 100644
--- a/packages/lib/client-only/providers/envelope-render-provider.tsx
+++ b/packages/lib/client-only/providers/envelope-render-provider.tsx
@@ -16,6 +16,10 @@ type FileData =
status: 'loaded';
};
+type EnvelopeRenderOverrideSettings = {
+ mode: 'edit' | 'sign' | 'export';
+};
+
type EnvelopeRenderItem = TEnvelope['envelopeItems'][number];
type EnvelopeRenderProviderValue = {
@@ -28,10 +32,12 @@ type EnvelopeRenderProviderValue = {
renderError: boolean;
setRenderError: (renderError: boolean) => void;
+ overrideSettings?: EnvelopeRenderOverrideSettings;
};
interface EnvelopeRenderProviderProps {
children: React.ReactNode;
+
envelope: Pick;
/**
@@ -54,6 +60,11 @@ interface EnvelopeRenderProviderProps {
* If not provided, it will be assumed that the current user can access the document.
*/
token: string | undefined;
+
+ /**
+ * Custom override settings for generic page renderers.
+ */
+ overrideSettings?: EnvelopeRenderOverrideSettings;
}
const EnvelopeRenderContext = createContext(null);
@@ -77,6 +88,7 @@ export const EnvelopeRenderProvider = ({
fields,
token,
recipientIds = [],
+ overrideSettings,
}: EnvelopeRenderProviderProps) => {
// Indexed by documentDataId.
const [files, setFiles] = useState>({});
@@ -185,6 +197,7 @@ export const EnvelopeRenderProvider = ({
getRecipientColorKey,
renderError,
setRenderError,
+ overrideSettings,
}}
>
{children}
diff --git a/packages/ui/primitives/combobox.tsx b/packages/ui/primitives/combobox.tsx
index 2f5bb6712..038b5f48a 100644
--- a/packages/ui/primitives/combobox.tsx
+++ b/packages/ui/primitives/combobox.tsx
@@ -58,7 +58,7 @@ const Combobox = ({
-
+