feat(final-docs): GRAND_FINAL_DOCS_REMINDER/SUBMITTED notification types + email template
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2238,6 +2238,42 @@ function getFinalistReminderTemplate(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reminder email sent to a finalist team to upload their Grand Final documents.
|
||||
*/
|
||||
function getGrandFinalDocsReminderTemplate(
|
||||
name: string,
|
||||
projectTitle: string,
|
||||
deadline: Date | null,
|
||||
uploadUrl: string,
|
||||
missing: string[],
|
||||
): EmailTemplate {
|
||||
const greeting = name ? `Hi ${name},` : 'Hi there,'
|
||||
const formattedDeadline = deadline
|
||||
? deadline.toLocaleString('en-GB', { timeZone: 'Europe/Paris', dateStyle: 'full', timeStyle: 'short' })
|
||||
: null
|
||||
const missingLine = missing.length
|
||||
? `Still needed: <strong>${escapeHtml(missing.join(', '))}</strong>.`
|
||||
: 'Please make sure all required documents are uploaded.'
|
||||
const content = `
|
||||
${sectionTitle('Grand Final — Final Documents')}
|
||||
${paragraph(greeting)}
|
||||
${paragraph(`Please upload the final documents for <strong>${escapeHtml(projectTitle)}</strong> ahead of the Monaco Ocean Protection Challenge Grand Finale.`)}
|
||||
${paragraph(missingLine)}
|
||||
${formattedDeadline ? infoBox(`Deadline: <strong>${escapeHtml(formattedDeadline)} (Paris time)</strong>.`, 'warning') : ''}
|
||||
${ctaButton(uploadUrl, 'Upload documents')}
|
||||
${paragraph('If you have any questions, please reach out to the MOPC team.')}
|
||||
`
|
||||
const text = [
|
||||
greeting, '',
|
||||
`Please upload the final documents for "${projectTitle}" ahead of the Grand Finale.`,
|
||||
missing.length ? `Still needed: ${missing.join(', ')}.` : 'Please make sure all required documents are uploaded.',
|
||||
formattedDeadline ? `Deadline: ${formattedDeadline} (Paris time).` : '',
|
||||
`Upload documents: ${uploadUrl}`, '', 'The MOPC team',
|
||||
].join('\n')
|
||||
return { subject: 'Action needed: upload your Grand Final documents', html: getEmailWrapper(content), text }
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification email sent to a team when their confirmed finalist slot is withdrawn by an admin.
|
||||
*/
|
||||
@@ -2685,6 +2721,14 @@ export const NOTIFICATION_EMAIL_TEMPLATES: Record<string, TemplateGenerator> = {
|
||||
new Date((ctx.metadata?.deadline as string) || Date.now()),
|
||||
ctx.linkUrl || '',
|
||||
),
|
||||
GRAND_FINAL_DOCS_REMINDER: (ctx) =>
|
||||
getGrandFinalDocsReminderTemplate(
|
||||
ctx.name || '',
|
||||
(ctx.metadata?.projectTitle as string) || 'Your project',
|
||||
ctx.metadata?.deadline ? new Date(ctx.metadata.deadline as string) : null,
|
||||
ctx.linkUrl || '',
|
||||
(ctx.metadata?.missing as string[]) || [],
|
||||
),
|
||||
FINALIST_WITHDRAWN: (ctx) =>
|
||||
getFinalistWithdrawnTemplate(
|
||||
ctx.name || '',
|
||||
|
||||
@@ -105,6 +105,8 @@ export const NotificationTypes = {
|
||||
FINALIST_WITHDRAWN: 'FINALIST_WITHDRAWN',
|
||||
TRAVEL_CONFIRMED: 'TRAVEL_CONFIRMED',
|
||||
VISA_STATUS_UPDATE: 'VISA_STATUS_UPDATE',
|
||||
GRAND_FINAL_DOCS_REMINDER: 'GRAND_FINAL_DOCS_REMINDER',
|
||||
GRAND_FINAL_DOCS_SUBMITTED: 'GRAND_FINAL_DOCS_SUBMITTED',
|
||||
} as const
|
||||
|
||||
export type NotificationType = (typeof NotificationTypes)[keyof typeof NotificationTypes]
|
||||
|
||||
Reference in New Issue
Block a user