import React, { useState, useEffect } from 'react' import { Link } from 'react-router-dom' import { CalendarCheck, ClipboardList, FilePenLine, Library } from 'lucide-react' import { useAuth } from '../context/AuthContext' import api from '../utils/api' import EmailVerificationBanner from '../components/EmailVerificationBanner' import DashboardTrainingVisibilityWidget from '../components/DashboardTrainingVisibilityWidget' function unitWhenLabel(u) { const d = u.planned_date ? String(u.planned_date).slice(0, 10) : '' const t = u.planned_time_start ? String(u.planned_time_start).slice(0, 5) : '' const bits = [d, t].filter(Boolean) return bits.length ? bits.join(' · ') : 'Termin' } function formatCappedCount(n, capped) { if (capped && n >= 1) return `${n}+` return String(n) } function Dashboard() { const [profile, setProfile] = useState(null) const [loading, setLoading] = useState(true) const [trainingHome, setTrainingHome] = useState(null) const [trainingHomeErr, setTrainingHomeErr] = useState(null) const [phase0Stats, setPhase0Stats] = useState(null) const [phase0Err, setPhase0Err] = useState(null) const { user } = useAuth() useEffect(() => { loadData() }, []) useEffect(() => { if (!user?.id) { setTrainingHome(null) setTrainingHomeErr(null) return undefined } let cancelled = false ;(async () => { setTrainingHomeErr(null) try { const today = new Date().toISOString().slice(0, 10) const [upcomingRaw, reviewPendingRaw, plannedPool] = await Promise.all([ api.listTrainingUnits({ assigned_to_me: true, status: 'planned', start_date: today, sort: 'asc', limit: 8, }), api.listTrainingUnits({ assigned_to_me: true, debrief_pending: true, sort: 'desc', limit: 8, }), api.listTrainingUnits({ assigned_to_me: true, status: 'planned', start_date: today, sort: 'asc', limit: 40, }), ]) const noteHits = (plannedPool || []).filter((u) => { const tn = (u.trainer_notes || '').trim() const n = (u.notes || '').trim() return Boolean(tn || n) }).slice(0, 5) if (!cancelled) { setTrainingHome({ upcoming: Array.isArray(upcomingRaw) ? upcomingRaw : [], reviewPending: Array.isArray(reviewPendingRaw) ? reviewPendingRaw : [], plannedWithNotes: noteHits, }) } } catch (e) { if (!cancelled) { console.error('Dashboard Trainingsübersicht:', e) setTrainingHomeErr(e.message || 'Konnte Trainingsdaten nicht laden') setTrainingHome(null) } } })() return () => { cancelled = true } }, [user?.id]) useEffect(() => { if (!user?.id) { setPhase0Stats(null) setPhase0Err(null) return undefined } let cancelled = false ;(async () => { setPhase0Err(null) try { const year = new Date().getFullYear() const yearStart = `${year}-01-01` const yearEnd = `${year}-12-31` const [draftList, mineList, ytdCompleted] = await Promise.all([ api.listExercises({ created_by_me: true, status: 'draft', limit: 100 }), api.listExercises({ created_by_me: true, limit: 100 }), api.listTrainingUnits({ assigned_to_me: true, status: 'completed', start_date: yearStart, end_date: yearEnd, limit: 250, sort: 'desc', }), ]) if (!cancelled) { const drafts = Array.isArray(draftList) ? draftList : [] setPhase0Stats({ year, draftCount: drafts.length, draftCapped: drafts.length >= 100, draftPreview: drafts.slice(0, 8).map((ex) => ({ id: ex.id, title: ex.title || `Übung #${ex.id}`, })), mineCount: Array.isArray(mineList) ? mineList.length : 0, mineCapped: Array.isArray(mineList) && mineList.length >= 100, ytdCompletedCount: Array.isArray(ytdCompleted) ? ytdCompleted.length : 0, ytdCapped: Array.isArray(ytdCompleted) && ytdCompleted.length >= 250, }) } } catch (e) { if (!cancelled) { console.error('Dashboard Übungs-Kennzahlen:', e) setPhase0Err(e.message || 'Konnte Übungs-Kennzahlen nicht laden') setPhase0Stats(null) } } })() return () => { cancelled = true } }, [user?.id]) const loadData = async () => { try { const profileData = await api.getCurrentProfile() setProfile(profileData) } catch (err) { console.error('Failed to load data:', err) } finally { setLoading(false) } } if (loading) { return (
Laden...
Willkommen, {user?.name || user?.email}! Shinkan unterstützt dich bei Übungen, Planung und Vereinsstruktur.
Trainings dieses Kalenderjahres beziehen sich auf den geplanten Termin (nicht zwingend Abschlussdatum). Zahlen können bei sehr vielen Einträgen mit „+“ enden.
{phase0Err}
) : null} {!phase0Err && !phase0Stats ? (Private Übungs-Entwürfe (z. B. aus der Planung) — Ziel, Durchführung und Details in der Bearbeitung ergänzen.
Alle Entwürfe in der Übersicht
Einheiten, bei denen du als Leitung oder Co-Trainer eingetragen bist.
{trainingHomeErr}
) : trainingHome?.upcoming?.length ? (Keine anstehenden Termine.{' '} Zur Trainingsplanung
)}{trainingHomeErr}
) : trainingHome?.plannedWithNotes?.length ? (Keine Vermerke in den nächsten geplanten Terminen.
)}{trainingHomeErr}
) : trainingHome?.reviewPending?.length ? (Keine durchgeführten Trainings mit offener Nachbereitung. Zum Abschluss der Rückschau in der Planung „Rückschau erledigt“ aktivieren.
)}