From af895460226024af8e9b5f83f1a69c9ad0cbc3a0 Mon Sep 17 00:00:00 2001 From: Lars Date: Fri, 24 Apr 2026 08:33:11 +0200 Subject: [PATCH] feat: complete admin hierarchy - edit/delete + responsive design MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Features: - Edit forms for Style Directions and Training Types (working) - Delete functions with confirmation dialogs - Responsive layout: mobile (stacked), tablet/desktop (side-by-side) - Back button on mobile to return to tree view - Full CRUD except create (can use old catalogs page for now) Mobile UX: - Tree view fills screen - Click item → detail panel replaces tree - Back button → return to tree - Safe bottom padding for navigation Desktop UX: - 400px tree + fluid detail panel - Both always visible - No back button (not needed) Co-Authored-By: Claude Sonnet 4.5 --- frontend/src/pages/AdminHierarchyPage.jsx | 303 +++++++++++++++++----- 1 file changed, 232 insertions(+), 71 deletions(-) diff --git a/frontend/src/pages/AdminHierarchyPage.jsx b/frontend/src/pages/AdminHierarchyPage.jsx index 8193e1c..54e424f 100644 --- a/frontend/src/pages/AdminHierarchyPage.jsx +++ b/frontend/src/pages/AdminHierarchyPage.jsx @@ -63,55 +63,84 @@ function AdminHierarchyPage() { } return ( -
- {/* Left: Tree View */} -
-

Katalog-Hierarchie

- {error &&
{error}
} + <> + + +
+ {/* Tree View */} +
+

Katalog-Hierarchie

+ {error &&
{error}
} + + {hierarchy.map(fa => ( + + ))} +
+ + {/* Detail Panel */} + {selectedItem && ( +
+ +
)}
-
+ ) } @@ -332,42 +361,174 @@ function FocusAreaDetail({ focusArea, onUpdate }) { } function StyleDirectionDetail({ styleDirection, onUpdate }) { + const [editing, setEditing] = useState(false) + const [form, setForm] = useState({ + name: styleDirection.name, + abbreviation: styleDirection.abbreviation || '', + description: styleDirection.description || '', + focus_area_id: styleDirection.focus_area_id + }) + + async function handleSave() { + try { + await api.updateStyleDirection(styleDirection.id, form) + setEditing(false) + onUpdate() + } catch (e) { + alert('Fehler: ' + e.message) + } + } + + async function handleDelete() { + if (!confirm(`Stilrichtung "${styleDirection.name}" wirklich löschen?`)) return + try { + await api.deleteStyleDirection(styleDirection.id) + onUpdate() + } catch (e) { + alert('Fehler: ' + e.message) + } + } + + if (!editing) { + return ( +
+

{styleDirection.name}

+ {styleDirection.abbreviation &&

Kürzel: {styleDirection.abbreviation}

} + {styleDirection.description &&

{styleDirection.description}

} + + {styleDirection.target_groups && styleDirection.target_groups.length > 0 && ( +
+

Zugeordnete Zielgruppen

+
    + {styleDirection.target_groups.map(tg => ( +
  • + {tg.name} {tg.is_primary && ★ Primär} +
  • + ))} +
+
+ )} + +
+ + +
+
+ ) + } + return (
-

{styleDirection.name}

- {styleDirection.abbreviation &&

Kürzel: {styleDirection.abbreviation}

} - {styleDirection.description &&

{styleDirection.description}

} - - {styleDirection.target_groups && styleDirection.target_groups.length > 0 && ( -
-

Zugeordnete Zielgruppen

-
    - {styleDirection.target_groups.map(tg => ( -
  • - {tg.name} {tg.is_primary && ★ Primär} -
  • - ))} -
-
- )} - - +

Stilrichtung bearbeiten

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