feat(email): add sendMentorTeamAssignmentEmail for per-team mentor notifications
Fires when a mentor is added to a specific project team — distinct from the one-time onboarding email keyed by User.mentorOnboardingSentAt. Idempotency for this new email is enforced at the call site in Task 4 via MentorAssignment.notificationSentAt. Wrapped in try/catch — never throws.
This commit is contained in:
@@ -2752,6 +2752,80 @@ export async function sendMentorOnboardingEmail(email: string, name: string | nu
|
|||||||
await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
|
await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Per-team mentor assignment (fires every time a mentor is added to a project)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
function getMentorTeamAssignmentTemplate(
|
||||||
|
name: string,
|
||||||
|
projectTitle: string,
|
||||||
|
workspaceUrl: string,
|
||||||
|
): EmailTemplate {
|
||||||
|
const subject = `You've been assigned to a new MOPC project: "${projectTitle}"`
|
||||||
|
const greeting = name ? `Hi ${name},` : 'Hi there,'
|
||||||
|
const text = [
|
||||||
|
greeting,
|
||||||
|
'',
|
||||||
|
`You have been assigned as a mentor to the project "${projectTitle}".`,
|
||||||
|
'',
|
||||||
|
'You may have co-mentors on this team — you can collaborate together in the project workspace.',
|
||||||
|
'',
|
||||||
|
`Open the workspace: ${workspaceUrl}`,
|
||||||
|
'',
|
||||||
|
'The MOPC team',
|
||||||
|
].join('\n')
|
||||||
|
|
||||||
|
const html = `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body style="margin:0;padding:0;background:#f6f8fa;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;color:#0f172a;">
|
||||||
|
<div style="max-width:560px;margin:32px auto;background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.06);">
|
||||||
|
<div style="background:#053d57;padding:24px 28px;color:#fefefe;">
|
||||||
|
<h1 style="margin:0;font-size:20px;font-weight:600;">New mentor assignment</h1>
|
||||||
|
</div>
|
||||||
|
<div style="padding:24px 28px;line-height:1.5;font-size:14px;">
|
||||||
|
<p style="margin-top:0;">${name ? `Hi ${escapeHtml(name)},` : 'Hi there,'}</p>
|
||||||
|
<p>You have been assigned as a mentor to the project <strong>${escapeHtml(projectTitle)}</strong>.</p>
|
||||||
|
<p style="margin-top:24px;">
|
||||||
|
<a href="${workspaceUrl}" style="display:inline-block;padding:10px 20px;background:#de0f1e;color:#fff;text-decoration:none;border-radius:6px;font-weight:600;">Open Project Workspace</a>
|
||||||
|
</p>
|
||||||
|
<p style="margin-top:24px;color:#64748b;font-size:12px;">
|
||||||
|
You may have co-mentors on this team — you can collaborate together in the project workspace.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div style="padding:16px 28px;background:#f1f5f9;color:#64748b;font-size:12px;text-align:center;">
|
||||||
|
Monaco Ocean Protection Challenge
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`.trim()
|
||||||
|
|
||||||
|
return { subject, text, html }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a per-team mentor assignment email. Fires every time a mentor is added
|
||||||
|
* to a specific project (distinct from the one-time onboarding email).
|
||||||
|
* Idempotency is enforced at the call site via MentorAssignment.notificationSentAt.
|
||||||
|
* Never throws — failures are caught and logged.
|
||||||
|
*/
|
||||||
|
export async function sendMentorTeamAssignmentEmail(
|
||||||
|
email: string,
|
||||||
|
name: string | null,
|
||||||
|
projectTitle: string,
|
||||||
|
projectId: string,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
const baseUrl = process.env.NEXTAUTH_URL || 'https://monaco-opc.com'
|
||||||
|
const workspaceUrl = `${baseUrl.replace(/\/$/, '')}/mentor/workspace/${projectId}`
|
||||||
|
const template = getMentorTeamAssignmentTemplate(name || '', projectTitle, workspaceUrl)
|
||||||
|
await sendEmail({ to: email, subject: template.subject, text: template.text, html: template.html })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[sendMentorTeamAssignmentEmail] failed', { email, projectId, error })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getFinalistConfirmationTemplate(
|
function getFinalistConfirmationTemplate(
|
||||||
name: string,
|
name: string,
|
||||||
projectTitle: string,
|
projectTitle: string,
|
||||||
|
|||||||
Reference in New Issue
Block a user