From b6ec7945f4cb786606318cc1c7dfc8fae6ae1a18 Mon Sep 17 00:00:00 2001 From: Kristina <7614497+khjrtbrg@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:55:18 +0200 Subject: [PATCH] [web] update copy in email notifications (#32912) * add footerMessage to base email template * add customized subject line and CTA * add _getBundledActivityList GitOrigin-RevId: e70c0955485b0892f31e20daa0430faef80b0d64 --- .../app/src/Features/Email/EmailBuilder.mjs | 15 +++++++ .../Layouts/BaseWithHeaderEmailLayout.mjs | 1 + .../test/unit/src/Email/EmailBuilder.test.mjs | 40 +++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/services/web/app/src/Features/Email/EmailBuilder.mjs b/services/web/app/src/Features/Email/EmailBuilder.mjs index 4d00a96745..070493d4e0 100644 --- a/services/web/app/src/Features/Email/EmailBuilder.mjs +++ b/services/web/app/src/Features/Email/EmailBuilder.mjs @@ -38,6 +38,12 @@ function _emailBodyPlainText(content, opts, ctaEmail) { emailBody += settings.email.template.customFooter } + const footerMessage = content.footerMessage(opts, true) + if (footerMessage) { + emailBody += `\r\n\r\n` + emailBody += footerMessage + } + return emailBody } @@ -62,11 +68,17 @@ function ctaTemplate(content) { if (!content.gmailGoToAction) { content.gmailGoToAction = () => {} } + if (!content.footerMessage) { + content.footerMessage = () => {} + } return { subject(opts) { return content.subject(opts) }, layout: BaseWithHeaderEmailLayout, + footerMessage(opts) { + return content.footerMessage(opts) + }, plainTextTemplate(opts) { return _emailBodyPlainText(content, opts, true) }, @@ -127,6 +139,9 @@ function buildEmail(templateName, opts) { const template = templates[templateName] opts.siteUrl = settings.siteUrl opts.body = template.compiledTemplate(opts) + opts.footerMessage = template.footerMessage + ? template.footerMessage(opts) + : '' return { subject: template.subject(opts), html: template.layout(opts), diff --git a/services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.mjs b/services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.mjs index 33c298d09b..4242241135 100644 --- a/services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.mjs +++ b/services/web/app/src/Features/Email/Layouts/BaseWithHeaderEmailLayout.mjs @@ -380,6 +380,7 @@ export default _.template(`\ settings.siteUrl }

+ <% if (footerMessage) { %>

<%= footerMessage %>

<% } %> diff --git a/services/web/test/unit/src/Email/EmailBuilder.test.mjs b/services/web/test/unit/src/Email/EmailBuilder.test.mjs index 6fa32ccf6b..d3a5369060 100644 --- a/services/web/test/unit/src/Email/EmailBuilder.test.mjs +++ b/services/web/test/unit/src/Email/EmailBuilder.test.mjs @@ -209,6 +209,46 @@ describe('EmailBuilder', function () { }).to.throw(Error) }) }) + + describe('footerMessage', function () { + it('should default footerMessage to undefined when not provided', function (ctx) { + const template = ctx.EmailBuilder.ctaTemplate({ + subject: () => 'Subject', + message: () => ['Message'], + ctaText: () => 'Click', + ctaURL: () => 'https://example.com', + }) + expect(template.footerMessage({})).to.be.undefined + }) + + it('should use the provided footerMessage callback', function (ctx) { + const template = ctx.EmailBuilder.ctaTemplate({ + subject: () => 'Subject', + message: () => ['Message'], + ctaText: () => 'Click', + ctaURL: () => 'https://example.com', + footerMessage: () => 'Custom footer text', + }) + expect(template.footerMessage({})).to.equal('Custom footer text') + }) + + it('should include footerMessage in plain text output when provided', function (ctx) { + ctx.EmailBuilder.templates.testFooterTemplate = + ctx.EmailBuilder.ctaTemplate({ + subject: () => 'Test Subject', + message: () => ['Body message'], + ctaText: () => 'Go', + ctaURL: () => 'https://example.com', + footerMessage: (opts, isPlainText) => + isPlainText ? 'Plain footer' : 'HTML footer', + }) + const email = ctx.EmailBuilder.buildEmail('testFooterTemplate', { + to: 'test@example.com', + }) + expect(email.text).to.contain('Plain footer') + delete ctx.EmailBuilder.templates.testFooterTemplate + }) + }) }) describe('templates', function () {