Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
'use client'
|
|
|
|
|
|
|
|
|
|
import { useParams } from 'next/navigation'
|
|
|
|
|
import Link from 'next/link'
|
|
|
|
|
import type { Route } from 'next'
|
|
|
|
|
import { trpc } from '@/lib/trpc/client'
|
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
|
|
|
import { Badge } from '@/components/ui/badge'
|
|
|
|
|
import { Button } from '@/components/ui/button'
|
|
|
|
|
import { Skeleton } from '@/components/ui/skeleton'
|
|
|
|
|
import { ArrowLeft, CheckCircle2, Clock, Circle } from 'lucide-react'
|
|
|
|
|
import { toast } from 'sonner'
|
|
|
|
|
|
|
|
|
|
export default function JuryRoundDetailPage() {
|
|
|
|
|
const params = useParams()
|
|
|
|
|
const roundId = params.roundId as string
|
|
|
|
|
|
|
|
|
|
const { data: assignments, isLoading } = trpc.roundAssignment.getMyAssignments.useQuery(
|
|
|
|
|
{ roundId },
|
2026-02-16 09:30:19 +01:00
|
|
|
{ enabled: !!roundId, refetchInterval: 30_000 }
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const { data: round } = trpc.round.getById.useQuery(
|
|
|
|
|
{ id: roundId },
|
2026-02-16 09:30:19 +01:00
|
|
|
{ enabled: !!roundId, refetchInterval: 30_000 }
|
Competition/Round architecture: full platform rewrite (Phases 1-9)
Replace Pipeline/Stage system with Competition/Round architecture.
New schema: Competition, Round (7 types), JuryGroup, AssignmentPolicy,
ProjectRoundState, DeliberationSession, ResultLock, SubmissionWindow.
New services: round-engine, round-assignment, deliberation, result-lock,
submission-manager, competition-context, ai-prompt-guard.
Full admin/jury/applicant/mentor UI rewrite. AI prompt hardening with
structured prompts, retry logic, and injection detection. All legacy
pipeline/stage code removed. 4 new migrations + seed aligned.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 23:04:15 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if (isLoading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<Skeleton className="h-8 w-64" />
|
|
|
|
|
<Skeleton className="h-64" />
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-6">
|
|
|
|
|
<div className="flex items-center gap-4">
|
|
|
|
|
<Button variant="ghost" size="sm" asChild>
|
|
|
|
|
<Link href={'/jury/competitions' as Route} aria-label="Back to competitions list">
|
|
|
|
|
<ArrowLeft className="mr-2 h-4 w-4" />
|
|
|
|
|
Back
|
|
|
|
|
</Link>
|
|
|
|
|
</Button>
|
|
|
|
|
<div>
|
|
|
|
|
<h1 className="text-2xl font-bold tracking-tight text-brand-blue dark:text-foreground">
|
|
|
|
|
{round?.name || 'Round Details'}
|
|
|
|
|
</h1>
|
|
|
|
|
<p className="text-muted-foreground mt-1">
|
|
|
|
|
Your assigned projects for this round
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle>Assigned Projects</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
{!assignments || assignments.length === 0 ? (
|
|
|
|
|
<div className="flex flex-col items-center justify-center py-8 text-center">
|
|
|
|
|
<Circle className="h-12 w-12 text-muted-foreground/50 mb-3" />
|
|
|
|
|
<p className="font-medium">No assignments yet</p>
|
|
|
|
|
<p className="text-sm text-muted-foreground mt-1">
|
|
|
|
|
You will see your assigned projects here once they are assigned
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
{assignments.map((assignment) => {
|
|
|
|
|
const isCompleted = assignment.evaluation?.status === 'SUBMITTED'
|
|
|
|
|
const isDraft = assignment.evaluation?.status === 'DRAFT'
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Link
|
|
|
|
|
key={assignment.id}
|
|
|
|
|
href={`/jury/competitions/${roundId}/projects/${assignment.projectId}` as Route}
|
|
|
|
|
className="flex items-center justify-between p-4 rounded-lg border border-border/60 hover:border-brand-blue/30 hover:bg-brand-blue/5 transition-all"
|
|
|
|
|
>
|
|
|
|
|
<div className="flex-1 min-w-0">
|
|
|
|
|
<p className="font-medium truncate">{assignment.project.title}</p>
|
|
|
|
|
<div className="flex items-center gap-2 mt-1 flex-wrap">
|
|
|
|
|
{assignment.project.competitionCategory && (
|
|
|
|
|
<Badge variant="secondary" className="text-xs">
|
|
|
|
|
{assignment.project.competitionCategory}
|
|
|
|
|
</Badge>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center gap-3 ml-4">
|
|
|
|
|
{isCompleted ? (
|
|
|
|
|
<Badge variant="default" className="bg-emerald-50 text-emerald-700 border-emerald-200">
|
|
|
|
|
<CheckCircle2 className="mr-1 h-3 w-3" />
|
|
|
|
|
Completed
|
|
|
|
|
</Badge>
|
|
|
|
|
) : isDraft ? (
|
|
|
|
|
<Badge variant="secondary" className="bg-amber-50 text-amber-700 border-amber-200">
|
|
|
|
|
<Clock className="mr-1 h-3 w-3" />
|
|
|
|
|
Draft
|
|
|
|
|
</Badge>
|
|
|
|
|
) : (
|
|
|
|
|
<Badge variant="outline">
|
|
|
|
|
<Circle className="mr-1 h-3 w-3" />
|
|
|
|
|
Pending
|
|
|
|
|
</Badge>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</Link>
|
|
|
|
|
)
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|