Files
bridzik/frontend/src/pages/GameList.tsx
T
timandClaude Fable 5 53274607b1 Donate stranka: PAY by square QR s vyberom sumy
Linka Na kavu v hlavicke lobby vedie na /donate. QR sa generuje
dynamicky (balicek bysquare) pre presety 1/2/5 EUR alebo vlastnu sumu;
IBAN sa da skopirovat do schranky. Navstevy loguje existujuci
pageview beacon.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:54:49 +02:00

109 lines
4.1 KiB
TypeScript

import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useGameStore } from '../store/gameStore';
import { emit, socket, setAuthToken } from '../lib/socket';
import { trackEvent } from '../lib/track';
import NameModal from '../components/NameModal';
import RulesModal from '../components/RulesModal';
export default function GameList() {
const navigate = useNavigate();
const games = useGameStore((s) => s.games);
const account = useGameStore((s) => s.account);
const [showCreate, setShowCreate] = useState(false);
const [showRules, setShowRules] = useState(false);
const handleShowRules = () => {
setShowRules(true);
trackEvent('rules_view');
};
const handleLogout = () => {
localStorage.removeItem('bridzik_token');
localStorage.removeItem('bridzik_player');
setAuthToken(null);
useGameStore.getState().logout();
// Drop the authenticated server-side session for this connection.
socket.disconnect();
socket.connect();
navigate('/auth', { replace: true });
};
return (
<div className="max-w-md mx-auto p-4 pt-8 min-h-screen">
<div className="flex items-center justify-between mb-6">
<h1 className="font-serif text-2xl text-gold tracking-wide">Bridžik</h1>
<div className="flex items-center gap-3 text-sm">
<span className="text-green-dim">{account?.username}</span>
<button onClick={() => navigate('/history')} className="text-gold hover:text-gold-bright">
História
</button>
<button onClick={() => navigate('/donate')} className="text-gold hover:text-gold-bright">
Na kávu
</button>
<button onClick={handleLogout} className="text-green-dim hover:text-gold">
Odhlásiť
</button>
</div>
</div>
<div className="flex flex-col gap-3 mb-6">
{games.length === 0 && (
<p className="text-center text-green-dim py-4">Žiadne hry. Vytvor prvú!</p>
)}
{games.map((g) => {
const full = g.players.length >= 4;
const isMember =
!!account && g.players.some((p) => p.player_id === account.player_id);
const canResume = g.started && isMember;
const unavailable = !canResume && (full || g.started);
const label = canResume ? 'Pokračovať' : full ? 'Plná' : g.started ? 'Začatá' : 'Vstúp';
return (
<div
key={g.gid}
className="flex items-center justify-between bg-header border border-[#142018] rounded-xl px-4 py-3"
>
<div>
<p className="font-serif text-green-score">{g.name}</p>
<p className="text-xs text-green-dim">
{g.players.length}/4 hráčov
{g.started ? ' · začatá' : ''}
</p>
</div>
<button
disabled={unavailable}
onClick={() => (canResume ? emit.rejoinGame(g.gid) : emit.registerPlayer(g.gid))}
className={`px-4 py-1.5 rounded-lg text-sm font-serif font-semibold disabled:opacity-40 disabled:cursor-default transition-colors ${
canResume
? 'bg-gold text-table hover:bg-gold-bright'
: 'border border-gold/40 text-gold hover:bg-gold hover:text-table'
}`}
>
{label}
</button>
</div>
);
})}
</div>
<button
onClick={() => setShowCreate(true)}
className="w-full py-2 rounded-xl bg-gold text-table font-serif font-semibold text-base mb-3 hover:bg-gold-bright transition-colors"
>
Vytvoriť novú hru
</button>
<button
onClick={handleShowRules}
className="w-full py-2 rounded-xl border border-gold/20 text-sm text-green-score hover:border-gold/50 transition-colors"
>
Pravidlá hry
</button>
{showRules && <RulesModal onClose={() => setShowRules(false)} />}
{showCreate && <NameModal onClose={() => setShowCreate(false)} />}
</div>
);
}