import React, { useEffect, useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { useNakama } from "./providers/NakamaProvider"; import getHaiku from "./utils/haikus"; export interface PlayerModel { user_id: string; username: string; index: number; metadata: Record; // e.g. { symbol: "X" } } interface BoardProps { board: string[][]; turn: number; winner: string | null; gameOver: boolean | null; players: PlayerModel[]; myUserId: string | null; onCellClick: (row: number, col: number) => void; } export default function Board({ board, turn, winner, gameOver, players, myUserId, onCellClick, }: BoardProps) { const myIndex = players.findIndex(p => p.user_id === myUserId); const gameReady = players.length === 2; const { matchId } = useNakama(); const mySymbol = myIndex !== null && players[myIndex] ? players[myIndex].metadata?.symbol ?? null : null; const opponentSymbol = myIndex !== null && players.length === 2 ? players[1 - myIndex].metadata?.symbol ?? null : null; const isMyTurn = gameReady && myIndex !== -1 && turn === myIndex; // ------------------------------- // STATUS // ------------------------------- let status; if (!gameReady) { status = "Waiting for opponent..."; } else if (winner) { status = `Winner: ${winner}`; } else if (gameOver) { status = `Draw!!!`; } else if (myIndex === -1) { status = "Spectating"; } else { status = isMyTurn ? "Your turn" : "Opponent's turn"; } const [haiku, setHaiku] = useState(getHaiku()); const [haikuIndex, setHaikuIndex] = useState(0); const nextLineIn = 3600; const allLinesStay = 2400; const allLinesFade = 1200; useEffect(() => { const totalTime = haiku.length * nextLineIn + allLinesStay + allLinesFade; const timer = setTimeout(() => { const next = getHaiku(); setHaiku(next); setHaikuIndex((i) => i + 1); }, totalTime); return () => clearTimeout(timer); }, [haikuIndex]); return ( <> {matchId && ( {status} {gameReady && mySymbol && ( You: {mySymbol} — Opponent:{" "} {opponentSymbol} )} {/* ------------------------- BOARD -------------------------- */} {board.map((row, rIdx) => row.map((cell, cIdx) => { const disabled = !!cell || !!winner || !gameReady || myIndex === -1 || !isMyTurn; return ( !disabled && onCellClick(rIdx, cIdx)} style={{ width: "80px", height: "80px", fontSize: "2rem", borderRadius: "10px", border: "2px solid #333", background: "#111", color: "white", cursor: disabled ? "not-allowed" : "pointer", display: "flex", alignItems: "center", justifyContent: "center", }} > {cell && ( {cell} )} ); }) )} {!winner && (
{haiku.map((line, i) => ( {line} ))}
)} {/* Winner pulse animation */} {winner && ( 🎉 {winner} Wins! 🎉 )}
)} ) }