import React from 'react' import { Link } from 'react-router-dom' import { Eye, Pencil, Trash2, Globe, Users, Lock, CheckCircle2, Archive, CircleDot, FilePenLine, } from 'lucide-react' import ExerciseRichTextBlock from '../ExerciseRichTextBlock' import { coerceApiNameList } from '../../utils/sanitizeHtml' import { canUserRequestExerciseDelete } from '../../utils/exercisePermissions' const VIS_LABELS = { official: 'Global', club: 'Verein', private: 'Privat' } const STATUS_LABELS = { draft: 'Entwurf', in_review: 'In Prüfung', approved: 'Freigegeben', archived: 'Archiv', } function visibilityLabel(v) { return VIS_LABELS[v] || v || '—' } function statusLabel(s) { return STATUS_LABELS[s] || s || '—' } function exerciseFocusNames(ex) { const fromApi = coerceApiNameList(ex.focus_area_names) if (fromApi.length) return fromApi if (ex.focus_area) return [ex.focus_area] return [] } function exerciseCardClassName(exercise, userId) { const vis = exercise.visibility || 'private' const visKey = vis === 'official' || vis === 'club' || vis === 'private' ? vis : 'private' const mine = userId != null && Number(exercise.created_by) === Number(userId) return ['card', 'exercise-card', `exercise-card--scope-${visKey}`, mine ? 'exercise-card--mine' : ''] .filter(Boolean) .join(' ') } function ExerciseCardScopeStatus({ exercise }) { const v = exercise.visibility || 'private' const s = exercise.status || 'draft' const visLabel = visibilityLabel(v) const stLabel = statusLabel(s) const tip = `${visLabel} · ${stLabel}` let VisIcon = Lock if (v === 'official') VisIcon = Globe else if (v === 'club') VisIcon = Users let StatIcon = FilePenLine if (s === 'approved') StatIcon = CheckCircle2 else if (s === 'archived') StatIcon = Archive else if (s === 'in_review') StatIcon = CircleDot return (
·
) } /** * Kartenzeile in der Übungsliste (Fokus/Planung — keine Virtualisierung im Grid, dafür content-visibility in app.css). */ export default function ExerciseListCard({ exercise, user, selectedIds, toggleSelect, onDelete }) { const focusNames = exerciseFocusNames(exercise) const styleNames = coerceApiNameList(exercise.style_direction_names) const typeNames = coerceApiNameList(exercise.training_type_names) return (
toggleSelect(exercise.id)} aria-label={`„${(exercise.title || 'Übung').replace(/"/g, '')}“ auswählen`} className="exercise-card-layout__check" />

{exercise.title}

{focusNames.map((name) => ( {name} ))} {styleNames.map((name) => ( {name} ))} {typeNames.map((name) => ( {name} ))} {(exercise.exercise_kind || '').toLowerCase().trim() === 'combination' ? ( Kombination ) : null}
{exercise.summary && String(exercise.summary).trim() ? (
) : null}
{canUserRequestExerciseDelete(user, exercise) ? ( ) : null}
) }