"use client"; import { cn } from "@/lib/utils"; import type { Card, PublicPlayerView } from "@/lib/minigames/poker"; import type { PokerSnapshot } from "@/app/(frontend)/minigames/poker/actions"; import { Badge } from "@/components/ui/badge"; import { Card as UiCard, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { CardView } from "./CardView"; import { PokerActionConsole } from "./PokerActionConsole"; import { PokerActionToolbar } from "./PokerActionToolbar"; import { PokerClock } from "./PokerClock"; import { PokerDeckOrigin } from "./PokerDeckOrigin"; import { PokerPopupBubble } from "./PokerPopups"; import { PokerSeat } from "./PokerSeat"; import type { ActivePokerPopup } from "./usePokerPopups"; import { isTopSeatPosition, seatPosition } from "./seatPosition"; export type SeatedSnapshot = PokerSnapshot & { readonly you: NonNullable; }; export interface FeltCanvasActionProps { readonly starting: boolean; readonly leaving: boolean; readonly onStart: () => void; readonly onLeave: () => void; } interface PokerFeltCanvasProps { readonly snapshot: SeatedSnapshot; readonly onSnapshot: (snapshot: PokerSnapshot) => void; readonly handLabel: string | null; readonly handTier: number | null; readonly bestCardKeys: ReadonlySet; readonly actionProps: FeltCanvasActionProps; readonly onActionFeedback: () => void; readonly popups: readonly ActivePokerPopup[]; readonly fullscreen?: boolean; } function cardKey(card: Card): string { return `${card.rank}-${card.suit}`; } function signedAmount(value: number): string { return `${value >= 0 ? "+" : ""}${value.toLocaleString()}`; } function PlacementBoard({ view }: { readonly view: SeatedSnapshot["you"] }) { const placements = [...(view.finalPlacements ?? [])].sort((a, b) => a.placement - b.placement); return ( Final placements
    {placements.map((placement) => { const player = view.players.find((item) => item.seatId === placement.seatId); return (
  1. {placement.placement}. {player?.name ?? `Seat ${placement.seatId + 1}`} {player?.stack.toLocaleString() ?? "0"}
  2. ); })}
); } export function PokerFeltCanvas({ snapshot, onSnapshot, handLabel, handTier, bestCardKeys, actionProps, onActionFeedback, popups, fullscreen = false, }: PokerFeltCanvasProps) { const view = snapshot.you; const winnerSeats = new Set(view.showdown?.pots.flatMap((pot) => pot.winnerSeats) ?? []); const result = view.showdown?.results.find((item) => item.seatId === view.viewerSeat); const hasHint = handLabel !== null; const opponents = view.players.filter((player) => player.seatId !== view.viewerSeat); const viewerPlayer = view.players.find((player) => player.seatId === view.viewerSeat); const popupsForSeat = (seatId: number): readonly ActivePokerPopup[] => popups.filter((popup) => popup.seatId === seatId && popup.tone !== "leave"); const viewerPopups = popupsForSeat(view.viewerSeat); const tableAnnouncements = popups.filter((popup) => popup.tone === "leave"); return (
{opponents.map((player: PublicPlayerView, opponentIndex) => { const positionClass = seatPosition(opponentIndex, opponents.length); return (
{popupsForSeat(player.seatId).length > 0 && ( )}
{player.seatId === view.buttonSeat && ( D )} {player.seatId === view.smallBlindSeat && SB} {player.seatId === view.bigBlindSeat && BB}
); })}
Pot {view.potTotal.toLocaleString()}
{view.communityCards.length > 0 ? ( view.communityCards.map((card, index) => { const isBestCard = bestCardKeys.has(cardKey(card)); return ( ); }) ) : ( Community cards )}
{view.phase === "betting" && (
)} {(view.phase === "showdown" || view.phase === "hand-complete") && (

{view.phase === "showdown" ? "Showdown" : "Hand complete"}

{result ? `Your result: ${signedAmount(result.netChange)} chips` : "The hand is settled."}

{snapshot.nextHandAt && ( )}
)}
{view.phase !== "game-complete" && view.yourHoleCards.length > 0 && (
{view.yourHoleCards.map((card, index) => ( ))}
)} {viewerPopups.length > 0 && ( )} {tableAnnouncements.length > 0 && (
{tableAnnouncements.map((popup) => ( ))}
)} {view.phase === "game-complete" && (
)}
); }