From cef4709444bccd86cb8ff6536c65dc0ae0e45cfc Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 17 Feb 2026 13:57:40 +0100 Subject: [PATCH] Auto-refresh jury dashboard every 30s for live round updates Add AutoRefresh client component that calls router.refresh() on an interval. Pauses when tab is hidden and refreshes immediately when tab becomes visible again. Jury dashboard now reflects round activations within seconds. Co-Authored-By: Claude Opus 4.6 --- src/app/(jury)/jury/page.tsx | 4 +++ src/components/shared/auto-refresh.tsx | 42 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/components/shared/auto-refresh.tsx diff --git a/src/app/(jury)/jury/page.tsx b/src/app/(jury)/jury/page.tsx index ccd2da0..c113d99 100644 --- a/src/app/(jury)/jury/page.tsx +++ b/src/app/(jury)/jury/page.tsx @@ -3,6 +3,7 @@ import { Suspense } from 'react' import Link from 'next/link' import { auth } from '@/lib/auth' import { prisma } from '@/lib/prisma' +import { AutoRefresh } from '@/components/shared/auto-refresh' export const metadata: Metadata = { title: 'Jury Dashboard' } export const dynamic = 'force-dynamic' @@ -744,6 +745,9 @@ export default async function JuryDashboardPage() { }> + + {/* Auto-refresh every 30s so voting round changes appear promptly */} + ) } diff --git a/src/components/shared/auto-refresh.tsx b/src/components/shared/auto-refresh.tsx new file mode 100644 index 0000000..2299df1 --- /dev/null +++ b/src/components/shared/auto-refresh.tsx @@ -0,0 +1,42 @@ +'use client' + +import { useEffect } from 'react' +import { useRouter } from 'next/navigation' + +/** + * Invisible client component that periodically calls router.refresh() + * to re-fetch server component data without a full page reload. + * Pauses when the tab is hidden to avoid unnecessary requests. + */ +export function AutoRefresh({ intervalMs = 30_000 }: { intervalMs?: number }) { + const router = useRouter() + + useEffect(() => { + let timer: ReturnType + + function start() { + timer = setInterval(() => { + router.refresh() + }, intervalMs) + } + + function handleVisibility() { + clearInterval(timer) + if (document.visibilityState === 'visible') { + // Refresh immediately when tab becomes visible again + router.refresh() + start() + } + } + + start() + document.addEventListener('visibilitychange', handleVisibility) + + return () => { + clearInterval(timer) + document.removeEventListener('visibilitychange', handleVisibility) + } + }, [router, intervalMs]) + + return null +}