import type { Metadata } from 'next' import { Suspense } from 'react' import Link from 'next/link' import { auth } from '@/lib/auth' import { prisma } from '@/lib/prisma' export const metadata: Metadata = { title: 'Jury Dashboard' } export const dynamic = 'force-dynamic' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Progress } from '@/components/ui/progress' import { Skeleton } from '@/components/ui/skeleton' import { ClipboardList, CheckCircle2, Clock, AlertCircle, ArrowRight, } from 'lucide-react' import { formatDateOnly } from '@/lib/utils' import { CountdownTimer } from '@/components/shared/countdown-timer' async function JuryDashboardContent() { const session = await auth() const userId = session?.user?.id if (!userId) { return null } // Get all assignments for this jury member const assignments = await prisma.assignment.findMany({ where: { userId, }, include: { project: { select: { id: true, title: true, teamName: true, }, }, round: { select: { id: true, name: true, status: true, votingStartAt: true, votingEndAt: true, program: { select: { name: true, }, }, }, }, evaluation: { select: { id: true, status: true, submittedAt: true, }, }, }, orderBy: [ { round: { votingEndAt: 'asc' } }, { createdAt: 'asc' }, ], }) // Calculate stats const totalAssignments = assignments.length const completedAssignments = assignments.filter( (a) => a.evaluation?.status === 'SUBMITTED' ).length const inProgressAssignments = assignments.filter( (a) => a.evaluation?.status === 'DRAFT' ).length const pendingAssignments = totalAssignments - completedAssignments - inProgressAssignments const completionRate = totalAssignments > 0 ? (completedAssignments / totalAssignments) * 100 : 0 // Group assignments by round const assignmentsByRound = assignments.reduce( (acc, assignment) => { const roundId = assignment.round.id if (!acc[roundId]) { acc[roundId] = { round: assignment.round, assignments: [], } } acc[roundId].assignments.push(assignment) return acc }, {} as Record ) // Get grace periods for this user const gracePeriods = await prisma.gracePeriod.findMany({ where: { userId, extendedUntil: { gte: new Date() }, }, select: { roundId: true, extendedUntil: true, }, }) // Build a map of roundId -> latest extendedUntil const graceByRound = new Map() for (const gp of gracePeriods) { const existing = graceByRound.get(gp.roundId) if (!existing || gp.extendedUntil > existing) { graceByRound.set(gp.roundId, gp.extendedUntil) } } // Get active rounds (voting window is open) const now = new Date() const activeRounds = Object.values(assignmentsByRound).filter( ({ round }) => round.status === 'ACTIVE' && round.votingStartAt && round.votingEndAt && new Date(round.votingStartAt) <= now && new Date(round.votingEndAt) >= now ) return ( <> {/* Stats */}
Total Assignments
{totalAssignments}
Completed
{completedAssignments}
In Progress
{inProgressAssignments}
Pending
{pendingAssignments}
{/* Progress */} Overall Progress

{completedAssignments} of {totalAssignments} evaluations completed ( {completionRate.toFixed(0)}%)

{/* Active Rounds */} {activeRounds.length > 0 && ( Active Voting Rounds These rounds are currently open for evaluation {activeRounds.map(({ round, assignments: roundAssignments }) => { const roundCompleted = roundAssignments.filter( (a) => a.evaluation?.status === 'SUBMITTED' ).length const roundTotal = roundAssignments.length const roundProgress = roundTotal > 0 ? (roundCompleted / roundTotal) * 100 : 0 return (

{round.name}

{round.program.name}

Active
Progress {roundCompleted}/{roundTotal}
{round.votingEndAt && (
({formatDateOnly(round.votingEndAt)})
)}
) })}
)} {/* No active rounds message */} {activeRounds.length === 0 && totalAssignments > 0 && (

No active voting rounds

Check back later when a voting window opens

)} {/* No assignments message */} {totalAssignments === 0 && (

No assignments yet

You'll see your project assignments here once they're assigned

)} ) } function DashboardSkeleton() { return ( <>
{[...Array(4)].map((_, i) => ( ))}
) } export default async function JuryDashboardPage() { const session = await auth() return (
{/* Header */}

Dashboard

Welcome back, {session?.user?.name || 'Juror'}

{/* Content */} }>
) }