"use client"; import { useEffect, useRef } from "react"; import { useRouter } from "next/navigation"; import { getSocket } from "../lib/socket-client"; import { useGame, readSession, writeSession } from "../lib/store"; import type { ChatMsg, RoomState } from "../lib/types"; /** * Mounts once per room page tree. Connects to the socket and (re)joins the room * using a stored session token. Pushes room state into the Zustand store. */ export default function RoomConnector({ code }: { code: string }) { const router = useRouter(); const setRoom = useGame((s) => s.setRoom); const pushChat = useGame((s) => s.pushChat); const clearChat = useGame((s) => s.clearChat); const setMe = useGame((s) => s.setMe); const ranOnce = useRef(false); useEffect(() => { if (ranOnce.current) return; ranOnce.current = true; const socket = getSocket(); const session = readSession(code); const tryJoin = () => { socket.emit( "room:join", { code, nickname: session?.nickname || "Guest", avatar: session?.avatar || "🐱", sessionToken: session?.token, }, (resp: any) => { if (!resp || !resp.ok) { // No valid session — bounce to /join with code prefilled router.replace(`/join?code=${code}`); return; } writeSession(resp.code, { token: resp.sessionToken, nickname: session?.nickname || "Guest", avatar: session?.avatar || "🐱", playerId: resp.playerId, }); setMe(resp.playerId, resp.sessionToken); } ); }; if (socket.connected) tryJoin(); else socket.once("connect", tryJoin); const onState = (state: RoomState) => setRoom(state); const onChat = (m: ChatMsg) => pushChat(m); socket.on("room:state", onState); socket.on("chat:msg", onChat); return () => { socket.off("room:state", onState); socket.off("chat:msg", onChat); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [code]); // when leaving the room subtree clear local chat useEffect(() => { return () => clearChat(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return null; }