// frontend/src/App.jsx
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";
import DicePanel from "./components/Dice/DicePanel";
import "./AppLayout.css";
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);
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 (