8a46a8a019
- move reusable domain, data, state, ui code into src/lib - update host screens to consume new library exports - document architecture and configure path aliases - bump astro integration dependencies for compatibility Refs #30
63 lines
2.6 KiB
TypeScript
63 lines
2.6 KiB
TypeScript
import { h } from 'preact';
|
||
import modalStyles from '@lib/ui/Modal.module.css';
|
||
import styles from './GameCompletionModal.module.css';
|
||
import type { Game } from '@lib/domain/types';
|
||
|
||
interface GameCompletionModalProps {
|
||
open: boolean;
|
||
game: Game | null;
|
||
onConfirm: () => void;
|
||
onClose: () => void;
|
||
onRematch: () => void;
|
||
}
|
||
|
||
/**
|
||
* Modal shown when a game is completed.
|
||
*/
|
||
const GameCompletionModal = ({ open, game, onConfirm, onClose, onRematch }: GameCompletionModalProps) => {
|
||
if (!open || !game) return null;
|
||
|
||
const playerNames = [game.player1, game.player2, game.player3].filter(Boolean);
|
||
const scores = [game.score1, game.score2, game.score3].filter((_, i) => playerNames[i]);
|
||
let maxScore, winners, winnerText;
|
||
|
||
if (game.forfeitedBy) {
|
||
winnerText = `${game.winner} hat gewonnen, da ${game.forfeitedBy} aufgegeben hat.`;
|
||
} else {
|
||
maxScore = Math.max(...scores);
|
||
winners = playerNames.filter((name, idx) => scores[idx] === maxScore);
|
||
winnerText = winners.length > 1
|
||
? `Unentschieden zwischen ${winners.join(' und ')}`
|
||
: `${winners[0]} hat gewonnen!`;
|
||
}
|
||
|
||
return (
|
||
<div id="game-completion-modal" className={modalStyles['modal'] + ' ' + modalStyles['show']} role="dialog" aria-modal="true" aria-labelledby="completion-modal-title">
|
||
<div className={modalStyles['modal-content']}>
|
||
<div className={modalStyles['modal-header']}>
|
||
<span className={modalStyles['modal-title']} id="completion-modal-title">Spiel beendet</span>
|
||
<button className={modalStyles['close-button']} onClick={onClose} aria-label="Schließen">×</button>
|
||
</div>
|
||
<div className={modalStyles['modal-body']}>
|
||
<div className={styles['final-scores']}>
|
||
{playerNames.map((name, idx) => (
|
||
<div className={styles['final-score']} key={name + idx}>
|
||
<span className={styles['player-name']}>{name}</span>
|
||
<span className={styles['score']}>{scores[idx]}</span>
|
||
</div>
|
||
))}
|
||
</div>
|
||
<div className={styles['winner-announcement']}><h3>{winnerText}</h3></div>
|
||
|
||
</div>
|
||
<div className={modalStyles['modal-footer']}>
|
||
<button className={styles['btn'] + ' ' + styles['btn--warning']} onClick={onConfirm} aria-label="Bestätigen">Bestätigen</button>
|
||
<button className={styles['btn'] + ' ' + styles['btn--primary']} onClick={onRematch} aria-label="Rematch">Rematch</button>
|
||
<button className={styles['btn']} onClick={onClose} aria-label="Abbrechen">Abbrechen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default GameCompletionModal;
|