import React, { useEffect, useMemo, useState } from 'react' import { collectDistinctSessionDurationsMinutes, EMPTY_FRAMEWORK_IMPORT_FILTERS, filterFrameworkPrograms, frameworkProgramOptionLabel, frameworkSessionDurationLabel, hasActiveFrameworkImportFilters, summarizeFrameworkImportFilters, } from '../../utils/frameworkProgramListHelpers' import { formatDurationDisplay } from '../../utils/trainingDurationUtils' /** * Modal: geplante Einheiten aus einem Trainingsrahmenprogramm (Blueprint-Slots) erzeugen. */ export default function TrainingPlanningFrameworkImportModal({ open, frameworkProgramsList, catalogFocusAreas = [], catalogTrainingTypes = [], catalogTargetGroups = [], fwImportProgramId, onProgramChange, fwImportLoading, fwImportDetail, fwImportSelectedSlots, onToggleSlot, fwImportSlotDates, onSlotDateChange, fwImportStartDate, onFwImportStartDateChange, fwImportIntervalDays, onFwImportIntervalDaysChange, fwImportSubmitting, onApplyDateSuggestions, onSubmit, onClose, }) { const [filters, setFilters] = useState(() => ({ ...EMPTY_FRAMEWORK_IMPORT_FILTERS })) const [filterPanelOpen, setFilterPanelOpen] = useState(true) useEffect(() => { if (!open) { setFilters({ ...EMPTY_FRAMEWORK_IMPORT_FILTERS }) setFilterPanelOpen(true) } }, [open]) const distinctDurations = useMemo( () => collectDistinctSessionDurationsMinutes(frameworkProgramsList), [frameworkProgramsList] ) const filteredPrograms = useMemo( () => filterFrameworkPrograms(frameworkProgramsList, filters), [frameworkProgramsList, filters] ) const filterActive = hasActiveFrameworkImportFilters(filters) const filterSummaryParts = useMemo( () => summarizeFrameworkImportFilters(filters, { focusAreas: catalogFocusAreas, trainingTypes: catalogTrainingTypes, targetGroups: catalogTargetGroups, }), [filters, catalogFocusAreas, catalogTrainingTypes, catalogTargetGroups] ) const totalCount = (frameworkProgramsList || []).length const matchCount = filteredPrograms.length useEffect(() => { if (!fwImportProgramId) return const stillVisible = filteredPrograms.some((p) => String(p.id) === String(fwImportProgramId)) if (!stillVisible) onProgramChange('') }, [filteredPrograms, fwImportProgramId, onProgramChange]) const selectedProgramSummary = useMemo(() => { if (!fwImportProgramId) return null return (frameworkProgramsList || []).find((p) => String(p.id) === String(fwImportProgramId)) }, [frameworkProgramsList, fwImportProgramId]) const updateFilter = (patch) => setFilters((prev) => ({ ...prev, ...patch })) const clearFilters = () => setFilters({ ...EMPTY_FRAMEWORK_IMPORT_FILTERS }) const toggleId = (key, id) => { const s = String(id) setFilters((prev) => { const cur = prev[key] || [] const next = cur.includes(s) ? cur.filter((x) => x !== s) : [...cur, s] return { ...prev, [key]: next } }) } if (!open) return null return (

Sessions aus Rahmen übernehmen

Wähle ein Trainingsrahmenprogramm und eine oder mehrere Sessions. Pro Session entsteht eine{' '} eigene geplante Einheit in der aktuellen Gruppe (Kopie des Ablaufs).

{matchCount} {' '} von {totalCount} Rahmenprogramm{totalCount === 1 ? '' : 'en'} {matchCount === 0 && totalCount > 0 ? ( — kein Treffer ) : null}
{filterActive ? ( Filter aktiv ) : null} {filterActive ? ( ) : null}
{!filterPanelOpen && filterActive && filterSummaryParts.length > 0 ? ( ) : null} {filterPanelOpen ? (
updateFilter({ query: e.target.value })} placeholder="z. B. Gürtel, Koordination …" disabled={fwImportSubmitting} />
Ziel-Session-Dauer
{[ { id: 'any', label: 'Alle' }, { id: 'range', label: 'Zeitspanne' }, { id: 'preset', label: 'Vorhandene Zeiten' }, ].map((opt) => ( ))}
{filters.durationMode === 'range' ? (
updateFilter({ durationMode: 'range', durationRangeFrom: e.target.value }) } placeholder="z. B. 60" disabled={fwImportSubmitting} />
updateFilter({ durationMode: 'range', durationRangeTo: e.target.value }) } placeholder="z. B. 90" disabled={fwImportSubmitting} />
) : null} {filters.durationMode === 'preset' ? ( distinctDurations.length === 0 ? (

In der Bibliothek sind noch keine Session-Dauern hinterlegt. Nutze „Zeitspanne“ oder lege Dauer pro Session im Rahmenprogramm fest.

) : (
{distinctDurations.map((min) => { const on = filters.durationPresetMin === min return ( ) })}
) ) : null}
{catalogFocusAreas.length > 0 ? (
Fokusbereich
{catalogFocusAreas.map((fa) => ( ))}
) : null} {catalogTrainingTypes.length > 0 ? (
Trainingsart
{catalogTrainingTypes.map((t) => ( ))}
) : null} {catalogTargetGroups.length > 0 ? (
Zielgruppe
{catalogTargetGroups.map((tg) => ( ))}
) : null}

Entwicklungsziele sind freie Texte — die Suche durchsucht auch Ziel-Titel. Bei der Dauer werden nur Programme mit hinterlegter Session-Dauer berücksichtigt.

) : null}
{selectedProgramSummary ? (

Session-Dauer: {frameworkSessionDurationLabel(selectedProgramSummary)} {selectedProgramSummary.goal_titles_agg ? ( <> {' '} · Ziele: {selectedProgramSummary.goal_titles_agg} ) : null}

) : null}
{fwImportLoading ? (

Laden der Sessions…

) : fwImportDetail?.slots?.length ? ( <>
Sessions (mit Ablauf)
    {[...fwImportDetail.slots] .sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0)) .map((slot) => { const hasBp = !!slot.blueprint_training_unit_id const checked = fwImportSelectedSlots.has(slot.id) const label = (slot.title || '').trim() || `Session ${(slot.sort_order ?? 0) + 1}` const slotDur = slot.planned_duration_min != null ? formatDurationDisplay(slot.planned_duration_min) : null return (
  • ) })}
onFwImportStartDateChange(e.target.value)} disabled={fwImportSubmitting} />
onFwImportIntervalDaysChange(parseInt(e.target.value, 10) || 0)} disabled={fwImportSubmitting} />
) : fwImportProgramId ? (

Keine Sessions in diesem Programm.

) : null}
) }