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 ? ( + Branding Logo + ) : ( + Documenso Logo + )} + + +
+
+ + {customBody && ( + +
+ +
{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 () => {