import React, { useState, useEffect, useCallback } from 'react' import { Link } from 'react-router-dom' import api from '../utils/api' import { notifyOrgInboxChanged, useOrgInbox } from '../context/OrgInboxContext' const CLUB_ROLE_OPTIONS = [ { code: 'club_admin', label: 'Vereinsadmin' }, { code: 'trainer', label: 'Trainer' }, { code: 'division_lead', label: 'Spartenleitung' }, { code: 'content_editor', label: 'Inhalte bearbeiten' }, ] const REASON_LABELS = { copyright: 'Urheberrecht', image_rights: 'Bildrechte', privacy: 'Datenschutz / Persönlichkeitsrecht', minors: 'Minderjährige', illegal_content: 'Rechtswidriger Inhalt', youth_protection: 'Jugendschutz', offensive_content: 'Beleidigender Inhalt', other: 'Sonstiges', } const STATUS_LABELS = { submitted: 'Eingegangen', under_review: 'In Bearbeitung', resolved_no_action: 'Abgeschlossen (kein Handlungsbedarf)', resolved_legal_hold: 'Abgeschlossen (Legal Hold)', rejected_invalid: 'Abgewiesen (ungültig)', } const STATUS_COLORS = { submitted: 'var(--accent)', under_review: '#e8960a', resolved_no_action: 'var(--text3)', resolved_legal_hold: 'var(--danger)', rejected_invalid: 'var(--text3)', } function formatWhen(iso) { if (!iso) return '' const s = String(iso) const d = s.includes('T') ? s.split('T')[0] : s.slice(0, 10) const t = s.includes('T') ? s.split('T')[1] : '' const time = t ? t.slice(0, 5) : '' return time ? `${d} · ${time}` : d } function PriorityBadge({ priority }) { if (priority !== 'high') return null return ( DRINGEND ) } const WORKFLOW_STEPS = [ { key: 'submitted', label: 'Eingegangen' }, { key: 'under_review', label: 'In Bearbeitung' }, { key: 'closed', label: 'Abgeschlossen' }, ] function WorkflowBar({ status }) { const closed = ['resolved_no_action', 'resolved_legal_hold', 'rejected_invalid'].includes(status) const step = closed ? 2 : status === 'under_review' ? 1 : 0 return (
{WORKFLOW_STEPS.map((s, i) => { const active = i === step const done = i < step return (
{done ? '✓' : i + 1}
{s.label}
{i < WORKFLOW_STEPS.length - 1 && (
)} ) })}
) } function ReportDetailModal({ report, onClose, onRefresh, isSuperadmin, isClubAdmin }) { const [resolutionNote, setResolutionNote] = useState(report.resolution_note || '') const [legalHoldNote, setLegalHoldNote] = useState('') const [saving, setSaving] = useState(false) const [error, setError] = useState(null) const [showLegalHoldForm, setShowLegalHoldForm] = useState(false) const isClosed = ['resolved_no_action', 'resolved_legal_hold', 'rejected_invalid'].includes(report.status) const isOpen = !isClosed async function patchAndClose(body) { setSaving(true) setError(null) try { await api.patchContentReport(report.id, body) notifyOrgInboxChanged() onRefresh() onClose() } catch (err) { setError(err.message || String(err)) setSaving(false) } } async function handleStatus(status) { if ((status === 'resolved_no_action' || status === 'rejected_invalid') && !resolutionNote.trim()) { setError('Bitte eine Begründung eingeben.') return } await patchAndClose({ status, resolution_note: resolutionNote.trim() || undefined }) } async function handleSaveNote() { if (!resolutionNote.trim()) { setError('Notiz ist leer.'); return } await patchAndClose({ resolution_note: resolutionNote.trim() }) } async function handleLegalHold() { if (!legalHoldNote.trim()) { setError('Begründung für Legal Hold erforderlich.'); return } await patchAndClose({ legalHoldNote }) } async function handleLegalHoldSubmit() { if (!legalHoldNote.trim()) { setError('Begründung für Legal Hold erforderlich.'); return } setSaving(true) setError(null) try { await api.setLegalHoldFromReport(report.id, { reason_note: legalHoldNote.trim() }) notifyOrgInboxChanged() onRefresh() onClose() } catch (err) { setError(err.message || String(err)) setSaving(false) } } const targetLabel = report.target_filename || report.target_exercise_name ? `${report.target_filename || report.target_exercise_name} (#${report.target_id})` : `#${report.target_id}` return (
{ if (e.target === e.currentTarget) onClose() }} >
{/* Header */}

Meldung #{report.id}

{STATUS_LABELS[report.status] || report.status}
{/* Workflow Bar */} {/* Details */}
Ziel {report.target_type === 'media_asset' ? 'Medium' : 'Übung'} {targetLabel}
Meldegrund {REASON_LABELS[report.report_reason] || report.report_reason}
Beschreibung {report.report_description}
Meldende Person {report.reporter_name} {report.reporter_email ? ` · ${report.reporter_email}` : ''} {report.reporter_profile_id ? ` · Profil #${report.reporter_profile_id}` : ' · anonym'}
Eingegangen {formatWhen(report.submitted_at || report.created_at)}
{report.reviewed_by_name && (
Geprüft von {report.reviewed_by_name}{report.reviewed_at ? ` · ${formatWhen(report.reviewed_at)}` : ''}
)} {report.target_legal_hold_active && (
Legal Hold aktiv auf diesem Medium
)}
{/* Resolution Note (Bearbeitungskommentar) */}