feat: semi-finalist tracker dashboard, account reminders, search + UX fixes
- Add getSemiFinalistStats query with per-category/per-award breakdown - Add sendAccountReminders mutation with invite token generation and dedup - Add SemiFinalistTracker dashboard widget with progress bars and remind buttons - Add ACCOUNT_REMINDER email template - Extend project search to match team member name/email (7 locations) - Fix Passed count deduplication: count distinct projects, not round-state rows - Fix role switcher: visible pills above user section, auto-refresh session on mount Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1959,6 +1959,32 @@ export function getEmailPreviewHtml(subject: string, body: string): string {
|
||||
return getEmailWrapper(content)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate "Account Setup Reminder" email template
|
||||
* Sent to semi-finalist team members who haven't set up their account yet.
|
||||
*/
|
||||
export function getAccountReminderTemplate(
|
||||
name: string,
|
||||
projectName: string,
|
||||
accountUrl: string,
|
||||
): EmailTemplate {
|
||||
const greeting = name ? `Hello ${name},` : 'Hello,'
|
||||
|
||||
const content = `
|
||||
${sectionTitle(greeting)}
|
||||
${paragraph(`Your project <strong>"${projectName}"</strong> has been selected as a semi-finalist in the Monaco Ocean Protection Challenge.`)}
|
||||
${infoBox('Please set up your account to access your applicant dashboard and stay up to date with the competition.', 'warning')}
|
||||
${ctaButton(accountUrl, 'Set Up Your Account')}
|
||||
${paragraph('If you have any questions, please contact the MOPC team.')}
|
||||
`
|
||||
|
||||
return {
|
||||
subject: `Action Required: Set up your MOPC account — "${projectName}"`,
|
||||
html: getEmailWrapper(content),
|
||||
text: `${greeting}\n\nYour project "${projectName}" has been selected as a semi-finalist in the Monaco Ocean Protection Challenge.\n\nPlease set up your account to access your applicant dashboard.\n\nSet up your account: ${getBaseUrl()}${accountUrl}\n\nIf you have any questions, please contact the MOPC team.\n\n---\nMonaco Ocean Protection Challenge\nTogether for a healthier ocean.`,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template registry mapping notification types to template generators
|
||||
*/
|
||||
@@ -2137,6 +2163,13 @@ export const NOTIFICATION_EMAIL_TEMPLATES: Record<string, TemplateGenerator> = {
|
||||
ctx.metadata?.accountUrl as string | undefined,
|
||||
),
|
||||
|
||||
ACCOUNT_REMINDER: (ctx) =>
|
||||
getAccountReminderTemplate(
|
||||
ctx.name || '',
|
||||
(ctx.metadata?.projectName as string) || 'Your Project',
|
||||
(ctx.metadata?.accountUrl as string) || '/accept-invite',
|
||||
),
|
||||
|
||||
// Admin templates
|
||||
NEW_APPLICATION: (ctx) =>
|
||||
getNewApplicationTemplate(
|
||||
|
||||
Reference in New Issue
Block a user