Admin UI audit round 2: fix 28 display bugs across 23 files
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m51s

HIGH fixes (broken features / wrong data):
- H1: Fix roundAssignments → projectRoundStates in project router (7 occurrences)
- H2: Fix deliberation results panel blank table (wrong field names)
- H3: Fix deliberation participant names blank (wrong data path)
- H4: Fix awards "Evaluated" stat duplicating "Eligible" count
- H5: Fix cross-round comparison enabled at 1 round (backend requires 2)
- H6: Fix setState during render anti-pattern (6 occurrences)
- H7: Fix round detail jury member count always showing 0
- H8: Remove 4 invalid status values from observer dashboard filter
- H9: Fix filtering progress bar always showing 100%

MEDIUM fixes (misleading display):
- M1: Filter special-award rounds from competition timeline
- M2: Exclude special-award rounds from distinct project count
- M3: Fix MENTORING pipeline node hardcoded "0 mentored"
- M4: Fix DELIB_LOCKED badge using red for success state
- M5: Add status label maps to deliberation session detail
- M6: Humanize deliberation category + tie-break method displays
- M8: Rename setStageId → setRoundId, "Select Stage" → "Select Round"
- M9: Add missing INVITED/ACTIVE/SUSPENDED to members status labels
- M10: Add ROUND_DRAFT/ACTIVE/CLOSED/ARCHIVED to StatusBadge
- M11: Fix unsent messages showing "Scheduled" instead of "Draft"
- M12: Rename misleading totalEvaluations → totalAssignments
- M13: Rename "Stage" column to "Program" in projects page

LOW fixes (cosmetic / edge-case):
- L1: Use unfiltered rounds array for active round detection
- L2: Use all rounds length for new round sort order
- L3: Filter special-award rounds from header count
- L4: Fix single-underscore replace in award status badges
- L5: Fix score bucket boundary gaps (4.99 dropped between buckets)
- L6: Title-case LIVE_FINAL pipeline metric status
- L7: Fix roundType.replace only replacing first underscore
- L8: Remove duplicate severity sort in smart-actions component

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt
2026-02-19 11:11:00 +01:00
parent ae1685179c
commit 51e18870b6
23 changed files with 170 additions and 111 deletions

View File

@@ -1,6 +1,6 @@
'use client'
import { useState } from 'react'
import { useState, useEffect } from 'react'
import Link from 'next/link'
import { trpc } from '@/lib/trpc/client'
import {
@@ -71,9 +71,11 @@ function ReportsOverview() {
// Project reporting scope (default: latest program, all rounds)
const [selectedValue, setSelectedValue] = useState<string | null>(null)
if (programs?.length && !selectedValue) {
setSelectedValue(`all:${programs[0].id}`)
}
useEffect(() => {
if (programs?.length && !selectedValue) {
setSelectedValue(`all:${programs[0].id}`)
}
}, [programs, selectedValue])
const scopeInput = parseSelection(selectedValue)
const hasScope = !!scopeInput.roundId || !!scopeInput.programId
@@ -109,7 +111,7 @@ function ReportsOverview() {
const activeRounds = dashStats?.activeRoundCount ?? rounds.filter((r: { status: string }) => r.status === 'ROUND_ACTIVE').length
const jurorCount = dashStats?.jurorCount ?? 0
const submittedEvaluations = dashStats?.submittedEvaluations ?? 0
const totalEvaluations = dashStats?.totalEvaluations ?? 0
const totalAssignments = dashStats?.totalAssignments ?? 0
const completionRate = dashStats?.completionRate ?? 0
return (
@@ -177,7 +179,7 @@ function ReportsOverview() {
<p className="text-sm font-medium text-muted-foreground">Evaluations</p>
<p className="text-2xl font-bold mt-1">{submittedEvaluations}</p>
<p className="text-xs text-muted-foreground mt-1">
{totalEvaluations > 0
{totalAssignments > 0
? `${completionRate}% completion rate`
: 'No assignments yet'}
</p>
@@ -417,9 +419,11 @@ function StageAnalytics() {
) || []
// Set default selected stage
if (rounds.length && !selectedValue) {
setSelectedValue(rounds[0].id)
}
useEffect(() => {
if (rounds.length && !selectedValue) {
setSelectedValue(rounds[0].id)
}
}, [rounds.length, selectedValue])
const queryInput = parseSelection(selectedValue)
const hasSelection = !!queryInput.roundId || !!queryInput.programId
@@ -701,9 +705,11 @@ function JurorConsistencyTab() {
((p.stages ?? []) as Array<{ id: string; name: string }>).map((s: { id: string; name: string }) => ({ id: s.id, name: s.name, programId: p.id, programName: `${p.year} Edition` }))
) || []
if (stages.length && !selectedValue) {
setSelectedValue(stages[0].id)
}
useEffect(() => {
if (stages.length && !selectedValue) {
setSelectedValue(stages[0].id)
}
}, [stages.length, selectedValue])
const queryInput = parseSelection(selectedValue)
const hasSelection = !!queryInput.roundId || !!queryInput.programId
@@ -773,9 +779,11 @@ function DiversityTab() {
((p.stages ?? []) as Array<{ id: string; name: string }>).map((s: { id: string; name: string }) => ({ id: s.id, name: s.name, programId: p.id, programName: `${p.year} Edition` }))
) || []
if (stages.length && !selectedValue) {
setSelectedValue(stages[0].id)
}
useEffect(() => {
if (stages.length && !selectedValue) {
setSelectedValue(stages[0].id)
}
}, [stages.length, selectedValue])
const queryInput = parseSelection(selectedValue)
const hasSelection = !!queryInput.roundId || !!queryInput.programId
@@ -846,7 +854,7 @@ function RoundPipelineTab() {
const { data: comparison, isLoading: comparisonLoading } =
trpc.analytics.getCrossRoundComparison.useQuery(
{ roundIds },
{ enabled: roundIds.length >= 1 }
{ enabled: roundIds.length >= 2 }
)
if (isLoading || comparisonLoading) {
@@ -929,9 +937,11 @@ export default function ReportsPage() {
((p.stages ?? []) as Array<{ id: string; name: string }>).map((s: { id: string; name: string }) => ({ id: s.id, name: s.name, programName: `${p.year} Edition` }))
) || []
if (pdfStages.length && !pdfStageId) {
setPdfStageId(pdfStages[0].id)
}
useEffect(() => {
if (pdfStages.length && !pdfStageId) {
setPdfStageId(pdfStages[0].id)
}
}, [pdfStages.length, pdfStageId])
const selectedPdfStage = pdfStages.find((r) => r.id === pdfStageId)