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 |
|
| # | 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 |
|
| 15 | Quality-Filter KI & Charts | TEILWEISE | Registry/Charts Confidence, kein durchgängiges Produkt |
|
||||||
| 21 | Universeller CSV-Parser + Mapping | OFFEN | Modul-spezifische Parser |
|
| 21 | Universeller CSV-Parser + Mapping | OFFEN | Modul-spezifische Parser |
|
||||||
| 25 | Ziele-System Goals | DONE? | GoalsPage, Router, Focus Areas |
|
| 25 | Ziele-System Goals | DONE? | GoalsPage, Router, Focus Areas |
|
||||||
|
|
@ -48,14 +48,11 @@
|
||||||
|
|
||||||
## Details je Issue (älteste zuerst)
|
## 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“.
|
**Gitea:** Issue **#14 geschlossen** (Kommentar + Close, Stand 2026-04).
|
||||||
|
|
||||||
**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.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState, useEffect } from 'react'
|
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 { Check, Brain } from 'lucide-react'
|
||||||
import {
|
import {
|
||||||
LineChart, Line, XAxis, YAxis, Tooltip,
|
LineChart, Line, XAxis, YAxis, Tooltip,
|
||||||
|
|
@ -252,8 +252,11 @@ function ComboChart({ weights, nutrition }) {
|
||||||
// ── Main Dashboard ────────────────────────────────────────────────────────────
|
// ── Main Dashboard ────────────────────────────────────────────────────────────
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const nav = useNavigate()
|
const nav = useNavigate()
|
||||||
|
const location = useLocation()
|
||||||
const { activeProfile } = useProfile()
|
const { activeProfile } = useProfile()
|
||||||
|
|
||||||
|
const [adminDeniedHint, setAdminDeniedHint] = useState(false)
|
||||||
|
|
||||||
const [stats, setStats] = useState(null)
|
const [stats, setStats] = useState(null)
|
||||||
const [weights, setWeights] = useState([])
|
const [weights, setWeights] = useState([])
|
||||||
const [calipers, setCalipers] = useState([])
|
const [calipers, setCalipers] = useState([])
|
||||||
|
|
@ -299,6 +302,14 @@ export default function Dashboard() {
|
||||||
|
|
||||||
useEffect(()=>{ load() },[])
|
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>
|
if (loading) return <div className="empty-state"><div className="spinner"/></div>
|
||||||
|
|
||||||
const latestCal = calipers[0]
|
const latestCal = calipers[0]
|
||||||
|
|
@ -349,6 +360,24 @@ export default function Dashboard() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dashboard-page">
|
<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 */}
|
{/* Header greeting */}
|
||||||
<div className="dashboard-greeting">
|
<div className="dashboard-greeting">
|
||||||
<h1 style={{fontSize:22,fontWeight:800,margin:0,color:'var(--text1)'}}>
|
<h1 style={{fontSize:22,fontWeight:800,margin:0,color:'var(--text1)'}}>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user