- New AdminPageNav component with horizontal navigation - Links to Hierarchie / Kataloge / Wiki-Import - Integrated in all 3 admin pages - Uses lucide-react icons (TreePine, FolderTree, Download) - Active state tracking via useLocation - Mobile-friendly with flexbox layout Navigation flow: /admin/hierarchy → /admin/catalogs → /admin/mediawiki-import
197 lines
5.2 KiB
JavaScript
197 lines
5.2 KiB
JavaScript
import React, { useState, useEffect } from 'react'
|
|
import { api } from '../utils/api'
|
|
import AdminPageNav from '../components/AdminPageNav'
|
|
import HierarchyTab from '../components/admin/HierarchyTab'
|
|
import CatalogsTab from '../components/admin/CatalogsTab'
|
|
import AssignmentsTab from '../components/admin/AssignmentsTab'
|
|
|
|
function AdminHierarchyPage() {
|
|
const [activeTab, setActiveTab] = useState('hierarchy')
|
|
const [loading, setLoading] = useState(true)
|
|
const [error, setError] = useState('')
|
|
|
|
// Hierarchy Tab State
|
|
const [hierarchy, setHierarchy] = useState([])
|
|
const [expandedNodes, setExpandedNodes] = useState(new Set())
|
|
const [selectedItem, setSelectedItem] = useState(null)
|
|
|
|
// Catalogs Tab State
|
|
const [targetGroups, setTargetGroups] = useState([])
|
|
const [skillCategories, setSkillCategories] = useState([])
|
|
const [trainingCharacters, setTrainingCharacters] = useState([])
|
|
|
|
// Assignments Tab State
|
|
const [styleDirections, setStyleDirections] = useState([])
|
|
const [assignments, setAssignments] = useState([])
|
|
|
|
useEffect(() => {
|
|
loadData()
|
|
}, [activeTab])
|
|
|
|
async function loadData() {
|
|
setLoading(true)
|
|
setError('')
|
|
try {
|
|
if (activeTab === 'hierarchy') {
|
|
const data = await api.getAdminHierarchy()
|
|
setHierarchy(data)
|
|
} else if (activeTab === 'catalogs') {
|
|
const [tgs, scs, tcs] = await Promise.all([
|
|
api.listTargetGroups(),
|
|
api.listSkillCategories(),
|
|
api.listTrainingCharacters()
|
|
])
|
|
setTargetGroups(tgs)
|
|
setSkillCategories(scs)
|
|
setTrainingCharacters(tcs)
|
|
} else if (activeTab === 'assignments') {
|
|
const [sds, tgs, assns] = await Promise.all([
|
|
api.listStyleDirections(),
|
|
api.listTargetGroups(),
|
|
api.listStyleDirectionTargetGroups()
|
|
])
|
|
setStyleDirections(sds)
|
|
setTargetGroups(tgs)
|
|
setAssignments(assns)
|
|
}
|
|
} catch (e) {
|
|
setError(e.message)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
function handleToggleNode(nodeId) {
|
|
setExpandedNodes(prev => {
|
|
const newSet = new Set(prev)
|
|
if (newSet.has(nodeId)) {
|
|
newSet.delete(nodeId)
|
|
} else {
|
|
newSet.add(nodeId)
|
|
}
|
|
return newSet
|
|
})
|
|
}
|
|
|
|
function handleSelectItem(item, type) {
|
|
if (item) {
|
|
setSelectedItem({ ...item, _type: type })
|
|
} else {
|
|
setSelectedItem(null)
|
|
}
|
|
}
|
|
|
|
function handleUpdate() {
|
|
setSelectedItem(null)
|
|
loadData()
|
|
}
|
|
|
|
const tabs = [
|
|
{ id: 'hierarchy', label: '🌳 Hierarchie', icon: '🌳' },
|
|
{ id: 'catalogs', label: '📋 Kataloge', icon: '📋' },
|
|
{ id: 'assignments', label: '🔗 Zuordnungen', icon: '🔗' }
|
|
]
|
|
|
|
return (
|
|
<div style={{ padding: '20px' }}>
|
|
<AdminPageNav />
|
|
|
|
<h1 style={{ marginTop: 0 }}>Admin: Katalog-Hierarchie</h1>
|
|
|
|
{/* Tab Navigation */}
|
|
<div className="tab-navigation">
|
|
{tabs.map(tab => (
|
|
<button
|
|
key={tab.id}
|
|
className={activeTab === tab.id ? 'tab-button active' : 'tab-button'}
|
|
onClick={() => setActiveTab(tab.id)}
|
|
>
|
|
{tab.icon} {tab.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* Tab Content */}
|
|
<div style={{ marginTop: '20px' }}>
|
|
{activeTab === 'hierarchy' && (
|
|
<HierarchyTab
|
|
hierarchy={hierarchy}
|
|
expandedNodes={expandedNodes}
|
|
selectedItem={selectedItem}
|
|
loading={loading}
|
|
error={error}
|
|
onToggleNode={handleToggleNode}
|
|
onSelectItem={handleSelectItem}
|
|
onUpdate={handleUpdate}
|
|
/>
|
|
)}
|
|
|
|
{activeTab === 'catalogs' && (
|
|
<CatalogsTab
|
|
targetGroups={targetGroups}
|
|
skillCategories={skillCategories}
|
|
trainingCharacters={trainingCharacters}
|
|
loading={loading}
|
|
error={error}
|
|
onUpdate={handleUpdate}
|
|
/>
|
|
)}
|
|
|
|
{activeTab === 'assignments' && (
|
|
<AssignmentsTab
|
|
styleDirections={styleDirections}
|
|
targetGroups={targetGroups}
|
|
assignments={assignments}
|
|
loading={loading}
|
|
error={error}
|
|
onUpdate={handleUpdate}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
<style>{`
|
|
.tab-navigation {
|
|
display: flex;
|
|
gap: 8px;
|
|
border-bottom: 2px solid var(--border);
|
|
margin-bottom: 20px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.tab-button {
|
|
padding: 12px 20px;
|
|
background: transparent;
|
|
border: none;
|
|
border-bottom: 3px solid transparent;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
color: var(--text2);
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.tab-button:hover {
|
|
color: var(--text1);
|
|
background: var(--surface2);
|
|
}
|
|
|
|
.tab-button.active {
|
|
color: var(--accent);
|
|
border-bottom-color: var(--accent);
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.tab-button {
|
|
flex: 1 1 auto;
|
|
min-width: 120px;
|
|
font-size: 14px;
|
|
padding: 10px 12px;
|
|
}
|
|
}
|
|
`}</style>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default AdminHierarchyPage
|