From cedd1883283e6cdc270c608a2468db4d1069b7fa Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 28 Apr 2026 15:58:17 +0200 Subject: [PATCH] =?UTF-8?q?feat(email):=20mentor-onboarding=20email=20temp?= =?UTF-8?q?late=20+=20sender=20(=C2=A7D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One-shot email sent when a user is first granted the MENTOR role. Subject: 'Welcome to MOPC mentoring'. Includes a CTA to /mentor and a hint about the Switch View pill for multi-role users. Idempotency lives at the call site (User.mentorOnboardingSentAt checked in user.bulkUpdateRoles / user.updateRoles). Plan: docs/superpowers/plans/2026-04-28-pr6-multi-role-and-workspace-previews.md --- src/lib/email.ts | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/lib/email.ts b/src/lib/email.ts index 718b3ba..ea0abc8 100644 --- a/src/lib/email.ts +++ b/src/lib/email.ts @@ -2494,3 +2494,76 @@ export async function sendNotificationEmail( const template = getNotificationEmailTemplate(name, subject, body, ensureAbsoluteUrl(linkUrl)) await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html }) } + +// ============================================================================= +// Mentor onboarding (one-shot, on first MENTOR role grant) +// ============================================================================= + +function getMentorOnboardingTemplate(name: string, baseUrl: string): EmailTemplate { + const mentorUrl = `${baseUrl.replace(/\/$/, '')}/mentor` + const subject = 'Welcome to MOPC mentoring' + const text = [ + `Hi ${name || 'there'},`, + '', + 'You have been added as a mentor for the Monaco Ocean Protection Challenge.', + '', + 'As a mentor, you will:', + ' • Be matched with one or more shortlisted projects', + ' • Communicate with project teams in a private workspace', + ' • Share files, comments, and milestone feedback', + ' • Help projects sharpen their submissions before the live final', + '', + `Your mentor dashboard: ${mentorUrl}`, + '', + 'If you also have other roles on the platform (e.g. juror), look for the', + '"Switch View" pill in the top-right of any page to move between dashboards.', + '', + 'The MOPC team', + ].join('\n') + + const html = ` + + + +
+
+

Welcome to MOPC mentoring

+
+
+

Hi ${name || 'there'},

+

You have been added as a mentor for the Monaco Ocean Protection Challenge.

+

As a mentor, you will:

+
    +
  • Be matched with one or more shortlisted projects
  • +
  • Communicate with project teams in a private workspace
  • +
  • Share files, comments, and milestone feedback
  • +
  • Help projects sharpen their submissions before the live final
  • +
+

+ Open Mentor Dashboard +

+

+ If you also have other roles on the platform, use the "Switch View" pill in the top-right of any page to move between dashboards. +

+
+
+ Monaco Ocean Protection Challenge +
+
+ + + `.trim() + + return { subject, text, html } +} + +/** + * Send mentor onboarding email. Idempotency is enforced at the call site + * (see user.bulkUpdateRoles / user.updateRoles) by checking + * User.mentorOnboardingSentAt. + */ +export async function sendMentorOnboardingEmail(email: string, name: string | null): Promise { + const baseUrl = process.env.NEXTAUTH_URL || 'https://monaco-opc.com' + const template = getMentorOnboardingTemplate(name || '', baseUrl) + await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html }) +}