"use client"; import type { CSSProperties } from "react"; import { useEffect, useRef, useState } from "react"; import type { BoardState } from "@/lib/protocol"; interface BoardProps { board: BoardState; onColumnClick?: (column: number) => void; disabled?: boolean; lastMove?: { column: number; row: number } | null; player1?: string; player2?: string; currentTurnColor?: 1 | 2 | null; } export default function Board({ board, onColumnClick, disabled = false, lastMove, player1, player2, currentTurnColor, }: BoardProps) { const [hoveredCol, setHoveredCol] = useState(null); const [animatingMove, setAnimatingMove] = useState<{ column: number; row: number; } | null>(null); const isFirstRender = useRef(true); const animationTimeoutRef = useRef(null); const canInteract = !disabled && !!onColumnClick; const lastMoveColumn = lastMove?.column ?? null; const lastMoveRow = lastMove?.row ?? null; useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; return; } if (animationTimeoutRef.current !== null) { window.clearTimeout(animationTimeoutRef.current); } if (lastMoveColumn === null || lastMoveRow === null) { setAnimatingMove(null); return; } setAnimatingMove({ column: lastMoveColumn, row: lastMoveRow }); animationTimeoutRef.current = window.setTimeout(() => { setAnimatingMove(null); animationTimeoutRef.current = null; }, 450); return () => { if (animationTimeoutRef.current !== null) { window.clearTimeout(animationTimeoutRef.current); } }; }, [lastMoveColumn, lastMoveRow]); return (
{/* Player legend */} {player1 && player2 && (
{currentTurnColor === 1 ? (
) : (
)} {player1}
vs
{currentTurnColor === 2 ? (
) : (
)} {player2}
)} {/* Board */}
{Array.from({ length: 7 }, (_, col) => (
canInteract && onColumnClick?.(col)} onMouseEnter={() => canInteract && setHoveredCol(col)} onMouseLeave={() => setHoveredCol(null)} > {/* Drop arrow indicator */}
{/* Cells (top row first) */} {Array.from({ length: 6 }, (_, rowIdx) => { const row = 5 - rowIdx; const cell = board[col][row]; const isLast = lastMove?.column === col && lastMove?.row === row; const isAnimatingDrop = animatingMove?.column === col && animatingMove?.row === row; const chipScale = isLast ? 1.1 : 1; const dropDistance = `${(5 - row) * 56 + 16}px`; return (
{cell !== 0 && (
)}
); })}
))}
{/* Column numbers */}
{Array.from({ length: 7 }, (_, col) => (
{col + 1}
))}
); }