import { useCallback, useEffect, useMemo, useState } from 'react' import { Link, Navigate } from 'react-router-dom' import { useAuth } from '../context/AuthContext' import api from '../utils/api' import AdminPageNav from '../components/AdminPageNav' const VISIBILITY_OPTIONS = [ { value: 'all', label: 'Alle Sichtbarkeiten' }, { value: 'private', label: 'Privat' }, { value: 'club', label: 'Verein' }, { value: 'official', label: 'Offiziell' }, ] const VISIBILITY_LABEL = { private: 'Privat', club: 'Verein', official: 'Offiziell', } const STATUS_LABELS = { draft: 'Entwurf', in_review: 'In Prüfung', approved: 'Freigegeben', archived: 'Archiviert', active: 'Aktiv', legacy_unreviewed: 'Rechte ungeprüft', declared: 'Rechte erklärt', blocked: 'Gesperrt', } const LIFECYCLE_LABELS = { active: 'Aktiv', trash_soft: 'Papierkorb (soft)', trash_hidden: 'Papierkorb (hidden)', } function formatDate(value) { if (!value) return '—' try { return new Date(value).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }) } catch { return String(value) } } function contentLink(item) { const id = item.id switch (item.content_type) { case 'exercise': return `/exercises/${id}` case 'training_module': return `/planning/training-modules/${id}` case 'framework_program': return `/planning/framework-programs/${id}` case 'plan_template': return `/planning/plan-templates/${id}` case 'maturity_model': return '/admin/maturity-models' case 'media_asset': return '/media' default: return null } } function statusOptionsForType(meta, contentType) { const t = meta?.content_types?.find((x) => x.id === contentType) return (t?.status_values || []).map((v) => ({ value: v, label: STATUS_LABELS[v] || v, })) } function EditModal({ open, item, meta, onClose, onSaved }) { const [status, setStatus] = useState('') const [visibility, setVisibility] = useState('') const [lifecycle, setLifecycle] = useState('') const [saving, setSaving] = useState(false) const [error, setError] = useState('') useEffect(() => { if (!item) return setStatus(item.status || '') setVisibility(item.visibility || '') setLifecycle(item.extra_status || 'active') setError('') }, [item]) if (!open || !item) return null const typeMeta = meta?.content_types?.find((x) => x.id === item.content_type) const statusOpts = statusOptionsForType(meta, item.content_type) const submit = async () => { setSaving(true) setError('') try { const body = {} if (typeMeta?.has_status && status && status !== item.status) body.status = status if (typeMeta?.has_visibility && visibility && visibility !== item.visibility) { body.visibility = visibility } if (item.content_type === 'media_asset' && lifecycle && lifecycle !== item.extra_status) { body.lifecycle_state = lifecycle } if (!Object.keys(body).length) { onClose() return } await api.patchAdminUserContentItem(item.content_type, item.id, body) await onSaved() onClose() } catch (e) { setError(e.message || String(e)) } finally { setSaving(false) } } return (
{item.type_label} · #{item.id}
{item.title || '—'}
{typeMeta?.has_status ? ({error}
) : null}Aktivitäten aller Nutzer einsehen — inklusive privater Inhalte. Status setzen oder Inhalte löschen (nur Superadmin).
{error}
Noch keine nutzerangelegten Inhalte.
) : (| Nutzer | Gesamt | {(meta?.content_types || []).map((t) => ({t.label} | ))}|
|---|---|---|---|
|
{u.name || `Profil #${u.id}`}
{u.email || '—'}
|
{u.total_count} | {(meta?.content_types || []).map((t) => ({u.counts_by_type?.[t.id] ?? 0} | ))}
Keine Inhalte für die aktuellen Filter.
) : (| Typ | Titel | Nutzer | Sichtbarkeit | Status | Aktualisiert | |
|---|---|---|---|---|---|---|
| {item.type_label} |
{href ? (
{item.title || '—'}
) : (
item.title || '—'
)}
#{item.id}
{item.club_name ? ` · ${item.club_name}` : ''}
|
{item.profile_name || '—'}
{item.profile_email || (item.profile_id ? `#${item.profile_id}` : '—')}
|
{item.visibility ? ( {VISIBILITY_LABEL[item.visibility] || item.visibility} ) : ( '—' )} |
{item.status ? STATUS_LABELS[item.status] || item.status : '—'}
{item.extra_status && item.extra_status !== 'active' ? (
{LIFECYCLE_LABELS[item.extra_status] || item.extra_status}
) : null}
|
{formatDate(item.updated_at)} |
|