Files
bridzik/frontend/src/pages/Lobby.tsx
T
timandClaude Fable 5 b1010ae008 Frontend: pridavanie botov v lobby
Hostitel prida na volne sedadlo bota (+ Bot = heuristika, + AI bot =
natrenovana siet) alebo bota odoberie; boti maju vlastnu ikonu a flag
is_bot v rosteroch. Surove ucty bot:<kind>-<n> sa vsade zobrazuju cez
displayName ako "Bot 2" / "AI bot 1" (stol, kopka, tabulky, historia).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 18:51:14 +02:00

113 lines
4.6 KiB
TypeScript

import { useEffect, useRef, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useGameStore } from '../store/gameStore';
import { emit } from '../lib/socket';
import { leaveGame } from '../lib/leaveGame';
import { displayName } from '../lib/names';
export default function Lobby() {
const { gid } = useParams<{ gid: string }>();
const navigate = useNavigate();
const myPlayer = useGameStore((s) => s.myPlayer);
const games = useGameStore((s) => s.games);
const [showCopied, setShowCopied] = useState(false);
const copiedTimeout = useRef<ReturnType<typeof setTimeout>>();
const game = games.find((g) => g.gid === gid);
const players = game?.players ?? [];
const isHost = myPlayer?.order === 0;
const canStart = players.length === 4 && isHost;
const handleLeave = () => leaveGame(navigate);
const handleCopyCode = () => {
if (!gid) return;
navigator.clipboard.writeText(`${window.location.origin}/lobby/${gid}`);
setShowCopied(true);
clearTimeout(copiedTimeout.current);
copiedTimeout.current = setTimeout(() => setShowCopied(false), 1800);
};
useEffect(() => () => clearTimeout(copiedTimeout.current), []);
return (
<div className="max-w-md mx-auto p-4 pt-8 min-h-screen">
<div
className={`fixed top-4 left-1/2 -translate-x-1/2 px-4 py-2 rounded-lg bg-header border border-gold/30 text-gold text-sm shadow-lg transition-opacity duration-300 z-50 ${
showCopied ? 'opacity-100' : 'opacity-0 pointer-events-none'
}`}
>
Odkaz na hru skopírovaný
</div>
<div className="flex items-center justify-between mb-6">
<h1 className="font-serif text-2xl text-gold">{game?.name ?? 'Hra'}</h1>
<button onClick={handleLeave} className="text-sm text-green-dim hover:text-gold">
Odísť
</button>
</div>
<div className="bg-header border border-[#142018] rounded-xl p-4 mb-4 flex items-center justify-between">
<div>
<p className="text-xs uppercase tracking-[.1em] text-green-dim mb-1">Kód hry</p>
<p className="font-mono text-sm text-green-score break-all">{gid}</p>
</div>
<button
onClick={handleCopyCode}
className="ml-3 px-3 py-1 rounded-lg text-sm border border-gold/30 text-gold hover:bg-gold hover:text-table transition-colors"
>
Kopírovať URL
</button>
</div>
<div className="bg-header border border-[#142018] rounded-xl p-4 mb-6 flex flex-col gap-3">
{[0, 1, 2, 3].map((order) => {
const p = players.find((pl) => pl.order === order);
return (
<div key={order} className="flex items-center gap-3">
<span className={`text-lg ${p ? 'text-gold' : 'text-[#7a7058]'}`}>
{p ? (p.is_bot ? '⚙' : '✦') : '○'}
</span>
<span className={p ? 'font-serif text-green-score' : 'text-green-dim italic'}>
{p ? `${displayName(p.name)}${myPlayer?.order === p.order ? ' (ty)' : ''}` : 'Čaká sa…'}
</span>
{isHost && p?.is_bot && (
<button
onClick={() => gid && emit.removeBot(gid, order)}
className="ml-auto text-xs text-green-dim hover:text-gold"
>
Odobrať
</button>
)}
{isHost && !p && (
<span className="ml-auto flex gap-2">
<button
onClick={() => gid && emit.addBot(gid)}
className="px-2 py-0.5 rounded-lg text-xs border border-gold/30 text-gold hover:bg-gold hover:text-table transition-colors"
>
+ Bot
</button>
<button
onClick={() => gid && emit.addBot(gid, 'neural')}
className="px-2 py-0.5 rounded-lg text-xs border border-gold/30 text-gold hover:bg-gold hover:text-table transition-colors"
>
+ AI bot
</button>
</span>
)}
</div>
);
})}
</div>
<button
disabled={!canStart}
onClick={() => gid && emit.startGame(gid)}
className="w-full py-3 rounded-xl bg-gold text-table font-serif font-semibold text-lg disabled:opacity-40 disabled:cursor-default hover:bg-gold-bright transition-colors"
>
{isHost ? (canStart ? 'Začať hru' : `Čaká sa na hráčov (${players.length}/4)`) : 'Čaká sa na hostiteľa…'}
</button>
</div>
);
}