"use client"; import { useEffect } from "react"; import { useRouter } from "next/navigation"; import { GAME_EVENT_EVENT, GAME_TICK_EVENT, NOTIFICATION_EVENT, POKER_STATE_EVENT, POKER_TABLES_EVENT, POKER_TERMINATED_EVENT, PROFILE_UPDATE_EVENT, type GameTickDetail, type PokerStateDetail, type PokerTablesDetail, type PokerTerminatedDetail, type ProfileUpdateDetail, } from "@/hooks/useGameTick"; /** * Opens a Server-Sent Events connection to the game tick stream. * When a game tick completes, refreshes server-rendered data via * router.refresh() and dispatches a window event that client-side * components (e.g. ShipmentToasts, EventLedger) listen to for refetch. */ export function GameTickRealtime() { const router = useRouter(); useEffect(() => { const source = new EventSource("/api/realtime"); let refreshTimer: ReturnType | null = null; const refresh = (delay = 250) => { if (refreshTimer) return; refreshTimer = setTimeout(() => { refreshTimer = null; router.refresh(); }, delay); }; source.addEventListener("game-tick", (event) => { let detail: GameTickDetail = {}; try { detail = JSON.parse(event.data ?? "{}"); } catch { // ignore malformed payload } refresh(); window.dispatchEvent(new CustomEvent(GAME_TICK_EVENT, { detail })); }); source.addEventListener("profile-update", (event) => { let detail: ProfileUpdateDetail = {}; try { detail = JSON.parse(event.data ?? "{}"); } catch { // ignore malformed payload } refresh(detail.xpGained ? 1700 : 250); window.dispatchEvent(new CustomEvent(PROFILE_UPDATE_EVENT, { detail })); }); source.addEventListener("game-event", () => { refresh(); window.dispatchEvent(new CustomEvent(GAME_EVENT_EVENT)); }); source.addEventListener("notification", (event) => { window.dispatchEvent(new CustomEvent(NOTIFICATION_EVENT, { detail: event.data })); }); source.addEventListener("poker-state", (event) => { let detail: PokerStateDetail = {}; try { detail = JSON.parse(event.data ?? "{}"); } catch { // ignore malformed payload } window.dispatchEvent(new CustomEvent(POKER_STATE_EVENT, { detail })); }); source.addEventListener("poker-tables", (event) => { let detail: PokerTablesDetail = {}; try { detail = JSON.parse(event.data ?? "{}"); } catch { // ignore malformed payload } window.dispatchEvent(new CustomEvent(POKER_TABLES_EVENT, { detail })); }); source.addEventListener("poker-terminated", (event) => { let detail: PokerTerminatedDetail = {}; try { detail = JSON.parse(event.data ?? "{}"); } catch { // ignore malformed payload } window.dispatchEvent(new CustomEvent(POKER_TERMINATED_EVENT, { detail })); }); return () => { if (refreshTimer) clearTimeout(refreshTimer); source.close(); }; }, [router]); return null; }