feat: poll evaluation scores every 30s and re-sort live
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m32s

The ranking dashboard now refetches roundEvaluationScores every 30
seconds. When a juror submits a new evaluation, the next refetch
updates the raw and balanced averages, and the existing re-sort
effect (now also keyed on snapshot + evalScores, not just the toggle)
re-orders the list in place. Manual reorders persisted on the
snapshot still take precedence — admins who have dragged rows aren't
overruled by score updates.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt
2026-04-27 14:05:40 +02:00
parent d0e7bfd60a
commit 90c53ef49f

View File

@@ -310,6 +310,7 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
const { data: evalScores } = trpc.ranking.roundEvaluationScores.useQuery(
{ roundId },
{ refetchInterval: 30_000 },
)
const { data: evalForm } = trpc.evaluation.getStageForm.useQuery(
@@ -464,9 +465,12 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
}
}, [snapshot, evalScores])
// ─── Re-sort on toggle flip (after init) ─────────────────────────────────
// ─── Re-sort when toggle flips OR scores refetch (after init) ────────────
// Only resorts when no server-side manual reorder is pinned for the snapshot;
// persisted manual reorders always win regardless of the score being used.
// The 30-second polling on roundEvaluationScores feeds this effect — when a
// juror submits a new evaluation, the next refetch picks it up, balanced/raw
// averages update, and the list re-sorts in place.
useEffect(() => {
if (!initialized.current || !snapshot || !evalScores) return
const reorders = (snapshot.reordersJson as Array<{
@@ -502,10 +506,7 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
STARTUP: sortedStartup.map((r) => r.projectId),
BUSINESS_CONCEPT: sortedConcept.map((r) => r.projectId),
})
// Eslint disable: snapshot/evalScores are read but the resort should only
// run on toggle flip, not on every snapshot/scores refetch.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [useBalanced])
}, [useBalanced, evalScores, snapshot])
// ─── numericCriteria from eval form ─────────────────────────────────────
const numericCriteria = useMemo(() => {