Files
bscscore/src/components/GameList.jsx
Frank Schwenk 209df5d9f2 refactor: apply Astro, Preact, and general best practices to src
- 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.
2025-06-06 16:28:57 +02:00

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;