- Refactored all components in src/components to: - Use arrow function components and prop destructuring - Add JSDoc for all exported components - Improve accessibility (aria-labels, roles, etc.) - Use correct key usage in lists - Add comments for non-obvious logic - Use modern event handler patterns and memoization where appropriate - Refactored src/pages/index.astro: - Removed <html>, <head>, and <body> (should be in layout) - Used semantic <main> for main content - Kept only necessary imports and markup - Refactored src/styles/index.css: - Removed duplicate rules - Ensured only global resets/utilities are present - Added comments for clarity - Ensured no component-specific styles are present - Used consistent formatting Brings the codebase in line with modern Astro and Preact best practices, improves maintainability, accessibility, and code clarity.
62 lines
2.9 KiB
JavaScript
62 lines
2.9 KiB
JavaScript
import { h } from 'preact';
|
|
import styles from './GameList.module.css';
|
|
|
|
/**
|
|
* List of games with filter and delete options.
|
|
* @param {object} props
|
|
* @param {object[]} props.games
|
|
* @param {string} props.filter
|
|
* @param {Function} props.setFilter
|
|
* @param {Function} props.onShowGameDetail
|
|
* @param {Function} props.onDeleteGame
|
|
* @returns {import('preact').VNode}
|
|
*/
|
|
const GameList = ({ games, filter = 'all', setFilter, onShowGameDetail, onDeleteGame }) => {
|
|
// Filter and sort games
|
|
const filteredGames = games
|
|
.filter(game => {
|
|
if (filter === 'active') return game.status === 'active';
|
|
if (filter === 'completed') return game.status === 'completed';
|
|
return true;
|
|
})
|
|
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
|
|
|
|
return (
|
|
<div className={styles['game-list'] + ' ' + styles['games-container']}>
|
|
<div className={styles['filter-buttons']}>
|
|
<button className={styles['filter-button'] + (filter === 'all' ? ' ' + styles['active'] : '')} onClick={() => setFilter('all')} aria-label="Alle Spiele anzeigen">Alle</button>
|
|
<button className={styles['filter-button'] + (filter === 'active' ? ' ' + styles['active'] : '')} onClick={() => setFilter('active')} aria-label="Nur aktive Spiele anzeigen">Aktiv</button>
|
|
<button className={styles['filter-button'] + (filter === 'completed' ? ' ' + styles['active'] : '')} onClick={() => setFilter('completed')} aria-label="Nur abgeschlossene Spiele anzeigen">Abgeschlossen</button>
|
|
</div>
|
|
{filteredGames.length === 0 ? (
|
|
<div className={styles['empty-state']}>Keine Spiele vorhanden</div>
|
|
) : (
|
|
filteredGames.map(game => {
|
|
const playerNames = game.player3
|
|
? `${game.player1} vs ${game.player2} vs ${game.player3}`
|
|
: `${game.player1} vs ${game.player2}`;
|
|
const scores = game.player3
|
|
? `${game.score1} - ${game.score2} - ${game.score3}`
|
|
: `${game.score1} - ${game.score2}`;
|
|
return (
|
|
<div
|
|
className={
|
|
styles['game-item'] + ' ' + (game.status === 'completed' ? styles['completed'] : styles['active'])
|
|
}
|
|
key={game.id}
|
|
>
|
|
<div className={styles['game-info']} onClick={() => onShowGameDetail(game.id)} role="button" tabIndex={0} aria-label={`Details für Spiel ${playerNames}`}>
|
|
<div className={styles['game-type']}>{game.gameType}{game.raceTo ? ` | ${game.raceTo}` : ''}</div>
|
|
<div className={styles['player-names']}>{playerNames}</div>
|
|
<div className={styles['game-scores']}>{scores}</div>
|
|
</div>
|
|
<button className={styles['delete-button']} onClick={() => onDeleteGame(game.id)} aria-label={`Spiel löschen: ${playerNames}`}></button>
|
|
</div>
|
|
);
|
|
})
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default GameList;
|