From f24489b1e5ac9f7a36f2c0d369620cd90b2eec3e Mon Sep 17 00:00:00 2001 From: nessi Date: Sun, 2 Aug 2026 10:04:58 +0200 Subject: [PATCH] Convert AdminPanel to modal overlay with close button and add admin dashboard menu option Refactored AdminPanel from inline component to modal overlay triggered from user menu. Added `open` and `onClose` props to control visibility, wrapped panel in modal overlay with backdrop click-to-close behavior, and added close button to header. Implemented admin-only menu item in TopBar user dropdown with shield icon and role label. Added state management for dashboard visibility in App.jsx with proper cleanup --- frontend/src/App.jsx | 7 +++- frontend/src/components/AdminPanel.jsx | 44 +++++++++++++++++++------- frontend/src/components/TopBar.jsx | 22 +++++++++++-- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 45e91de..86383ee 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -61,6 +61,7 @@ export default function App() { const [chipOpen, setChipOpen] = useState(false); const [chipEntry, setChipEntry] = useState(null); const [userMenuOpen, setUserMenuOpen] = useState(false); + const [adminOpen, setAdminOpen] = useState(false); const [pwOpen, setPwOpen] = useState(false); const [pw1, setPw1] = useState(""); @@ -689,11 +690,15 @@ export default function App() { openPwModal={openPwModal} openDesignModal={openDesignModal} openStatsModal={openStatsModal} + openAdminPanel={() => { + setAdminOpen(true); + setUserMenuOpen(false); + }} doLogout={doLogout} onOpenNewGame={() => setNewGameOpen(true)} /> - {me.role === "admin" && } + setAdminOpen(false)} /> { - if (!open) return; + if (!dashboardOpen && !userModalOpen) return; const prev = document.body.style.overflow; document.body.style.overflow = "hidden"; @@ -23,7 +23,14 @@ export default function AdminPanel() { return () => { document.body.style.overflow = prev; }; - }, [open]); + }, [dashboardOpen, userModalOpen]); + + useEffect(() => { + if (!dashboardOpen) { + setUserModalOpen(false); + setMsg(""); + } + }, [dashboardOpen]); const loadUsers = async () => { const u = await api("/admin/users"); @@ -51,7 +58,7 @@ export default function AdminPanel() { setMsg("✅ User erstellt."); await loadUsers(); resetForm(); - setOpen(false); + setUserModalOpen(false); } catch (e) { setMsg("❌ Fehler: " + (e?.message || "unknown")); } @@ -68,17 +75,29 @@ export default function AdminPanel() { }; const closeModal = () => { - setOpen(false); + setUserModalOpen(false); setMsg(""); }; - return ( -
+ if (!dashboardOpen) return null; + + return createPortal( +
+
e.stopPropagation()} + > +
Admin Dashboard
- + +
@@ -125,7 +144,7 @@ export default function AdminPanel() { ))}
- {open && + {userModalOpen && createPortal(
e.stopPropagation()}> @@ -200,6 +219,9 @@ export default function AdminPanel() { document.body ) } -
+
+
+
, + document.body ); } diff --git a/frontend/src/components/TopBar.jsx b/frontend/src/components/TopBar.jsx index b0bfcb7..032d624 100644 --- a/frontend/src/components/TopBar.jsx +++ b/frontend/src/components/TopBar.jsx @@ -9,10 +9,13 @@ export default function TopBar({ openPwModal, openDesignModal, openStatsModal, + openAdminPanel, doLogout, onOpenNewGame, }) { const displayName = me ? ((me.display_name || "").trim() || me.email) : ""; + const isAdmin = me?.role === "admin"; + const roleLabel = isAdmin ? "Admin" : "User"; return (
@@ -31,8 +34,8 @@ export default function TopBar({ style={styles.userBtn} title="User Menü" > - 👤 - User + {isAdmin ? "🛡️" : "👤"} + {roleLabel} @@ -60,6 +63,21 @@ export default function TopBar({ Statistik + {isAdmin && ( + <> +
+ + + )} +