diff --git a/apps/desktop/src/components/GameModal.tsx b/apps/desktop/src/components/GameModal.tsx new file mode 100644 index 0000000..55ff32a --- /dev/null +++ b/apps/desktop/src/components/GameModal.tsx @@ -0,0 +1,108 @@ +import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { useAuth } from '../context/AuthContext'; +import { useGame } from '../hooks/useGame'; +import { ConnectFourBoard } from './ConnectFourBoard'; +import { TicTacToeBoard } from './TicTacToeBoard'; +import { XIcon } from './icons'; + +interface Props { + gameId: string; + onClose: () => void; +} + +export function GameModal({ gameId, onClose }: Props) { + const { t } = useTranslation(); + const { game, loading, error, makeMove } = useGame(gameId); + const { session: auth } = useAuth(); + + useEffect(() => { + const onKey = (e: KeyboardEvent) => { + if (e.key === 'Escape') onClose(); + }; + window.addEventListener('keydown', onKey); + return () => window.removeEventListener('keydown', onKey); + }, [onClose]); + + const myUserId = auth?.user.id ?? null; + const myPlayerIdx: 0 | 1 | null = + !game || !myUserId + ? null + : game.players[0] === myUserId + ? 0 + : game.players[1] === myUserId + ? 1 + : null; + const isMyTurn = !!game && game.currentTurnUserId === myUserId; + const finished = !!game?.finishedAt; + const winnerIdx: 0 | 1 | null = + !game?.winnerUserId + ? null + : game.players[0] === game.winnerUserId + ? 0 + : game.players[1] === game.winnerUserId + ? 1 + : null; + const title = + game?.gameType === 'c4' + ? t('app:game.c4', { defaultValue: 'Vier-Gewinnt' }) + : t('app:game.ttt', { defaultValue: 'Tic-Tac-Toe' }); + + const statusLine = (() => { + if (loading) return t('app:game.loading', { defaultValue: 'Lädt…' }); + if (error) return error; + if (!game) return t('app:game.missing', { defaultValue: 'Spiel nicht gefunden.' }); + if (finished) { + if (winnerIdx === null) return t('app:game.draw', { defaultValue: 'Unentschieden!' }); + if (winnerIdx === myPlayerIdx) return t('app:game.you_win', { defaultValue: 'Du hast gewonnen!' }); + return t('app:game.you_lose', { defaultValue: 'Du hast verloren.' }); + } + if (myPlayerIdx === null) return t('app:game.spectator', { defaultValue: 'Du schaust nur zu.' }); + if (isMyTurn) return t('app:game.your_turn', { defaultValue: 'Du bist dran' }); + return t('app:game.opponent_turn', { defaultValue: 'Gegner ist dran…' }); + })(); + + return ( +