From 90c53ef49fab205e8ccf0d437f942aaae69259a6 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 27 Apr 2026 14:05:40 +0200 Subject: [PATCH] feat: poll evaluation scores every 30s and re-sort live MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/components/admin/round/ranking-dashboard.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/admin/round/ranking-dashboard.tsx b/src/components/admin/round/ranking-dashboard.tsx index fb9ec2b..f379afa 100644 --- a/src/components/admin/round/ranking-dashboard.tsx +++ b/src/components/admin/round/ranking-dashboard.tsx @@ -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(() => {