diff --git a/apps/web/src/app/(dashboard)/templates/[id]/edit/edit-template.tsx b/apps/web/src/app/(dashboard)/templates/[id]/edit/edit-template.tsx
index 766d45caa..1a2a3fa19 100644
--- a/apps/web/src/app/(dashboard)/templates/[id]/edit/edit-template.tsx
+++ b/apps/web/src/app/(dashboard)/templates/[id]/edit/edit-template.tsx
@@ -141,6 +141,23 @@ export const EditTemplateForm = ({
},
});
+ const { mutateAsync: updateTypedSignature } =
+ trpc.template.updateTemplateTypedSignatureSettings.useMutation({
+ ...DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
+ onSuccess: (newData) => {
+ utils.template.getTemplateWithDetailsById.setData(
+ {
+ id: initialTemplate.id,
+ },
+ (oldData) => ({
+ ...(oldData || initialTemplate),
+ ...newData,
+ id: Number(newData.id),
+ }),
+ );
+ },
+ });
+
const onAddSettingsFormSubmit = async (data: TAddTemplateSettingsFormSchema) => {
try {
await updateTemplateSettings({
@@ -211,6 +228,12 @@ export const EditTemplateForm = ({
fields: data.fields,
});
+ await updateTypedSignature({
+ templateId: template.id,
+ teamId: team?.id,
+ typedSignatureEnabled: data.typedSignatureEnabled,
+ });
+
// Clear all field data from localStorage
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
@@ -225,14 +248,13 @@ export const EditTemplateForm = ({
duration: 5000,
});
- // Router refresh is here to clear the router cache for when navigating to /documents.
- router.refresh();
-
router.push(templateRootPath);
} catch (err) {
+ console.error(err);
+
toast({
title: _(msg`Error`),
- description: _(msg`An error occurred while adding signers.`),
+ description: _(msg`An error occurred while adding fields.`),
variant: 'destructive',
});
}
@@ -301,6 +323,7 @@ export const EditTemplateForm = ({
fields={fields}
onSubmit={onAddFieldsFormSubmit}
teamId={team?.id}
+ typedSignatureEnabled={template.templateMeta?.typedSignatureEnabled}
/>
diff --git a/apps/web/src/app/(dashboard)/templates/[id]/template-page-view.tsx b/apps/web/src/app/(dashboard)/templates/[id]/template-page-view.tsx
index 0436ab3f6..ba011b2f3 100644
--- a/apps/web/src/app/(dashboard)/templates/[id]/template-page-view.tsx
+++ b/apps/web/src/app/(dashboard)/templates/[id]/template-page-view.tsx
@@ -73,7 +73,6 @@ export const TemplatePageView = async ({ params, team }: TemplatePageViewProps)
const mockedDocumentMeta = templateMeta
? {
- typedSignatureEnabled: false,
...templateMeta,
signingOrder: templateMeta.signingOrder || DocumentSigningOrder.SEQUENTIAL,
documentId: 0,
@@ -155,7 +154,7 @@ export const TemplatePageView = async ({ params, team }: TemplatePageViewProps)
-
+
Manage and view template
diff --git a/apps/web/src/app/(internal)/%5F%5Fhtmltopdf/certificate/page.tsx b/apps/web/src/app/(internal)/%5F%5Fhtmltopdf/certificate/page.tsx
index 35c0d0542..40cf83cee 100644
--- a/apps/web/src/app/(internal)/%5F%5Fhtmltopdf/certificate/page.tsx
+++ b/apps/web/src/app/(internal)/%5F%5Fhtmltopdf/certificate/page.tsx
@@ -209,11 +209,19 @@ export default async function SigningCertificate({ searchParams }: SigningCertif
boxShadow: `0px 0px 0px 4.88px rgba(122, 196, 85, 0.1), 0px 0px 0px 1.22px rgba(122, 196, 85, 0.6), 0px 0px 0px 0.61px rgba(122, 196, 85, 1)`,
}}
>
-
+ {signature.Signature?.signatureImageAsBase64 && (
+
+ )}
+
+ {signature.Signature?.typedSignature && (
+
+ {signature.Signature?.typedSignature}
+
+ )}
diff --git a/apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx b/apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx
index ea4e7f8f0..bf9b671c4 100644
--- a/apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx
+++ b/apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx
@@ -102,9 +102,9 @@ export const SignDirectTemplateForm = ({
created: new Date(),
recipientId: 1,
fieldId: 1,
- signatureImageAsBase64: value.value,
- typedSignature: null,
- };
+ signatureImageAsBase64: value.value.startsWith('data:') ? value.value : null,
+ typedSignature: value.value.startsWith('data:') ? null : value.value,
+ } satisfies Signature;
}
if (field.type === FieldType.DATE) {
diff --git a/apps/web/src/app/(signing)/sign/[token]/provider.tsx b/apps/web/src/app/(signing)/sign/[token]/provider.tsx
index 454007cb0..6c65fd85d 100644
--- a/apps/web/src/app/(signing)/sign/[token]/provider.tsx
+++ b/apps/web/src/app/(signing)/sign/[token]/provider.tsx
@@ -1,6 +1,6 @@
'use client';
-import { createContext, useContext, useState } from 'react';
+import { createContext, useContext, useEffect, useState } from 'react';
export type SigningContextValue = {
fullName: string;
@@ -44,6 +44,12 @@ export const SigningProvider = ({
const [email, setEmail] = useState(initialEmail || '');
const [signature, setSignature] = useState(initialSignature || null);
+ useEffect(() => {
+ if (initialSignature) {
+ setSignature(initialSignature);
+ }
+ }, [initialSignature]);
+
return (
(null);
+ const containerRef = useRef(null);
+ const [fontSize, setFontSize] = useState(2);
+
const { signature: providedSignature, setSignature: setProvidedSignature } =
useRequiredSigningContext();
@@ -108,6 +112,7 @@ export const SignatureField = ({
actionTarget: field.type,
});
};
+
const onSign = async (authOptions?: TRecipientActionAuth, signature?: string) => {
try {
const value = signature || providedSignature;
@@ -117,11 +122,23 @@ export const SignatureField = ({
return;
}
+ const isTypedSignature = !value.startsWith('data:image');
+
+ if (isTypedSignature && !typedSignatureEnabled) {
+ toast({
+ title: _(msg`Error`),
+ description: _(msg`Typed signatures are not allowed. Please draw your signature.`),
+ variant: 'destructive',
+ });
+
+ return;
+ }
+
const payload: TSignFieldWithTokenMutationSchema = {
token: recipient.token,
fieldId: field.id,
value,
- isBase64: true,
+ isBase64: !isTypedSignature,
authOptions,
};
@@ -176,6 +193,41 @@ export const SignatureField = ({
}
};
+ useLayoutEffect(() => {
+ if (!signatureRef.current || !containerRef.current || !signature?.typedSignature) {
+ return;
+ }
+
+ const adjustTextSize = () => {
+ const container = containerRef.current;
+ const text = signatureRef.current;
+
+ if (!container || !text) {
+ return;
+ }
+
+ let size = 2;
+ text.style.fontSize = `${size}rem`;
+
+ while (
+ (text.scrollWidth > container.clientWidth || text.scrollHeight > container.clientHeight) &&
+ size > 0.8
+ ) {
+ size -= 0.1;
+ text.style.fontSize = `${size}rem`;
+ }
+
+ setFontSize(size);
+ };
+
+ const resizeObserver = new ResizeObserver(adjustTextSize);
+ resizeObserver.observe(containerRef.current);
+
+ adjustTextSize();
+
+ return () => resizeObserver.disconnect();
+ }, [signature?.typedSignature]);
+
return (
- {/* This optional chaining is intentional, we don't want to move the check into the condition above */}
- {signature?.typedSignature}
-
+
+
+ {signature?.typedSignature}
+
+
)}