/** 홈 (PC 기준, docs/07-ui-ux.md §3.3): 큰 행동 줄 + 게임 격자 + 열린 공개 방. */ import { useEffect, useState } from 'react'; import { Link, useNavigate } from 'react-router'; import { CATALOG, formatRoomCode } from '@bg/shared/lite'; import { Sheet } from '../components/ui'; import { NicknameForm } from '../components/NicknameForm'; import { CodeInput } from '../components/CodeInput'; import { GameGrid } from '../components/GameGrid'; import { gameName } from '../components/GameNotice'; import { api } from '../net/api'; import { useSession } from '../store/session'; import { toast } from '../store/toast'; import { GAME_ICON, UPCOMING } from '../lib/catalog-ui'; export function Home() { const { me, activeRoom } = useSession(); const catalog = useSession((s) => (s.catalog.length ? s.catalog : CATALOG)); const nav = useNavigate(); const [picker, setPicker] = useState(false); const [needName, setNeedName] = useState void)>(null); const [busy, setBusy] = useState(false); const [rooms, setRooms] = useState<{ code: string; gameId: string; host: string; seated: number; max: number }[]>([]); const [codeKey, setCodeKey] = useState(0); const available = catalog.filter((g) => g.available); useEffect(() => { const load = () => api.allPublicRooms().then((r) => setRooms(r.rooms), () => {}); load(); const t = setInterval(load, 5000); return () => clearInterval(t); }, []); const withName = (fn: () => void) => (me ? fn() : setNeedName(() => fn)); const create = (gameId: string) => withName(async () => { setBusy(true); try { const { code } = await api.createRoom(gameId); nav(`/r/${code}`); } catch (e) { toast((e as Error).message, 'error'); } finally { setBusy(false); } }); const joinCode = async (code: string) => { try { await api.room(code); nav(`/r/${code}`); } catch (e) { toast((e as Error).message, 'error'); setCodeKey((k) => k + 1); } }; return (

{useSession.getState().siteName}

{activeRoom && ( ▶ 하던 게임으로 돌아가기 (방 {formatRoomCode(activeRoom)}) )}

친구랑 같이 하기

방을 만들면 코드와 링크가 바로 나와요. 친구에게 보내 주세요.

코드로 참여하기

받은 숫자 6자리를 넣으면 바로 들어가요.

게임 고르기

곧 나와요: {UPCOMING.join(' · ')}

{picker && ( setPicker(false)} label="게임 고르기">

어떤 게임을 할까요?

{available.map((g) => ( ))}
)} {needName && ( setNeedName(null)} label="이름 정하기">

먼저 이름을 정해 주세요

{ const fn = needName; setNeedName(null); fn(); }} />
)}
); }