diff --git a/src/lib/email.ts b/src/lib/email.ts
index d47b9a7..f6c11d5 100644
--- a/src/lib/email.ts
+++ b/src/lib/email.ts
@@ -2832,11 +2832,13 @@ export async function sendMentorTeamAssignmentEmail(
}
}
-function getTeamMentorIntroductionTemplate(
+export function getTeamMentorIntroductionTemplate(
recipientName: string | null,
projectTitle: string,
mentors: { name: string | null; email: string }[],
workspaceUrl: string,
+ teammates?: { name: string | null; email: string }[],
+ customNote?: string,
): EmailTemplate {
const count = mentors.length
const subject =
@@ -2846,40 +2848,73 @@ function getTeamMentorIntroductionTemplate(
const greeting = recipientName ? `Hi ${recipientName},` : 'Hi there,'
const mentorTextLines = mentors
- .map(
- (m) => ` • ${m.name ?? 'Mentor'} — ${m.email}`,
- )
+ .map((m) => ` • ${m.name ?? 'Mentor'} — ${m.email}`)
.join('\n')
+ const teammateTextLines =
+ teammates && teammates.length > 0
+ ? ['', 'Your team:', ...teammates.map((t) => ` • ${t.name ?? 'Team member'} — ${t.email}`)]
+ : []
const text = [
greeting,
'',
+ ...(customNote ? [customNote, ''] : []),
count === 1
? `The mentoring round is now open, and your project "${projectTitle}" has a mentor:`
: `The mentoring round is now open, and your project "${projectTitle}" has ${count} mentors:`,
'',
mentorTextLines,
+ ...teammateTextLines,
'',
- 'You can chat with them, share files, and track milestones in your mentor workspace:',
- workspaceUrl,
+ 'Working with your mentor:',
+ ' - Go to the Mentoring section of your applicant portal to message your mentor directly — they are notified by email when you write.',
+ ' - Share documents and questions early; your mentor is here to help you sharpen your project before the finals.',
+ ' - You can also email your mentor directly using the address above.',
'',
- 'Feel free to reach out to them directly by email as well.',
+ `Open your mentoring page: ${workspaceUrl}`,
'',
'The MOPC team',
].join('\n')
+ const customNoteHtml = customNote
+ ? `
${escapeHtml(customNote)}
`
+ : ''
+
const mentorHtmlList = mentors
.map(
(m) => `
| ${escapeHtml(m.name ?? 'Mentor')} |
-
- ${escapeHtml(m.email)}
- |
+ ${escapeHtml(m.email)} |
`,
)
.join('')
+ const teammatesHtml =
+ teammates && teammates.length > 0
+ ? `
+ Your team
+ ${teammates
+ .map(
+ (t) => `
+
+ | ${escapeHtml(t.name ?? 'Team member')} |
+ ${escapeHtml(t.email)} |
+
`,
+ )
+ .join('')}
`
+ : ''
+
+ const instructionsHtml = `
+
+
Working with your mentor
+
+ - Go to the Mentoring section of your applicant portal to message your mentor directly — they are notified by email when you write.
+ - Share documents and questions early; your mentor is here to help you sharpen your project before the finals.
+ - You can also email your mentor directly using the address above.
+
+
`
+
const html = `
@@ -2890,16 +2925,16 @@ function getTeamMentorIntroductionTemplate(
${recipientName ? `Hi ${escapeHtml(recipientName)},` : 'Hi there,'}
+ ${customNoteHtml}
${count === 1
? `The mentoring round is now open and a mentor has been assigned to your project ${escapeHtml(projectTitle)}:`
: `The mentoring round is now open and ${count} mentors have been assigned to your project ${escapeHtml(projectTitle)}:`}
-
+
+ ${teammatesHtml}
+ ${instructionsHtml}
Open Mentor Workspace
-
- You can chat with them, share files, and track milestones in the workspace — or reach out to them directly by email.
-
Monaco Ocean Protection Challenge
@@ -2946,10 +2981,15 @@ export async function sendTeamMentorIntroductionEmail(
}
}
-function getMentorBulkAssignmentTemplate(
+export function getMentorBulkAssignmentTemplate(
name: string,
- projects: { title: string; url: string }[],
+ projects: {
+ title: string
+ url: string
+ teamMembers?: { name: string | null; email: string }[]
+ }[],
mentorDashboardUrl: string,
+ customNote?: string,
): EmailTemplate {
const count = projects.length
const subject =
@@ -2958,32 +2998,65 @@ function getMentorBulkAssignmentTemplate(
: `You've been assigned to ${count} new MOPC projects`
const greeting = name ? `Hi ${name},` : 'Hi there,'
- const textLines = projects
- .map((p) => ` • ${p.title} — ${p.url}`)
- .join('\n')
+ const textBlocks = projects.map((p) => {
+ const members =
+ p.teamMembers && p.teamMembers.length > 0
+ ? '\n' +
+ p.teamMembers
+ .map((m) => ` - ${m.name ?? 'Team member'}: ${m.email}`)
+ .join('\n')
+ : ''
+ return ` • ${p.title} — ${p.url}${members}`
+ })
const text = [
greeting,
'',
+ ...(customNote ? [customNote, ''] : []),
count === 1
? `You have been assigned as a mentor to a new project:`
: `You have been assigned as a mentor to ${count} new projects:`,
'',
- textLines,
+ ...textBlocks,
'',
- 'You may have co-mentors on these teams — you can collaborate together in each project workspace.',
+ 'How to mentor on MOPC:',
+ ' - Open each project workspace from your Mentor Dashboard to chat with the team, share files, and track milestones.',
+ ' - Messages you send in the workspace notify the team by email automatically.',
+ ' - You can also email team members directly using the addresses listed above.',
'',
`Open your mentor dashboard: ${mentorDashboardUrl}`,
'',
'The MOPC team',
].join('\n')
+ const customNoteHtml = customNote
+ ? `
${escapeHtml(customNote)}
`
+ : ''
+
const htmlList = projects
- .map(
- (p) =>
- `
${escapeHtml(p.title)}`,
- )
+ .map((p) => {
+ const members =
+ p.teamMembers && p.teamMembers.length > 0
+ ? `
${p.teamMembers
+ .map(
+ (m) =>
+ `| ${escapeHtml(m.name ?? 'Team member')} | ${escapeHtml(m.email)} |
`,
+ )
+ .join('')}
`
+ : ''
+ return `
${escapeHtml(p.title)}${members}`
+ })
.join('')
+ const instructionsHtml = `
+
+
How to mentor on MOPC
+
+ - Open each project workspace from your Mentor Dashboard to chat with the team, share files, and track milestones.
+ - Messages you send in the workspace notify the team by email automatically.
+ - You can also email team members directly using the addresses listed above.
+
+
`
+
const html = `
@@ -2994,14 +3067,13 @@ function getMentorBulkAssignmentTemplate(
${name ? `Hi ${escapeHtml(name)},` : 'Hi there,'}
+ ${customNoteHtml}
${count === 1 ? 'You have been assigned as a mentor to a new project:' : `You have been assigned as a mentor to ${count} new projects:`}
+ ${instructionsHtml}
Open Mentor Dashboard
-
- You may have co-mentors on these teams — you can collaborate together in each project workspace.
-
Monaco Ocean Protection Challenge
diff --git a/tests/unit/mentor-welcome-email.test.ts b/tests/unit/mentor-welcome-email.test.ts
new file mode 100644
index 0000000..fbf601e
--- /dev/null
+++ b/tests/unit/mentor-welcome-email.test.ts
@@ -0,0 +1,66 @@
+import { describe, it, expect } from 'vitest'
+import {
+ getMentorBulkAssignmentTemplate,
+ getTeamMentorIntroductionTemplate,
+} from '@/lib/email'
+
+describe('getMentorBulkAssignmentTemplate', () => {
+ it('includes team-member emails, the instructions block, and a custom note', () => {
+ const t = getMentorBulkAssignmentTemplate(
+ 'Alice',
+ [
+ {
+ title: 'Reef Project',
+ url: 'https://x/mentor/workspace/1',
+ teamMembers: [{ name: 'Bob', email: 'bob@team.com' }],
+ },
+ ],
+ 'https://x/mentor',
+ 'Please reach out this week.',
+ )
+ expect(t.html).toContain('bob@team.com')
+ expect(t.html).toContain('How to mentor on MOPC')
+ expect(t.html).toContain('Please reach out this week.')
+ expect(t.text).toContain('bob@team.com')
+ expect(t.text).toContain('How to mentor on MOPC')
+ })
+
+ it('renders without team members or note (backward compatible)', () => {
+ const t = getMentorBulkAssignmentTemplate(
+ 'Alice',
+ [{ title: 'P', url: 'https://x/p' }],
+ 'https://x/mentor',
+ )
+ expect(t.html).toContain('How to mentor on MOPC')
+ // Custom-note box uses the #fff7ed background; absent when no note passed.
+ expect(t.html).not.toContain('#fff7ed')
+ })
+})
+
+describe('getTeamMentorIntroductionTemplate', () => {
+ it('includes mentor + teammate emails, the instructions block, and a custom note', () => {
+ const t = getTeamMentorIntroductionTemplate(
+ 'Bob',
+ 'Reef Project',
+ [{ name: 'Alice', email: 'alice@mentor.com' }],
+ 'https://x/applicant/mentor',
+ [{ name: 'Carol', email: 'carol@team.com' }],
+ 'Welcome aboard!',
+ )
+ expect(t.html).toContain('alice@mentor.com')
+ expect(t.html).toContain('carol@team.com')
+ expect(t.html).toContain('Working with your mentor')
+ expect(t.html).toContain('Welcome aboard!')
+ })
+
+ it('renders without teammates or note (backward compatible)', () => {
+ const t = getTeamMentorIntroductionTemplate(
+ 'Bob',
+ 'Reef Project',
+ [{ name: 'Alice', email: 'alice@mentor.com' }],
+ 'https://x/applicant/mentor',
+ )
+ expect(t.html).toContain('Working with your mentor')
+ expect(t.html).not.toContain('#fff7ed')
+ })
+})