'use client';
import React from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { Player } from '@/lib/types';
interface PlayerHandProps {
player: Player;
isCurrentPlayer: boolean;
selectedTileId: string | null;
onTileClick: (tileId: string) => void;
validTileIds: string[];
}
export function PlayerHand({
player,
isCurrentPlayer,
selectedTileId,
onTileClick,
validTileIds,
}: PlayerHandProps) {
return (
{player.name.charAt(0).toUpperCase()}
{player.name}
{player.tiles.length} tiles
{isCurrentPlayer && (
Your Turn
)}
{!player.isAI && (
{player.tiles.map((tile, index) => {
const isSelected = tile.id === selectedTileId;
const isPlayable = validTileIds.includes(tile.id);
return (
isPlayable && isCurrentPlayer && onTileClick(tile.id)}
className={`relative ${
isPlayable && isCurrentPlayer ? 'cursor-pointer' : 'cursor-not-allowed'
}`}
role="button"
tabIndex={isPlayable && isCurrentPlayer ? 0 : -1}
aria-label={`Tile ${tile.left}-${tile.right}${isSelected ? ' (selected)' : ''}${!isPlayable ? ' (cannot be played)' : ''}`}
aria-pressed={isSelected}
onKeyDown={(e) => {
if ((e.key === 'Enter' || e.key === ' ') && isPlayable && isCurrentPlayer) {
e.preventDefault();
onTileClick(tile.id);
}
}}
>
);
})}
)}
);
}
interface DominoTileSVGProps {
tile: { left: number; right: number; id: string };
isSelected: boolean;
isPlayable: boolean;
}
function DominoTileSVG({ tile, isSelected, isPlayable }: DominoTileSVGProps) {
const width = 60;
const height = 30;
return (
);
}
function renderDots(value: number, isSelected: boolean) {
const dotRadius = 2.5;
const margin = 6;
const fill = isSelected ? '#ffffff' : '#1f2937';
const positions = getDotPositions(value, margin);
return positions.map((pos, i) => (
));
}
function getDotPositions(value: number, margin: number): { x: number; y: number }[] {
const positions: { x: number; y: number }[] = [];
switch (value) {
case 0:
return [];
case 1:
positions.push({ x: 0, y: 0 });
break;
case 2:
positions.push({ x: -margin, y: -margin });
positions.push({ x: margin, y: margin });
break;
case 3:
positions.push({ x: -margin, y: -margin });
positions.push({ x: 0, y: 0 });
positions.push({ x: margin, y: margin });
break;
case 4:
positions.push({ x: -margin, y: -margin });
positions.push({ x: margin, y: -margin });
positions.push({ x: -margin, y: margin });
positions.push({ x: margin, y: margin });
break;
case 5:
positions.push({ x: -margin, y: -margin });
positions.push({ x: margin, y: -margin });
positions.push({ x: 0, y: 0 });
positions.push({ x: -margin, y: margin });
positions.push({ x: margin, y: margin });
break;
case 6:
positions.push({ x: -margin, y: -margin });
positions.push({ x: 0, y: -margin });
positions.push({ x: margin, y: -margin });
positions.push({ x: -margin, y: margin });
positions.push({ x: 0, y: margin });
positions.push({ x: margin, y: margin });
break;
}
return positions;
}