TypeScript 97.6%
SQL 1.4%
JavaScript 0.5%
1"use client";23import { useEffect, useState } from "react";4import { useRouter } from "next/navigation";5import { RefreshCw } from "lucide-react";6import { Button } from "@/components/ui";78const INTERVAL = 30;910/** Polls the API every 30 s and returns to the lobby as soon as it answers. */11export function MaintenanceRetry() {12 const router = useRouter();13 const [left, setLeft] = useState(INTERVAL);14 const [checking, setChecking] = useState(false);1516 const check = async () => {17 setChecking(true);18 try {19 const res = await fetch("/api/games", { cache: "no-store" });20 if (res.ok) {21 router.replace("/");22 return;23 }24 } catch {25 // still down26 } finally {27 setChecking(false);28 setLeft(INTERVAL);29 }30 };3132 useEffect(() => {33 const t = setInterval(() => {34 setLeft((n) => {35 if (n <= 1) {36 void check();37 return INTERVAL;38 }39 return n - 1;40 });41 }, 1000);42 return () => clearInterval(t);43 // eslint-disable-next-line react-hooks/exhaustive-deps44 }, []);4546 return (47 <div className="mt-8 flex flex-col items-center gap-3">48 <Button size="lg" variant="secondary" onClick={check} loading={checking}>49 <RefreshCw className="h-4 w-4" /> Check now50 </Button>51 <span className="text-[12px] tabular text-fg-4">Next automatic check in {left}s</span>52 </div>53 );54}55