import React, { useEffect, useMemo, useState } from 'react' import { Link } from 'react-router-dom' import TrainingPlanExerciseVisibilityPanel from '../TrainingPlanExerciseVisibilityPanel' import TrainingUnitSectionsEditor from '../TrainingUnitSectionsEditor' import { activeClubMemberships } from '../../utils/activeClub' import { canDeleteLibraryContent } from '../../utils/libraryContentPermissions' import { frameworkLineageText } from '../../utils/trainingPlanningPageHelpers' /** * Großes Modal: Neue Trainingseinheit / Einheit bearbeiten (Planung, Trainer, Abschnitte, Durchführung, Notizen). */ export default function TrainingPlanningUnitFormModal({ open, editingUnit, formData, updateFormField, setFormData, onSubmit, onCancel, draftPlanTemplateId, onDraftTemplateSelect, planTemplates, onDeletePlanTemplate, clubDirectory, clubDirectoryForCo, planningModalClubId, user, onMetaRefresh, sectionsEditMode, setSectionsEditMode, onSaveAsTemplate, onRequestTrainingModulePick, onRequestExercisePick, onPeekExercise, }) { const [newTplVisibility, setNewTplVisibility] = useState('private') const [newTplClubId, setNewTplClubId] = useState('') const memberClubs = useMemo(() => activeClubMemberships(user?.clubs), [user?.clubs]) const roleLc = String(user?.role || '').toLowerCase() const isSuperadmin = roleLc === 'superadmin' useEffect(() => { if (!open) return if (planningModalClubId != null && planningModalClubId !== '') { setNewTplClubId(String(planningModalClubId)) } else if (memberClubs.length === 1) { setNewTplClubId(String(memberClubs[0].id)) } }, [open, planningModalClubId, memberClubs]) if (!open) return null return (

{editingUnit ? 'Trainingseinheit bearbeiten' : 'Neue Trainingseinheit'}

{editingUnit?.origin_framework_slot_id ? (() => { const L = frameworkLineageText(editingUnit) return (
Herkunft:{' '} {editingUnit.origin_framework_program_id ? ( {L.fpTitle} ) : ( L.fpTitle )} · {L.slotBit}

Inhalt stammt aus dem Session-Blueprint des Rahmenprogramms. Änderungen gelten nur für diese geplante Einheit; die Zuordnung zum Rahmen bleibt zur Nachverfolgung erhalten.

) })() : null} {!editingUnit && (

Übernimmt nur die Sektionsstruktur aus der Bibliothek; Übungen trägst du unten bei den Abschnitten ein. Gespeicherte Vorlagen kannst du unter Planung später erweitern.

)} {planTemplates.length > 0 && typeof onDeletePlanTemplate === 'function' ? (
Gespeicherte Vorlagen löschen

Entfernen nach Rolle: eigene private Vorlagen; Vereins­inhalte als Vereins­admin; offizielle nur als Plattform‑Admin. Einheiten mit Verweis behalten den Ablauf; die Vorlage wird entkoppelt.

    {planTemplates.map((t, ti) => { const canDel = user && canDeleteLibraryContent(user, t) return (
  • {t.name} ( {String(t.visibility || 'club').toLowerCase() === 'private' ? 'Privat' : String(t.visibility || 'club').toLowerCase() === 'official' ? 'Offiziell' : 'Verein'} ) {typeof t.sections_count === 'number' ? ( · {t.sections_count} Abschn. ) : null} {canDel ? ( ) : ( nur Lesen )}
  • ) })}
) : null}

Planung

updateFormField('planned_date', e.target.value)} required />
updateFormField('planned_time_start', e.target.value)} />
updateFormField('planned_time_end', e.target.value)} />
updateFormField('planned_focus', e.target.value)} placeholder="z.B. Grundlagen, Kinder altersgerecht" />

Trainerzuordnung (diese Einheit)

Für Vertretungen genügt in der Regel die Vereinsmitgliedschaft; Zuweisen dürfen u. a. Haupt-/Co‑Trainer dieser Gruppe, der/die Ersteller:in der Einheit oder Vereinsadmins.

{!formData.session_assistants_inherit ? (
{clubDirectoryForCo.map((m) => { const mid = typeof m.id === 'number' ? m.id : parseInt(String(m.id), 10) const labelText = `${(m.name || '').trim() || m.email || `Profil ${mid}`}` const isOn = Number.isFinite(mid) && formData.session_assistant_profile_ids.includes(mid) return ( ) })}
) : null} {!clubDirectory.length ? (

Keine Einträge im Vereins-Mitgliederverzeichnis oder noch nicht geladen (nur für Vereinsinterne).

) : null}
{editingUnit ? (
Ablauf bearbeiten als
{[ { id: 'planning', label: 'Planung' }, { id: 'debrief', label: 'Nachbereitung' }, ].map((opt, i) => ( ))}

{sectionsEditMode === 'debrief' ? 'Ist‑Minuten rechts in derselben Spaltenbreite wie „Min“ (Plan); Abweichungen als Text über die volle Breite.' : 'Ablauf, Übungen und geplante Minuten. Ist‑Werte und Abweichungen unter „Nachbereitung“.'}

) : null}
{newTplVisibility === 'club' ? (
) : null}
} sections={formData.sections} wideExerciseGrid onSectionsChange={(updater) => setFormData((prev) => ({ ...prev, sections: updater(prev.sections), })) } onRequestTrainingModulePick={onRequestTrainingModulePick} onRequestExercisePick={onRequestExercisePick} onPeekExercise={onPeekExercise} showExecutionExtras={Boolean(editingUnit) && sectionsEditMode === 'debrief'} enableParallelPhaseControls />
{editingUnit && ( <>

Durchführung

updateFormField('actual_date', e.target.value)} />
updateFormField('actual_time_start', e.target.value)} />
updateFormField('actual_time_end', e.target.value)} />
updateFormField('attendance_count', e.target.value)} />
{formData.status === 'completed' ? (
) : null} )}

Notizen