feat: add admin advancement summary card and advance column in assignments table

- Update listByStage query to include evaluation form criteriaJson and criterionScoresJson
- Add Advance column to individual assignments table showing YES/NO badge per submitted evaluation
- Create AdvancementSummaryCard component showing yes/no/pending vote counts with stacked bar
- Wire AdvancementSummaryCard into the EVALUATION round overview tab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 15:19:30 +01:00
parent 79bd4dbae7
commit c96f1b67a5
4 changed files with 126 additions and 3 deletions

View File

@@ -312,17 +312,18 @@ export function IndividualAssignmentsTable({
</p>
) : (
<div className="space-y-1 max-h-[500px] overflow-y-auto">
<div className="grid grid-cols-[1fr_1fr_100px_70px] gap-2 text-xs text-muted-foreground font-medium px-3 py-2 sticky top-0 bg-background border-b">
<div className="grid grid-cols-[1fr_1fr_80px_80px_70px] gap-2 text-xs text-muted-foreground font-medium px-3 py-2 sticky top-0 bg-background border-b">
<span>Juror</span>
<span>Project</span>
<span>Status</span>
<span>Advance</span>
<span>Actions</span>
</div>
{assignments.map((a: any, idx: number) => (
<div
key={a.id}
className={cn(
'grid grid-cols-[1fr_1fr_100px_70px] gap-2 items-center px-3 py-2 rounded-md text-sm transition-colors',
'grid grid-cols-[1fr_1fr_80px_80px_70px] gap-2 items-center px-3 py-2 rounded-md text-sm transition-colors',
idx % 2 === 1 ? 'bg-muted/20' : 'hover:bg-muted/20',
)}
>
@@ -349,6 +350,20 @@ export function IndividualAssignmentsTable({
</Badge>
)}
</div>
<div className="flex items-center justify-center">
{(() => {
const ev = a.evaluation
if (!ev || ev.status !== 'SUBMITTED') return <span className="text-muted-foreground text-xs"></span>
const criteria = (ev.form?.criteriaJson ?? []) as Array<{ id: string; type?: string }>
const scores = (ev.criterionScoresJson ?? {}) as Record<string, unknown>
const advCrit = criteria.find((c: any) => c.type === 'advance')
if (!advCrit) return <span className="text-muted-foreground text-xs"></span>
const val = scores[advCrit.id]
if (val === true) return <Badge variant="outline" className="text-[10px] bg-emerald-50 text-emerald-700 border-emerald-200">YES</Badge>
if (val === false) return <Badge variant="outline" className="text-[10px] bg-red-50 text-red-700 border-red-200">NO</Badge>
return <span className="text-muted-foreground text-xs"></span>
})()}
</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="h-7 w-7">