Add styled notification emails and round-attached notifications

- Add 15+ styled email templates matching existing invite email design
- Wire up notification triggers in all routers (assignment, round, project, mentor, application, onboarding)
- Add test email button for each notification type in admin settings
- Add round-attached notifications: admins can configure which notification to send when projects enter a round
- Fall back to status-based notifications when round has no configured notification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-04 00:10:51 +01:00
parent 3be6a743ed
commit b0189cad92
13 changed files with 1892 additions and 28 deletions

View File

@@ -6,7 +6,7 @@
*/
import { prisma } from '@/lib/prisma'
import { sendNotificationEmail } from '@/lib/email'
import { sendStyledNotificationEmail } from '@/lib/email'
// Notification priority levels
export type NotificationPriority = 'low' | 'normal' | 'high' | 'urgent'
@@ -218,7 +218,7 @@ export async function createNotification(
})
// Check if we should also send an email
await maybeSendEmail(userId, type, title, message, linkUrl)
await maybeSendEmail(userId, type, title, message, linkUrl, metadata)
}
/**
@@ -267,7 +267,7 @@ export async function createBulkNotifications(params: {
// Check email settings and send emails
for (const userId of userIds) {
await maybeSendEmail(userId, type, title, message, linkUrl)
await maybeSendEmail(userId, type, title, message, linkUrl, metadata)
}
}
@@ -373,7 +373,8 @@ async function maybeSendEmail(
type: string,
title: string,
message: string,
linkUrl?: string
linkUrl?: string,
metadata?: Record<string, unknown>
): Promise<void> {
try {
// Check if email is enabled for this notification type
@@ -396,16 +397,21 @@ async function maybeSendEmail(
return
}
// Send the email
const subject = emailSetting.emailSubject || title
const body = emailSetting.emailTemplate
? emailSetting.emailTemplate
.replace('{title}', title)
.replace('{message}', message)
.replace('{link}', linkUrl || '')
: message
await sendNotificationEmail(user.email, user.name || 'User', subject, body, linkUrl)
// Send styled email with full context
// The styled template will use metadata for rich content
// Subject can be overridden by admin settings
await sendStyledNotificationEmail(
user.email,
user.name || 'User',
type,
{
title,
message,
linkUrl,
metadata,
},
emailSetting.emailSubject || undefined
)
} catch (error) {
// Log but don't fail the notification creation
console.error('[Notification] Failed to send email:', error)