From 0ff304fca71a5547ae736d9bf8eebae378882e10 Mon Sep 17 00:00:00 2001
From: Ephraim Atta-Duncan
Date: Tue, 15 Apr 2025 11:09:21 +0000
Subject: [PATCH] feat: document reminder email template
---
.../template-document-reminder.tsx | 79 ++++++++++++++++
.../email/templates/document-reminder.tsx | 89 +++++++++++++++++++
.../emails/send-reminder.handler.ts | 8 +-
3 files changed, 171 insertions(+), 5 deletions(-)
create mode 100644 packages/email/template-components/template-document-reminder.tsx
create mode 100644 packages/email/templates/document-reminder.tsx
diff --git a/packages/email/template-components/template-document-reminder.tsx b/packages/email/template-components/template-document-reminder.tsx
new file mode 100644
index 000000000..de3255597
--- /dev/null
+++ b/packages/email/template-components/template-document-reminder.tsx
@@ -0,0 +1,79 @@
+import { useLingui } from '@lingui/react';
+import { Trans } from '@lingui/react/macro';
+import type { RecipientRole } from '@prisma/client';
+import { match } from 'ts-pattern';
+
+import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
+
+import { Button, Section, Text } from '../components';
+import { TemplateDocumentImage } from './template-document-image';
+
+export interface TemplateDocumentReminderProps {
+ recipientName: string;
+ documentName: string;
+ signDocumentLink: string;
+ assetBaseUrl: string;
+ role: RecipientRole;
+}
+
+export const TemplateDocumentReminder = ({
+ recipientName,
+ documentName,
+ signDocumentLink,
+ assetBaseUrl,
+ role,
+}: TemplateDocumentReminderProps) => {
+ const { _ } = useLingui();
+
+ const { actionVerb } = RECIPIENT_ROLES_DESCRIPTION[role];
+
+ return (
+ <>
+
+
+
+ {/* Reminder specific text */}
+
+
+ Reminder: Please {_(actionVerb).toLowerCase()} your document
+
"{documentName}"
+
+
+
+ {/* Addressee */}
+
+ Hi {recipientName},
+
+
+ {/* Reminder Call to Action */}
+
+ {match(role)
+ .with('SIGNER', () => Continue by signing the document.)
+ .with('VIEWER', () => Continue by viewing the document.)
+ .with('APPROVER', () => Continue by approving the document.)
+ .with('CC', () => '')
+ .with('ASSISTANT', () => Continue by assisting with the document.)
+ .exhaustive()}
+
+
+ {/* Primary Action Button */}
+
+
+
+
+ >
+ );
+};
+
+export default TemplateDocumentReminder;
diff --git a/packages/email/templates/document-reminder.tsx b/packages/email/templates/document-reminder.tsx
new file mode 100644
index 000000000..03ed3f9e2
--- /dev/null
+++ b/packages/email/templates/document-reminder.tsx
@@ -0,0 +1,89 @@
+import { useLingui } from '@lingui/react';
+import type { RecipientRole } from '@prisma/client';
+
+import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
+
+import { Body, Container, Head, Hr, Html, Img, Preview, Section, Text } from '../components';
+import { useBranding } from '../providers/branding';
+import { TemplateDocumentReminder } from '../template-components/template-document-reminder';
+import { TemplateFooter } from '../template-components/template-footer';
+
+export type DocumentReminderEmailTemplateProps = {
+ recipientName: string;
+ documentName: string;
+ signDocumentLink: string;
+ assetBaseUrl?: string;
+ customBody?: string;
+ role: RecipientRole;
+};
+
+export const DocumentReminderEmailTemplate = ({
+ recipientName,
+ documentName = 'Open Source Pledge.pdf',
+ signDocumentLink = 'https://documenso.com',
+ assetBaseUrl = 'http://localhost:3002',
+ customBody,
+ role,
+}: DocumentReminderEmailTemplateProps) => {
+ const { i18n } = useLingui();
+ const branding = useBranding();
+
+ const action = i18n.t(RECIPIENT_ROLES_DESCRIPTION[role].actionVerb).toLowerCase();
+
+ const previewTextString = `Reminder to ${action} ${documentName}`;
+
+ const getAssetUrl = (path: string) => {
+ return new URL(path, assetBaseUrl).toString();
+ };
+
+ return (
+
+
+ {previewTextString}
+
+
+
+
+
+ {branding.brandingEnabled && branding.brandingLogo ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ {customBody && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default DocumentReminderEmailTemplate;
diff --git a/packages/lib/jobs/definitions/emails/send-reminder.handler.ts b/packages/lib/jobs/definitions/emails/send-reminder.handler.ts
index 636bdf0cd..706ec4255 100644
--- a/packages/lib/jobs/definitions/emails/send-reminder.handler.ts
+++ b/packages/lib/jobs/definitions/emails/send-reminder.handler.ts
@@ -3,7 +3,7 @@ import { createElement } from 'react';
import { msg } from '@lingui/core/macro';
import { mailer } from '@documenso/email/mailer';
-import DocumentInviteEmailTemplate from '@documenso/email/templates/document-invite';
+import DocumentReminderEmailTemplate from '@documenso/email/templates/document-reminder';
import { prisma } from '@documenso/prisma';
import type { DocumentReminderInterval } from '@documenso/prisma/client';
import { DocumentStatus, RecipientRole, SendStatus, SigningStatus } from '@documenso/prisma/client';
@@ -118,15 +118,13 @@ export async function run({ io, intervals }: SendReminderHandlerOptions) {
const signDocumentLink = `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${recipient.token}`;
const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000';
- const template = createElement(DocumentInviteEmailTemplate, {
+ const template = createElement(DocumentReminderEmailTemplate, {
+ recipientName: recipient.name,
documentName: document.title,
- inviterName: document.user.name || undefined,
- inviterEmail: document.user.email,
assetBaseUrl,
signDocumentLink,
customBody: emailMessage,
role: recipient.role,
- selfSigner: recipient.email === document.user.email,
});
await io.runTask(`send-reminder-${recipient.id}`, async () => {