import React, { useEffect, useRef, useState } from "react"; import { api } from "./api/client"; import { cycleTag } from "./utils/cycleTag"; import { getChipLS, setChipLS, clearChipLS } from "./utils/chipStorage"; import { useHpGlobalStyles } from "./styles/hooks/useHpGlobalStyles"; import { styles } from "./styles/styles"; import { applyTheme, DEFAULT_THEME_KEY } from "./styles/themes"; import { stylesTokens } from "./styles/theme"; import LoginPage from "./components/LoginPage"; import SheetSection from "./components/SheetSection"; import ChipModal from "./components/ChipModal"; export default function App() { useHpGlobalStyles(); // Auth/Login UI state const [me, setMe] = useState(null); const [loginEmail, setLoginEmail] = useState(""); const [loginPassword, setLoginPassword] = useState(""); const [showPw, setShowPw] = useState(false); // Game/Sheet state (minimal) const [games, setGames] = useState([]); const [gameId, setGameId] = useState(null); const [sheet, setSheet] = useState(null); const [pulseId, setPulseId] = useState(null); // Chip modal const [chipOpen, setChipOpen] = useState(false); const [chipEntry, setChipEntry] = useState(null); // Live refresh (optional) const aliveRef = useRef(true); const load = async () => { const m = await api("/auth/me"); setMe(m); const tk = m?.theme_key || DEFAULT_THEME_KEY; applyTheme(tk); const gs = await api("/games"); setGames(gs); // Auto-pick first game (kein UI dafür) if (gs[0] && !gameId) setGameId(gs[0].id); }; const reloadSheet = async () => { if (!gameId) return; const sh = await api(`/games/${gameId}/sheet`); setSheet(sh); }; // initial load useEffect(() => { aliveRef.current = true; (async () => { try { await load(); } catch { // ignore } })(); return () => { aliveRef.current = false; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // on game change useEffect(() => { (async () => { if (!gameId) return; try { await reloadSheet(); } catch { // ignore } })(); }, [gameId]); // Live refresh (nur Sheet) useEffect(() => { if (!me || !gameId) return; let alive = true; const tick = async () => { try { await reloadSheet(); } catch {} }; tick(); const id = setInterval(() => { if (!alive) return; tick(); }, 2500); return () => { alive = false; clearInterval(id); }; }, [me?.id, gameId]); // ===== Auth actions ===== const doLogin = async () => { await api("/auth/login", { method: "POST", body: JSON.stringify({ email: loginEmail, password: loginPassword }), }); await load(); }; // ===== Sheet actions (wie bisher) ===== const cycleStatus = async (entry) => { let next = 0; if (entry.status === 0) next = 2; else if (entry.status === 2) next = 1; else if (entry.status === 1) next = 3; else next = 0; await api(`/games/${gameId}/sheet/${entry.entry_id}`, { method: "PATCH", body: JSON.stringify({ status: next }), }); await reloadSheet(); setPulseId(entry.entry_id); setTimeout(() => setPulseId(null), 220); }; const toggleTag = async (entry) => { const next = cycleTag(entry.note_tag); if (next === "s") { setChipEntry(entry); setChipOpen(true); return; } if (next === null) clearChipLS(gameId, entry.entry_id); await api(`/games/${gameId}/sheet/${entry.entry_id}`, { method: "PATCH", body: JSON.stringify({ note_tag: next, chip: null }), }); await reloadSheet(); }; const chooseChip = async (chip) => { if (!chipEntry) return; const entry = chipEntry; setChipOpen(false); setChipEntry(null); setChipLS(gameId, entry.entry_id, chip); try { await api(`/games/${gameId}/sheet/${entry.entry_id}`, { method: "PATCH", body: JSON.stringify({ note_tag: "s", chip }), }); } finally { await reloadSheet(); } }; const closeChipModalToDash = async () => { if (!chipEntry) { setChipOpen(false); return; } const entry = chipEntry; setChipOpen(false); setChipEntry(null); clearChipLS(gameId, entry.entry_id); try { await api(`/games/${gameId}/sheet/${entry.entry_id}`, { method: "PATCH", body: JSON.stringify({ note_tag: null, chip: null }), }); } finally { await reloadSheet(); } }; const displayTag = (entry) => { const t = entry.note_tag; if (!t) return "—"; if (t === "s") { const chip = entry.chip || getChipLS(gameId, entry.entry_id); return chip ? `s.${chip}` : "s"; } return t; // i oder m }; // ===== Login page ===== if (!me) { return ( ); } const sections = sheet ? [ { key: "suspect", title: "VERDÄCHTIGE PERSON", entries: sheet.suspect || [] }, { key: "item", title: "GEGENSTAND", entries: sheet.item || [] }, { key: "location", title: "ORT", entries: sheet.location || [] }, ] : []; const PlaceholderCard = ({ title, hint }) => (
{title}
{hint}
); return (