import React, { useState, useEffect } from 'react' import { api } from '../utils/api' /** * AdminHierarchyPage - Hierarchische Katalog-Verwaltung * * Layout: * ┌─ Tree (links) ─────────┬─ Detail Panel (rechts) ─┐ * │ ▼ Fokusbereich │ │ * │ ├─ Stilrichtungen │ [Edit-Form für │ * │ └─ Trainingstypen │ ausgewähltes Element] │ * └────────────────────────┴──────────────────────────┘ */ function AdminHierarchyPage() { const [hierarchy, setHierarchy] = useState([]) const [expandedNodes, setExpandedNodes] = useState(new Set()) const [selectedItem, setSelectedItem] = useState(null) const [loading, setLoading] = useState(false) const [error, setError] = useState('') useEffect(() => { loadHierarchy() }, []) async function loadHierarchy() { setLoading(true) setError('') try { const data = await api.getAdminHierarchy() setHierarchy(data) // Auto-expand first focus area if (data.length > 0) { setExpandedNodes(new Set([`fa-${data[0].id}`])) } } catch (e) { setError(e.message) } finally { setLoading(false) } } function toggleNode(nodeId) { const newExpanded = new Set(expandedNodes) if (newExpanded.has(nodeId)) { newExpanded.delete(nodeId) } else { newExpanded.add(nodeId) } setExpandedNodes(newExpanded) } function selectItem(item, type) { setSelectedItem({ ...item, _type: type }) } if (loading && hierarchy.length === 0) { return (
) } return (
{/* Left: Tree View */}

Katalog-Hierarchie

{error &&
{error}
} {hierarchy.map(fa => ( ))}
{/* Right: Detail Panel */}
{selectedItem ? ( ) : (

← Wähle ein Element aus dem Baum

)}
) } // ============================================================================ // Tree Node Components // ============================================================================ function FocusAreaNode({ focusArea, expanded, onToggle, onSelect, selectedId, selectedType }) { const nodeId = `fa-${focusArea.id}` const isExpanded = expanded.has(nodeId) const isSelected = selectedType === 'focus_area' && selectedId === focusArea.id return (
{/* Focus Area Header */}
onSelect(focusArea, 'focus_area')} style={{ display: 'flex', alignItems: 'center', padding: '8px 12px', borderRadius: '8px', cursor: 'pointer', background: isSelected ? 'var(--accent)' : 'transparent', color: isSelected ? 'white' : 'var(--text1)', fontWeight: 600 }} > { e.stopPropagation(); onToggle(nodeId) }} style={{ marginRight: '8px', cursor: 'pointer', fontSize: '18px' }} > {isExpanded ? '▼' : '▶'} {focusArea.icon} {focusArea.name}
{/* Children: Style Directions + Training Types */} {isExpanded && (
{/* Style Directions Section */} {focusArea.style_directions && focusArea.style_directions.length > 0 && (
Stilrichtungen
{focusArea.style_directions.map(sd => ( ))}
)} {/* Training Types Section */} {focusArea.training_types && focusArea.training_types.length > 0 && (
Trainingstypen
{focusArea.training_types.map(tt => ( ))}
)}
)}
) } function StyleDirectionNode({ styleDirection, onSelect, isSelected }) { return (
onSelect(styleDirection, 'style_direction')} style={{ padding: '6px 12px', marginBottom: '4px', borderRadius: '6px', cursor: 'pointer', background: isSelected ? 'var(--accent)' : 'var(--surface2)', color: isSelected ? 'white' : 'var(--text1)', fontSize: '14px' }} > {styleDirection.name} {styleDirection.abbreviation && ( ({styleDirection.abbreviation}) )} {styleDirection.target_groups && styleDirection.target_groups.length > 0 && (
Zielgruppen: {styleDirection.target_groups.map(tg => tg.name).join(', ')}
)}
) } function TrainingTypeNode({ trainingType, onSelect, isSelected }) { return (
onSelect(trainingType, 'training_type')} style={{ padding: '6px 12px', marginBottom: '4px', borderRadius: '6px', cursor: 'pointer', background: isSelected ? 'var(--accent)' : 'var(--surface2)', color: isSelected ? 'white' : 'var(--text1)', fontSize: '14px' }} > {trainingType.name} {trainingType.abbreviation && ( ({trainingType.abbreviation}) )}
) } // ============================================================================ // Detail Panel (Edit Forms) // ============================================================================ function DetailPanel({ item, onUpdate }) { if (!item) return null const type = item._type if (type === 'focus_area') { return } else if (type === 'style_direction') { return } else if (type === 'training_type') { return } return null } function FocusAreaDetail({ focusArea, onUpdate }) { const [editing, setEditing] = useState(false) const [form, setForm] = useState({ name: focusArea.name, icon: focusArea.icon, description: focusArea.description || '' }) async function handleSave() { try { await api.updateFocusArea(focusArea.id, form) setEditing(false) onUpdate() } catch (e) { alert('Fehler: ' + e.message) } } if (!editing) { return (

{focusArea.icon} {focusArea.name}

{focusArea.description &&

{focusArea.description}

}
) } return (

Fokusbereich bearbeiten

setForm({ ...form, name: e.target.value })} />
setForm({ ...form, icon: e.target.value })} />