reconnecting.tsx43 lines · main
1'use client';
2
3import { useEffect, useState } from 'react';
4
5/**
6 * Shown when apps/api is briefly unreachable — almost always the ~1–2 minute
7 * window while a deploy swaps containers. Instead of the hard "something
8 * broke" 500 boundary, we show a calm "reconnecting…" and auto-reload until
9 * the api answers again, at which point the dashboard renders normally.
10 */
11export function Reconnecting() {
12 const [secs, setSecs] = useState(5);
13
14 useEffect(() => {
15 const tick = setInterval(() => setSecs((s) => (s > 0 ? s - 1 : 0)), 1000);
16 const reload = setTimeout(() => window.location.reload(), 5000);
17 return () => {
18 clearInterval(tick);
19 clearTimeout(reload);
20 };
21 }, []);
22
23 return (
24 <main className="flex h-dvh flex-col items-center justify-center gap-4 bg-[var(--color-bg)] px-6 text-center text-[var(--color-text)]">
25 <div
26 aria-hidden
27 className="h-6 w-6 animate-spin rounded-full border-2 border-[var(--color-border)] border-t-[var(--color-primary)]"
28 />
29 <h1 className="font-mono text-lg">reconnecting…</h1>
30 <p className="max-w-sm font-mono text-sm text-[var(--color-text-muted)]">
31 briven is finishing a quick update. your data is safe — this page refreshes
32 itself in {secs}s.
33 </p>
34 <button
35 type="button"
36 onClick={() => window.location.reload()}
37 className="rounded-md border border-[var(--color-border)] px-4 py-2 font-mono text-xs text-[var(--color-text-muted)] transition hover:text-[var(--color-text)]"
38 >
39 retry now
40 </button>
41 </main>
42 );
43}