import React, { useState, useEffect, useMemo } 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 { getTenantClubDependencyKey } from '../utils/activeClub' import EmailVerificationBanner from '../components/EmailVerificationBanner' import DashboardTrainingVisibilityWidget from '../components/DashboardTrainingVisibilityWidget' import DashboardOrgInboxWidget from '../components/DashboardOrgInboxWidget' 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 [trainingHome, setTrainingHome] = useState(null) const [phase0Stats, setPhase0Stats] = useState(null) const [dashboardKpisErr, setDashboardKpisErr] = useState(null) const { user, loading: authLoading } = useAuth() const tenantClubDepKey = useMemo(() => getTenantClubDependencyKey(user), [user]) useEffect(() => { if (!user?.id) { setTrainingHome(null) setPhase0Stats(null) setDashboardKpisErr(null) return undefined } let cancelled = false ;(async () => { setDashboardKpisErr(null) try { const data = await api.getDashboardKpis() if (cancelled || !data || typeof data !== 'object') return const th = data.training_home && typeof data.training_home === 'object' ? data.training_home : {} setTrainingHome({ upcoming: Array.isArray(th.upcoming) ? th.upcoming : [], reviewPending: Array.isArray(th.review_pending) ? th.review_pending : [], plannedWithNotes: Array.isArray(th.planned_with_notes) ? th.planned_with_notes : [], }) setPhase0Stats({ year: data.year, draftCount: data.draft_count, draftCapped: Boolean(data.draft_capped), draftPreview: Array.isArray(data.draft_preview) ? data.draft_preview : [], mineCount: data.mine_count ?? 0, mineCapped: Boolean(data.mine_capped), ytdCompletedCount: data.ytd_completed_count ?? 0, ytdCapped: Boolean(data.ytd_capped), }) } catch (e) { if (!cancelled) { console.error('Dashboard KPIs / Trainingsübersicht:', e) setDashboardKpisErr(e.message || 'Konnte Dashboard-Daten nicht laden') setTrainingHome(null) setPhase0Stats(null) } } })() return () => { cancelled = true } }, [user?.id, tenantClubDepKey]) if (authLoading) { 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.
{dashboardKpisErr}
) : null} {!dashboardKpisErr && !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.
{dashboardKpisErr}
) : trainingHome?.upcoming?.length ? (Keine anstehenden Termine.{' '} Zur Trainingsplanung
)}{dashboardKpisErr}
) : trainingHome?.plannedWithNotes?.length ? (Keine Vermerke in den nächsten geplanten Terminen.
)}{dashboardKpisErr}
) : trainingHome?.reviewPending?.length ? (Keine durchgeführten Trainings mit offener Nachbereitung. Zum Abschluss der Rückschau in der Planung „Rückschau erledigt“ aktivieren.
)}