feat: Ergebnis-Banner, Dev-Simulations-Panel & Spiele-Reset
- MatchCard: farbiger Ergebnis-Banner (Exakt/Tendenz/Falsch) ersetzt tipRow, passender Card-Glow je Ergebnis; Lucide-Icons (lucide-react) - MatchCard: Ändern-Button links, vertikal mittig zur Tipp-Box ausgerichtet - DevPanel: Simulationsmodus mit User-Switcher, Zeit- & Status-Presets - DevPanel: Reset-Section mit "Spiel zurücksetzen", "Alle Spiele" und "Tipps löschen" (3 Buttons, farblich differenziert) - Backend: dev.ts mit set-time, set-status, reset-tips, reset-match - reset-match stellt Original-Datum wieder her (original_utc_date Spalte) - set-time sichert Original-Datum per COALESCE beim ersten Aufruf - Supabase Migration: original_utc_date TIMESTAMPTZ zu matches hinzugefügt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+56
-3
@@ -1,3 +1,4 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Routes, Route, NavLink } from 'react-router-dom';
|
||||
import MatchesPage from './pages/MatchesPage';
|
||||
import LeaderboardPage from './pages/LeaderboardPage';
|
||||
@@ -5,7 +6,47 @@ import ProfilePage from './pages/ProfilePage';
|
||||
import AdminPage from './pages/AdminPage';
|
||||
import styles from './App.module.css';
|
||||
|
||||
const IS_DEV = import.meta.env.DEV;
|
||||
|
||||
// Lazy-load DevPanel nur in Development
|
||||
let DevPanel: React.ComponentType<any> | null = null;
|
||||
if (IS_DEV) {
|
||||
// Dynamic import — kein Bundle-Impact in Production
|
||||
import('./components/DevPanel').then(m => { DevPanel = m.default; });
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [devUser, setDevUser] = useState(1);
|
||||
const [devMatches, setDevMatches] = useState<any[]>([]);
|
||||
const [refreshKey, setRefreshKey] = useState(0);
|
||||
|
||||
// DevUser als Query-Parameter im API-Fetch setzen
|
||||
useEffect(() => {
|
||||
if (!IS_DEV) return;
|
||||
// Patch fetch für Dev-Mode: devUser Query-Param anhängen
|
||||
const origFetch = window.fetch;
|
||||
window._devUser = devUser;
|
||||
window.fetch = (input, init) => {
|
||||
if (typeof input === 'string' && input.startsWith('/api')) {
|
||||
const url = new URL(input, window.location.origin);
|
||||
url.searchParams.set('devUser', String(window._devUser ?? 1));
|
||||
return origFetch(url.toString(), init);
|
||||
}
|
||||
return origFetch(input, init);
|
||||
};
|
||||
return () => { window.fetch = origFetch; };
|
||||
}, [devUser]);
|
||||
|
||||
// Matches für DevPanel laden
|
||||
useEffect(() => {
|
||||
if (!IS_DEV) return;
|
||||
fetch('/api/matches').then(r => r.json()).then(d => setDevMatches(d.matches ?? [])).catch(() => {});
|
||||
}, [refreshKey, devUser]);
|
||||
|
||||
function handleDevRefresh() {
|
||||
setRefreshKey(k => k + 1);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<header className={styles.header}>
|
||||
@@ -13,6 +54,9 @@ export default function App() {
|
||||
<div className={styles.logo}>
|
||||
<span className={styles.logoFlag}>🏆</span>
|
||||
<span className={styles.logoText}>WM 2026 Tippspiel</span>
|
||||
{IS_DEV && (
|
||||
<span className={styles.devBadge}>DEV · User {devUser}</span>
|
||||
)}
|
||||
</div>
|
||||
<nav className={styles.nav}>
|
||||
<NavLink to="/" end className={({ isActive }) => isActive ? styles.navLinkActive : styles.navLink}>
|
||||
@@ -33,12 +77,21 @@ export default function App() {
|
||||
|
||||
<main className={styles.main}>
|
||||
<Routes>
|
||||
<Route path="/" element={<MatchesPage />} />
|
||||
<Route path="/rangliste" element={<LeaderboardPage />} />
|
||||
<Route path="/profil" element={<ProfilePage />} />
|
||||
<Route path="/" element={<MatchesPage key={refreshKey} devUser={devUser} />} />
|
||||
<Route path="/rangliste" element={<LeaderboardPage key={refreshKey} />} />
|
||||
<Route path="/profil" element={<ProfilePage key={refreshKey} />} />
|
||||
<Route path="/admin" element={<AdminPage />} />
|
||||
</Routes>
|
||||
</main>
|
||||
|
||||
{IS_DEV && DevPanel && (
|
||||
<DevPanel
|
||||
currentUser={devUser}
|
||||
onUserChange={(u: number) => { setDevUser(u); setRefreshKey(k => k + 1); }}
|
||||
matches={devMatches}
|
||||
onRefresh={handleDevRefresh}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user