feat: Add admin access denial alert to Dashboard with timeout handling
This commit is contained in:
parent
430a928df6
commit
bd694b30a6
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
| # | Titel (gekürzt) | Vorschlag | Notiz |
|
||||
|---|-----------------|-----------|--------|
|
||||
| 14 | Icon Picker Trainingstypen | OFFEN | Nur Freitext-Feld `icon` |
|
||||
| 14 | Icon Picker Trainingstypen | **ERLEDIGT** | `EmojiIconPicker` in `AdminTrainingTypesPage.jsx`; Gitea #14 geschlossen (2026-04) |
|
||||
| 15 | Quality-Filter KI & Charts | TEILWEISE | Registry/Charts Confidence, kein durchgängiges Produkt |
|
||||
| 21 | Universeller CSV-Parser + Mapping | OFFEN | Modul-spezifische Parser |
|
||||
| 25 | Ziele-System Goals | DONE? | GoalsPage, Router, Focus Areas |
|
||||
|
|
@ -48,14 +48,11 @@
|
|||
|
||||
## Details je Issue (älteste zuerst)
|
||||
|
||||
### #14 – [FEAT-001] Icon Picker für Trainingstypen
|
||||
### #14 – [FEAT-001] Icon Picker für Trainingstypen — **ERLEDIGT**
|
||||
|
||||
**Code-Stand:** `AdminTrainingTypesPage.jsx` nutzt ein **Textfeld** `icon` (frei, z. B. Emoji). Kein dedizierter Icon-Picker (Palette, Vorschau, Kategorien).
|
||||
**Code-Stand:** `AdminTrainingTypesPage.jsx` nutzt **`EmojiIconPicker`** (`frontend/src/components/EmojiIconPicker.jsx`) für Neu- und Bearbeiten-Dialoge; Wert bleibt String in `training_types.icon`.
|
||||
|
||||
**Vorschlag:** `OFFEN` – Issue beibehalten; optional präzisieren: „Emoji-Picker oder vordefinierte Icon-Liste statt Freitext“.
|
||||
|
||||
**Kommentar-Entwurf für Gitea:**
|
||||
> Stand Backend/Frontend: `icon` wird als String in `training_types` gespeichert, Eingabe ist Freitext. Icon-Picker-UX steht noch aus.
|
||||
**Gitea:** Issue **#14 geschlossen** (Kommentar + Close, Stand 2026-04).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useNavigate, useLocation } from 'react-router-dom'
|
||||
import { Check, Brain } from 'lucide-react'
|
||||
import {
|
||||
LineChart, Line, XAxis, YAxis, Tooltip,
|
||||
|
|
@ -252,8 +252,11 @@ function ComboChart({ weights, nutrition }) {
|
|||
// ── Main Dashboard ────────────────────────────────────────────────────────────
|
||||
export default function Dashboard() {
|
||||
const nav = useNavigate()
|
||||
const location = useLocation()
|
||||
const { activeProfile } = useProfile()
|
||||
|
||||
const [adminDeniedHint, setAdminDeniedHint] = useState(false)
|
||||
|
||||
const [stats, setStats] = useState(null)
|
||||
const [weights, setWeights] = useState([])
|
||||
const [calipers, setCalipers] = useState([])
|
||||
|
|
@ -299,6 +302,14 @@ export default function Dashboard() {
|
|||
|
||||
useEffect(()=>{ load() },[])
|
||||
|
||||
useEffect(() => {
|
||||
if (!location.state?.adminDenied) return
|
||||
setAdminDeniedHint(true)
|
||||
nav('.', { replace: true, state: null })
|
||||
const clear = window.setTimeout(() => setAdminDeniedHint(false), 8000)
|
||||
return () => window.clearTimeout(clear)
|
||||
}, [location.state, nav])
|
||||
|
||||
if (loading) return <div className="empty-state"><div className="spinner"/></div>
|
||||
|
||||
const latestCal = calipers[0]
|
||||
|
|
@ -349,6 +360,24 @@ export default function Dashboard() {
|
|||
|
||||
return (
|
||||
<div className="dashboard-page">
|
||||
{adminDeniedHint && (
|
||||
<div
|
||||
role="alert"
|
||||
style={{
|
||||
marginBottom: 14,
|
||||
padding: '12px 14px',
|
||||
borderRadius: 10,
|
||||
background: '#FCEBEB',
|
||||
border: '1px solid #D85A3033',
|
||||
fontSize: 13,
|
||||
color: '#D85A30',
|
||||
lineHeight: 1.5,
|
||||
}}
|
||||
>
|
||||
<strong>Kein Admin-Zugriff.</strong> Dieser Bereich ist nur für Konten mit Administrator-Rolle.
|
||||
Du wurdest zur Übersicht weitergeleitet.
|
||||
</div>
|
||||
)}
|
||||
{/* Header greeting */}
|
||||
<div className="dashboard-greeting">
|
||||
<h1 style={{fontSize:22,fontWeight:800,margin:0,color:'var(--text1)'}}>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user