import React, { useEffect, useState } from 'react' import { Link, useNavigate, useParams } from 'react-router-dom' import api from '../utils/api' import ExerciseRichTextBlock from '../components/ExerciseRichTextBlock' import ExerciseMediaEmbed from '../components/ExerciseMediaEmbed' import { formatSkillLevelSlug } from '../constants/skillLevels' function TagRow({ exercise }) { const tags = [] ;(exercise.focus_areas || []).forEach((f) => { tags.push({ key: `fa-${f.id}`, label: f.name, accent: !!f.is_primary }) }) ;(exercise.training_styles || []).forEach((t) => { tags.push({ key: `ts-${t.id}`, label: t.name, accent: false }) }) ;(exercise.training_types || []).forEach((t) => { tags.push({ key: `tt-${t.id}`, label: t.name, accent: false }) }) ;(exercise.target_groups || []).forEach((g) => { tags.push({ key: `tg-${g.id}`, label: g.name, accent: !!g.is_primary }) }) if (tags.length === 0) return null return (
{tags.map((t) => ( {t.label} ))}
) } function metaParts(exercise) { const parts = [] if (exercise.duration_min != null || exercise.duration_max != null) { const a = exercise.duration_min const b = exercise.duration_max if (a != null && b != null && a !== b) parts.push(`${a}–${b} Min.`) else if (a != null) parts.push(`ca. ${a} Min.`) else if (b != null) parts.push(`ca. ${b} Min.`) } if (exercise.group_size_min != null || exercise.group_size_max != null) { const a = exercise.group_size_min const b = exercise.group_size_max if (a != null && b != null && a !== b) parts.push(`Gruppe ${a}–${b}`) else if (a != null) parts.push(`Gruppe ab ${a}`) else if (b != null) parts.push(`Gruppe bis ${b}`) } return parts } function ExerciseDetailPage() { const { id } = useParams() const navigate = useNavigate() const [exercise, setExercise] = useState(null) const [error, setError] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { let cancelled = false const load = async () => { setLoading(true) setError(null) try { const data = await api.getExercise(id) if (!cancelled) setExercise(data) } catch (err) { if (!cancelled) setError(err) } finally { if (!cancelled) setLoading(false) } } if (id) load() return () => { cancelled = true } }, [id]) if (loading) { return (

Laden...

) } if (error) { const msg = error.message || String(error) return (

Übung

{msg}

) } if (!exercise) return null const meta = metaParts(exercise) const visibleMedia = (exercise.media || []).filter((m) => { const lc = String(m.asset_lifecycle_state || 'active').toLowerCase() return lc !== 'trash_hidden' }) return (
Bearbeiten

{exercise.title}

{exercise.summary && (
)}
{exercise.visibility} {exercise.status} {exercise.club_name && {exercise.club_name}}
{meta.length > 0 &&

{meta.join(' · ')}

}
{exercise.goal && (

Ziel

)} {(exercise.equipment || []).length > 0 && (

Material & Aufbau

)} {exercise.preparation && (

Vorbereitung

)} {exercise.execution && (

Ablauf

)} {visibleMedia.length > 0 && (

Medien

{visibleMedia.map((m) => (
{m.title || m.original_filename || m.media_type} {String(m.asset_lifecycle_state || 'active').toLowerCase() === 'trash_soft' && (

Hinweis: Dieses Medium ist im Papierkorb und steht künftig nicht mehr zur Verfügung.

)} {m.description &&

{m.description}

}
))}
)} {exercise.trainer_notes && (

Hinweise für Trainer

)} {(exercise.skills || []).length > 0 && (

Fähigkeiten

{exercise.skills.map((s) => { const rl = formatSkillLevelSlug(s.required_level) const tl = formatSkillLevelSlug(s.target_level) const lvl = rl || tl ? ` (${[rl, tl].filter(Boolean).join(' → ')})` : '' return ( {s.skill_name} {s.intensity ? ` · ${s.intensity}` : ''} {lvl} ) })}
)} {(exercise.variants || []).length > 0 && (

Varianten

{exercise.variants.map((v) => { const dur = v.duration_min != null || v.duration_max != null ? v.duration_min != null && v.duration_max != null && v.duration_min !== v.duration_max ? `${v.duration_min}–${v.duration_max} Min.` : v.duration_min != null ? `ca. ${v.duration_min} Min.` : `bis ca. ${v.duration_max} Min.` : null const diffLabel = v.difficulty_adjustment === 'easier' ? 'einfacher' : v.difficulty_adjustment === 'harder' ? 'schwerer' : v.difficulty_adjustment === 'same' ? 'gleiche Schwierigkeit' : v.difficulty_adjustment === 'adapted' ? 'angepasst' : null const equip = Array.isArray(v.equipment_changes) && v.equipment_changes.length > 0 ? v.equipment_changes.join(', ') : null return (
{v.variant_name} {(dur || diffLabel || equip || v.progression_level != null) && (
{[dur, diffLabel, equip && `Material: ${equip}`, v.progression_level != null && `Progression ${v.progression_level}`] .filter(Boolean) .join(' · ')}
)} {v.description &&

{v.description}

} {v.execution_changes && (
)}
) })}
)}
) } export default ExerciseDetailPage