diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 5767050..a7f2a0e 100644 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -33,5 +33,9 @@ else echo "==> Database already seeded ($USER_COUNT users found), skipping seed." fi +# Always sync notification email settings (upsert — safe for existing data) +echo "==> Syncing notification email settings..." +npx tsx prisma/seed-notification-settings.ts || echo "WARNING: Notification settings sync failed." + echo "==> Starting application..." exec node server.js diff --git a/prisma/seed-notification-settings.ts b/prisma/seed-notification-settings.ts index 8add7ad..deefc7f 100644 --- a/prisma/seed-notification-settings.ts +++ b/prisma/seed-notification-settings.ts @@ -90,6 +90,20 @@ const NOTIFICATION_EMAIL_SETTINGS = [ description: 'When multiple projects are assigned at once', sendEmail: true, }, + { + notificationType: 'COI_REASSIGNED', + category: 'jury', + label: 'COI Reassignment', + description: 'When a project is reassigned to you due to another juror\'s conflict of interest', + sendEmail: true, + }, + { + notificationType: 'MANUAL_REASSIGNED', + category: 'jury', + label: 'Manual Reassignment', + description: 'When an admin manually reassigns a project to you', + sendEmail: true, + }, { notificationType: 'ROUND_NOW_OPEN', category: 'jury', diff --git a/prisma/seed.ts b/prisma/seed.ts index ce1d287..95bbbd5 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -920,6 +920,8 @@ async function main() { { 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 }, + { notificationType: 'COI_REASSIGNED', category: 'jury', label: 'COI Reassignment', description: 'When a project is reassigned to you due to another juror\'s conflict of interest', sendEmail: true }, + { notificationType: 'MANUAL_REASSIGNED', category: 'jury', label: 'Manual Reassignment', description: 'When an admin manually reassigns a project to you', 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 }, diff --git a/src/components/forms/coi-declaration-dialog.tsx b/src/components/forms/coi-declaration-dialog.tsx index 37266ca..7344a04 100644 --- a/src/components/forms/coi-declaration-dialog.tsx +++ b/src/components/forms/coi-declaration-dialog.tsx @@ -20,7 +20,7 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select' -import { Loader2, ShieldAlert } from 'lucide-react' +import { AlertTriangle, Loader2, ShieldAlert } from 'lucide-react' import { toast } from 'sonner' interface COIDeclarationDialogProps { @@ -39,22 +39,31 @@ export function COIDeclarationDialog({ const [hasConflict, setHasConflict] = useState(null) const [conflictType, setConflictType] = useState('') const [description, setDescription] = useState('') + const [showConfirmation, setShowConfirmation] = useState(false) const declareCOI = trpc.evaluation.declareCOI.useMutation({ onSuccess: (data) => { if (data.hasConflict) { - toast.info('Conflict of interest recorded. An admin will review your declaration.') + toast.info('Conflict of interest recorded. This project will be reassigned to another juror.') } + setShowConfirmation(false) onComplete(data.hasConflict) }, onError: (error) => { toast.error(error.message || 'Failed to submit COI declaration') + setShowConfirmation(false) }, }) const handleSubmit = () => { if (hasConflict === null) return + // If declaring a conflict, show confirmation first + if (hasConflict && !showConfirmation) { + setShowConfirmation(true) + return + } + declareCOI.mutate({ assignmentId, hasConflict, @@ -71,91 +80,132 @@ export function COIDeclarationDialog({ return ( - - - - Conflict of Interest Declaration - - - Before evaluating “{projectTitle}”, please declare whether - you have any conflict of interest with this project. - - - -
-
- -
+ {showConfirmation ? ( + <> + + + + Confirm Conflict of Interest + + +
+

+ Are you sure you want to declare a conflict of interest with + “{projectTitle}”? +

+
+ This action cannot be undone. The project will be + removed from your assignments and reassigned to another juror. +
+
+
+
+ -
-
+ + + ) : ( + <> + + + + Conflict of Interest Declaration + + + Before evaluating “{projectTitle}”, please declare whether + you have any conflict of interest with this project. + + - {hasConflict && ( - <> -
- - -
- -
-