Add React frontend and clean up legacy HTTP backend

This commit is contained in:
tim
2026-06-15 22:20:56 +02:00
parent b8e2d15e27
commit beaf142ee4
40 changed files with 8328 additions and 437 deletions
+70
View File
@@ -0,0 +1,70 @@
import { useEffect } from 'react';
import { BrowserRouter, Routes, Route, Navigate, useNavigate } from 'react-router-dom';
import { useGameStore } from './store/gameStore';
import { socket, emit } from './lib/socket';
import type { MyPlayer } from './types';
import GameList from './pages/GameList';
import Lobby from './pages/Lobby';
import GameTable from './pages/GameTable';
function AppInner() {
const navigate = useNavigate();
const myPlayer = useGameStore((s) => s.myPlayer);
const gameStatus = useGameStore((s) => s.gameStatus);
const error = useGameStore((s) => s.error);
const clearError = useGameStore((s) => s.clearError);
// Reconnect on every socket connect event (handles auto-reconnects after network drops)
useEffect(() => {
const doReconnect = () => {
const saved = localStorage.getItem('bridzik_player');
if (!saved) return;
const player = JSON.parse(saved) as MyPlayer;
emit.reconnectToGame(player.gid, player.token);
};
socket.on('connect', doReconnect);
if (socket.connected) doReconnect();
return () => { socket.off('connect', doReconnect); };
}, []);
// Single authoritative navigation: derive target from store state
const targetRoute = myPlayer
? gameStatus ? `/game/${gameStatus.gid}` : `/lobby/${myPlayer.gid}`
: null;
useEffect(() => {
if (!targetRoute) return;
navigate(targetRoute, { replace: true });
}, [targetRoute, navigate]);
// Auto-dismiss errors after 4 s
useEffect(() => {
if (!error) return;
const t = setTimeout(clearError, 4000);
return () => clearTimeout(t);
}, [error, clearError]);
return (
<>
{error && (
<div className="fixed top-4 left-1/2 -translate-x-1/2 z-50 bg-red-600 text-white px-4 py-2 rounded-lg shadow-lg text-sm max-w-xs text-center">
{error}
</div>
)}
<Routes>
<Route path="/" element={<GameList />} />
<Route path="/lobby/:gid" element={<Lobby />} />
<Route path="/game/:gid" element={<GameTable />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</>
);
}
export default function App() {
return (
<BrowserRouter>
<AppInner />
</BrowserRouter>
);
}