import React, { useCallback, useEffect, useMemo, useState } from 'react' import api from '../utils/api' import NavStateLink from '../components/NavStateLink' import { useAuth } from '../context/AuthContext' import { getTenantClubDependencyKey } from '../utils/activeClub' import { buildFrameworkProgramsListReturnContext } from '../utils/navReturnContext' function dashIfEmpty(val) { const s = (val ?? '').toString().trim() return s.length ? s : '—' } function FrameworkSummaryMeta({ r }) { const trainingTypes = typeof r.training_type_names_agg === 'string' ? r.training_type_names_agg.trim() : '' const targetGroups = typeof r.target_group_names_agg === 'string' ? r.target_group_names_agg.trim() : '' const styleDir = typeof r.style_direction_name === 'string' ? r.style_direction_name.trim() : '' const focus = typeof r.focus_area_name === 'string' ? r.focus_area_name.trim() : '' const rowStyle = { display: 'grid', gridTemplateColumns: 'minmax(6.5rem, 32%) 1fr', gap: '0.25rem 0.75rem', alignItems: 'start', marginTop: '0.35rem', lineHeight: 1.45, } return (
Fokusbereich
{dashIfEmpty(focus)}
{styleDir ? (
Stilrichtung
{styleDir}
) : null}
Trainingsarten
{trainingTypes.length ? trainingTypes : '—'}
Zielgruppen
{targetGroups.length ? targetGroups : '—'}
Kurzbeschreibung
{(r.description && String(r.description).trim()) || '—'}
) } export default function TrainingFrameworkProgramsListPage() { const { user } = useAuth() const tenantClubDepKey = useMemo(() => getTenantClubDependencyKey(user), [user]) const frameworkListReturn = useMemo(() => buildFrameworkProgramsListReturnContext(), []) const [rows, setRows] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const load = useCallback(async () => { setLoading(true) setError('') try { const list = await api.listTrainingFrameworkPrograms() setRows(Array.isArray(list) ? list : []) } catch (e) { setError(e.message || 'Laden fehlgeschlagen') setRows([]) } finally { setLoading(false) } }, []) useEffect(() => { load() }, [load, tenantClubDepKey]) async function handleDelete(id, title) { if (!confirm(`Rahmenprogramm „${title || id}“ wirklich löschen?`)) return try { await api.deleteTrainingFrameworkProgram(id) await load() } catch (e) { alert(e.message || 'Löschen fehlgeschlagen') } } return ( <>

Trainingsrahmenprogramme

Vorlagen für Ziele und Sessions — die Verknüpfung mit Gruppenterminen erfolgt in der Trainingsplanung (Registerkarte oben).

Mehr zur Übernahme in die Planung
Unter Planung wählst du eine Gruppe und übernimmst Slots aus einem Rahmenprogramm in echte Termine. So bleibt die Bibliothek wiederverwendbar, ohne dass Einzelgruppen fest verdrahtet sind.
Rahmenprogramm anlegen
{error && (
{error}
)} {loading ? (

Laden…

) : rows.length === 0 ? (

Noch kein Rahmenprogramm gespeichert. Lege ein neues an — mit Titel, mindestens einem Ziel und optional Slots samt Übungen.

Rahmenprogramm anlegen
) : ( )} ) }