"use client"; import { useState } from "react"; import { cn } from "@/lib/utils"; import type { PokerSnapshot } from "@/app/(frontend)/minigames/poker/actions"; import { MIN_PLAYERS } from "@/lib/minigames/poker"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { PokerCardStyleProvider } from "./cardStyle"; import { PokerGameTable } from "./PokerGameTable"; import { RenameTableDialog } from "./RenameTableDialog"; import { usePokerPopups } from "./usePokerPopups"; import { usePokerSounds } from "./usePokerSounds"; import { seatPosition } from "./seatPosition"; interface PokerTableProps { readonly snapshot: PokerSnapshot | null; readonly currentUserId: number | string; readonly loading: boolean; readonly tableError: string | null; readonly onSnapshot: (snapshot: PokerSnapshot) => void; readonly onJoin: () => Promise; readonly onSpectate: () => Promise; readonly onStart: () => Promise; readonly onLeave: () => Promise; readonly onBack: () => void; readonly isSuperuser: boolean; readonly superuserIds: readonly number[]; } type SeatedSnapshot = PokerSnapshot & { readonly you: NonNullable; }; function isSeatedSnapshot(snapshot: PokerSnapshot): snapshot is SeatedSnapshot { return snapshot.you !== null; } function WaitingTable({ snapshot, currentUserId, onSnapshot, onJoin, onSpectate, onStart, onLeave, onBack, }: { readonly snapshot: PokerSnapshot; readonly currentUserId: number | string; readonly onSnapshot: (snapshot: PokerSnapshot) => void; readonly onJoin: () => Promise; readonly onSpectate: () => Promise; readonly onStart: () => Promise; readonly onLeave: () => Promise; readonly onBack: () => void; }) { const [starting, setStarting] = useState(false); const [leaving, setLeaving] = useState(false); const viewerSeat = snapshot.seats.findIndex((id) => String(id) === String(currentUserId)); const seated = viewerSeat >= 0; const full = snapshot.seats.length > 0 && snapshot.seats.every((id) => id !== null); const seatedCount = snapshot.seats.filter((id) => id !== null).length; const enoughPlayers = seatedCount >= MIN_PLAYERS; const isHost = seated && snapshot.hostSeatId === viewerSeat; const opponentCount = snapshot.seats.length - (seated ? 1 : 0); const start = async () => { setStarting(true); await onStart(); setStarting(false); }; const leave = async () => { setLeaving(true); await onLeave(); setLeaving(false); }; return (
{snapshot.name ?? `Table ${snapshot.tableId}`} {isHost && ( )}

{seated ? "You have a seat reserved." : "Join an open seat to receive a private hand view."}

Waiting room
{snapshot.seats.map((userId, seatId) => (
previousSeatId !== viewerSeat).length, opponentCount, ), userId !== null && "poker-waiting-seat-occupied", )} > Seat {seatId + 1} {userId === null ? "Open seat" : String(userId) === String(currentUserId) ? "You" : "Occupied"}
))}
Polaris Hold'em {seated ? "Waiting for the host to start" : "Open seating"}
{seated ? ( <> {isHost && ( )} ) : ( <> {snapshot.inGame && ( )} )}
); } function PokerTableInner({ snapshot, currentUserId, loading, tableError, onSnapshot, onJoin, onSpectate, onStart, onLeave, onBack, isSuperuser, superuserIds, }: PokerTableProps) { // Sound + popup transitions must live here, ABOVE the waiting/game split: // the hooks have to observe the waiting-room-to-first-hand transition, // which happens before the game table (and its seat view) mounts. const sound = usePokerSounds(snapshot); const { popups, actionLog } = usePokerPopups(snapshot); if (loading && !snapshot) { return ( ); } if (!snapshot) { return ( Table unavailable

{tableError ?? "This table could not be loaded."}

); } if (!isSeatedSnapshot(snapshot)) { return ( ); } return ( ); } export function PokerTable(props: PokerTableProps) { return ( ); }