"use client"; import { useEffect, useState, useCallback, useMemo, use } from "react"; import { GroupId, GroupTable, Match, Team, ThirdPlaceRow } from "@/lib/types"; import { ThirdAssignment } from "@/lib/bracket"; import { getDictionary, Locale, Dictionary } from "@/lib/i18n"; import Groups from "./components/Groups"; import ThirdPlace from "./components/ThirdPlace"; import Bracket from "./components/Bracket"; import Fixtures from "./components/Fixtures"; import Simulation from "./components/Simulation"; import KoFixtures from "./components/KoFixtures"; interface ApiData { updatedAt: string; teams: Team[]; matches: Match[]; groupTables: GroupTable[]; groupTablesLive: GroupTable[]; thirdTable: ThirdPlaceRow[]; secureThirdTeams: string[]; annexAssignment: ThirdAssignment | null; annexResolved: boolean; } type Tab = "groups" | "groupfixtures" | "kofixtures" | "thirds" | "bracket" | "sim"; export default function Home({ params }: { params: Promise<{ locale: string }> }) { const { locale } = use(params) as { locale: Locale }; const dict = useMemo(() => getDictionary(locale), [locale]); const [data, setData] = useState(null); const [error, setError] = useState(null); const [tab, setTab] = useState("kofixtures"); // Zuletzt gewählte Gruppe für den Spiele-Tab. null = noch keine gewählt. const [fixturesGroup, setFixturesGroup] = useState(null); const load = useCallback(async () => { try { const res = await fetch(`/api/matches?locale=${locale}`, { cache: "no-store" }); if (!res.ok) { const body = await res.json().catch(() => ({})); throw new Error(body.detail || `Fehler ${res.status}`); } setData(await res.json()); setError(null); } catch (e) { setError(e instanceof Error ? e.message : "Verbindung fehlgeschlagen"); } }, [locale]); useEffect(() => { load(); const id = setInterval(load, 30_000); // alle 30 s aktualisieren return () => clearInterval(id); }, [load]); // Klick auf einen Gruppen-Header: Gruppe merken und zum Spiele-Tab wechseln. const openGroupFixtures = useCallback((g: GroupId) => { setFixturesGroup(g); setTab("groupfixtures"); }, []); const anyLive = data?.matches.some( (m) => m.status === "LIVE" || m.status === "IN_PLAY" || m.status === "PAUSED", ); return ( <>
WM 26 {dict.header.hostCountries}
{error ? dict.status.feedOffline : data ? anyLive ? dict.status.live : dict.status.updated(new Date(data.updatedAt).toLocaleTimeString(locale === "en" ? "en-US" : "de-DE")) : dict.status.loading}
{error && (
{dict.error.feedUnreachable}
)} {!data && !error && (
{Array.from({ length: 6 }).map((_, i) =>
)}
)} {data && tab === "kofixtures" && ( )} {data && tab === "groups" && ( )} {data && tab === "groupfixtures" && fixturesGroup && ( )} {data && tab === "thirds" && ( )} {data && tab === "bracket" && ( )} {data && tab === "sim" && ( )}
); }