Add notification bell system and MOPC onboarding form
Notification System: - Add InAppNotification and NotificationEmailSetting database models - Create notification service with 60+ notification types for all user roles - Add notification router with CRUD endpoints - Build NotificationBell UI component with dropdown and unread count - Integrate bell into admin, jury, mentor, and observer navs - Add notification email settings admin UI in Settings > Notifications - Add notification triggers to filtering router (complete/failed) - Add sendNotificationEmail function to email library - Add formatRelativeTime utility function MOPC Onboarding Form: - Create /apply landing page with auto-redirect for single form - Create seed script for MOPC 2026 application form (6 steps) - Create seed script for default notification email settings Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
253
prisma/seed-notification-settings.ts
Normal file
253
prisma/seed-notification-settings.ts
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Seed script for notification email settings
|
||||
*
|
||||
* Run with: npx tsx prisma/seed-notification-settings.ts
|
||||
*/
|
||||
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
// Default notification email settings by category
|
||||
const NOTIFICATION_EMAIL_SETTINGS = [
|
||||
// Team / Applicant notifications
|
||||
{
|
||||
notificationType: 'APPLICATION_SUBMITTED',
|
||||
category: 'team',
|
||||
label: 'Application Submitted',
|
||||
description: 'When a team submits their application',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'TEAM_INVITE_RECEIVED',
|
||||
category: 'team',
|
||||
label: 'Team Invitation Received',
|
||||
description: 'When someone is invited to join a team',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'TEAM_MEMBER_JOINED',
|
||||
category: 'team',
|
||||
label: 'Team Member Joined',
|
||||
description: 'When a new member joins the team',
|
||||
sendEmail: false,
|
||||
},
|
||||
{
|
||||
notificationType: 'ADVANCED_SEMIFINAL',
|
||||
category: 'team',
|
||||
label: 'Advanced to Semi-Finals',
|
||||
description: 'When a project advances to semi-finals',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'ADVANCED_FINAL',
|
||||
category: 'team',
|
||||
label: 'Selected as Finalist',
|
||||
description: 'When a project is selected as a finalist',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'MENTOR_ASSIGNED',
|
||||
category: 'team',
|
||||
label: 'Mentor Assigned',
|
||||
description: 'When a mentor is assigned to the team',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'NOT_SELECTED',
|
||||
category: 'team',
|
||||
label: 'Not Selected',
|
||||
description: 'When a project is not selected for the next round',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'FEEDBACK_AVAILABLE',
|
||||
category: 'team',
|
||||
label: 'Feedback Available',
|
||||
description: 'When jury feedback becomes available',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'WINNER_ANNOUNCEMENT',
|
||||
category: 'team',
|
||||
label: 'Winner Announcement',
|
||||
description: 'When a project wins an award',
|
||||
sendEmail: true,
|
||||
},
|
||||
|
||||
// Jury notifications
|
||||
{
|
||||
notificationType: 'ASSIGNED_TO_PROJECT',
|
||||
category: 'jury',
|
||||
label: 'Assigned to Project',
|
||||
description: 'When a jury member is assigned to a project',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'BATCH_ASSIGNED',
|
||||
category: 'jury',
|
||||
label: 'Batch Assignment',
|
||||
description: 'When multiple projects are assigned at once',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'ROUND_NOW_OPEN',
|
||||
category: 'jury',
|
||||
label: 'Round Now Open',
|
||||
description: 'When a round opens for evaluation',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'REMINDER_24H',
|
||||
category: 'jury',
|
||||
label: 'Reminder (24h)',
|
||||
description: 'Reminder 24 hours before deadline',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'REMINDER_1H',
|
||||
category: 'jury',
|
||||
label: 'Reminder (1h)',
|
||||
description: 'Urgent reminder 1 hour before deadline',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'ROUND_CLOSED',
|
||||
category: 'jury',
|
||||
label: 'Round Closed',
|
||||
description: 'When a round closes',
|
||||
sendEmail: false,
|
||||
},
|
||||
{
|
||||
notificationType: 'AWARD_VOTING_OPEN',
|
||||
category: 'jury',
|
||||
label: 'Award Voting Open',
|
||||
description: 'When special award voting opens',
|
||||
sendEmail: true,
|
||||
},
|
||||
|
||||
// Mentor notifications
|
||||
{
|
||||
notificationType: 'MENTEE_ASSIGNED',
|
||||
category: 'mentor',
|
||||
label: 'Mentee Assigned',
|
||||
description: 'When assigned as mentor to a project',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'MENTEE_UPLOADED_DOCS',
|
||||
category: 'mentor',
|
||||
label: 'Mentee Documents Updated',
|
||||
description: 'When a mentee uploads new documents',
|
||||
sendEmail: false,
|
||||
},
|
||||
{
|
||||
notificationType: 'MENTEE_ADVANCED',
|
||||
category: 'mentor',
|
||||
label: 'Mentee Advanced',
|
||||
description: 'When a mentee advances to the next round',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'MENTEE_FINALIST',
|
||||
category: 'mentor',
|
||||
label: 'Mentee is Finalist',
|
||||
description: 'When a mentee is selected as finalist',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'MENTEE_WON',
|
||||
category: 'mentor',
|
||||
label: 'Mentee Won',
|
||||
description: 'When a mentee wins an award',
|
||||
sendEmail: true,
|
||||
},
|
||||
|
||||
// Observer notifications
|
||||
{
|
||||
notificationType: 'ROUND_STARTED',
|
||||
category: 'observer',
|
||||
label: 'Round Started',
|
||||
description: 'When a new round begins',
|
||||
sendEmail: false,
|
||||
},
|
||||
{
|
||||
notificationType: 'ROUND_COMPLETED',
|
||||
category: 'observer',
|
||||
label: 'Round Completed',
|
||||
description: 'When a round is completed',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'FINALISTS_ANNOUNCED',
|
||||
category: 'observer',
|
||||
label: 'Finalists Announced',
|
||||
description: 'When finalists are announced',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'WINNERS_ANNOUNCED',
|
||||
category: 'observer',
|
||||
label: 'Winners Announced',
|
||||
description: 'When winners are announced',
|
||||
sendEmail: true,
|
||||
},
|
||||
|
||||
// Admin notifications (in-app only by default)
|
||||
{
|
||||
notificationType: 'FILTERING_COMPLETE',
|
||||
category: 'admin',
|
||||
label: 'AI Filtering Complete',
|
||||
description: 'When AI filtering job completes',
|
||||
sendEmail: false,
|
||||
},
|
||||
{
|
||||
notificationType: 'FILTERING_FAILED',
|
||||
category: 'admin',
|
||||
label: 'AI Filtering Failed',
|
||||
description: 'When AI filtering job fails',
|
||||
sendEmail: true,
|
||||
},
|
||||
{
|
||||
notificationType: 'NEW_APPLICATION',
|
||||
category: 'admin',
|
||||
label: 'New Application',
|
||||
description: 'When a new application is received',
|
||||
sendEmail: false,
|
||||
},
|
||||
{
|
||||
notificationType: 'SYSTEM_ERROR',
|
||||
category: 'admin',
|
||||
label: 'System Error',
|
||||
description: 'When a system error occurs',
|
||||
sendEmail: true,
|
||||
},
|
||||
]
|
||||
|
||||
async function main() {
|
||||
console.log('Seeding notification email settings...')
|
||||
|
||||
for (const setting of NOTIFICATION_EMAIL_SETTINGS) {
|
||||
await prisma.notificationEmailSetting.upsert({
|
||||
where: { notificationType: setting.notificationType },
|
||||
update: {
|
||||
category: setting.category,
|
||||
label: setting.label,
|
||||
description: setting.description,
|
||||
},
|
||||
create: setting,
|
||||
})
|
||||
console.log(` - ${setting.label} (${setting.notificationType})`)
|
||||
}
|
||||
|
||||
console.log(`\nSeeded ${NOTIFICATION_EMAIL_SETTINGS.length} notification email settings.`)
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
Reference in New Issue
Block a user