From 18043bc147e603a8d358788391e2da1ee8bba155 Mon Sep 17 00:00:00 2001 From: bes-r <27369668+bes-r@users.noreply.github.com> Date: Mon, 15 Jun 2026 22:09:48 +0200 Subject: [PATCH] Vernieuw navigatie en roostermaker UI --- backend/core/apps.py | 10 +-- backend/modules/leerplein/apps.py | 6 +- frontend/src/App.jsx | 119 ++++++++++++++---------------- frontend/src/pages.jsx | 58 +++++++-------- frontend/src/styles.css | 64 +++++++++++----- 5 files changed, 137 insertions(+), 120 deletions(-) diff --git a/backend/core/apps.py b/backend/core/apps.py index 231f0d4..b6647a1 100644 --- a/backend/core/apps.py +++ b/backend/core/apps.py @@ -30,12 +30,10 @@ class CoreConfig(AppConfig): # Hoofdniveau: Rooster = weergave, Roostermaker = aanpasser. MenuItem("Rooster", "/rooster", icon="calendar", order=10), MenuItem("Roostermaker", "/roostermaker", icon="calendar", order=12), - # Submenu Personen (functies zitten als tab in het Personen-scherm) - MenuItem("Personen", "/personen", icon="users", order=20, group="Personen"), - MenuItem("Afwezigheid", "/afwezigheid", icon="away", order=28, group="Personen"), - # Submenu Groepen - MenuItem("Groepen", "/groepen", icon="layers", order=30, group="Groepen"), - MenuItem("Subgroepen", "/subgroepen", icon="layers", order=40, group="Groepen"), + # Submenu Organisatie: wie hoort waar. + MenuItem("Personen", "/personen", icon="users", order=20, group="Organisatie"), + MenuItem("Structuur", "/structuur", icon="layers", order=24, group="Organisatie"), + MenuItem("Afwezigheid", "/afwezigheid", icon="away", order=28, group="Organisatie"), ), ) ) diff --git a/backend/modules/leerplein/apps.py b/backend/modules/leerplein/apps.py index 19be4c5..7c9fa9c 100644 --- a/backend/modules/leerplein/apps.py +++ b/backend/modules/leerplein/apps.py @@ -8,7 +8,7 @@ class LeerpleinConfig(AppConfig): verbose_name = "Module: Leerplein (groepsstructuur)" def ready(self): - from plugins.registry import MenuItem, ModuleSpec, registry + from plugins.registry import ModuleSpec, registry registry.register( ModuleSpec( @@ -22,8 +22,6 @@ class LeerpleinConfig(AppConfig): category="Structuur", core=False, default_enabled=False, - menu_items=( - MenuItem("Leerplein", "/leerplein", icon="layers", order=50, group="Groepen"), - ), + menu_items=(), ) ) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 11142af..674e841 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -2,7 +2,7 @@ import { useEffect, useMemo, useState } from "react"; import { getMe, login, logout, getModules, setModuleState } from "./api.js"; import Logo from "./Logo.jsx"; import { - GroepenPage, PersonenPage, SubgroepenPage, FunctiesPage, + PersonenPage, FunctiesPage, ActiviteitenPage, LocatiesPage, TijdslotenPage, SchooljaarPage, RoosterWeergavePage, RoostermakerPage, AfwezigheidPage, LeerpleinPage, StagePage, GebruikersPage, @@ -14,21 +14,23 @@ const ICONS = { away: "🌴", gear: "⚙️", }; +const STRUCTUUR_PADEN = new Set(["/structuur", "/leerplein", "/groepen", "/subgroepen"]); +const STRUCTUUR_ITEM = { label: "Structuur", path: "/structuur", icon: "layers", order: 24, group: "Organisatie" }; +const normaliseerPad = (path) => (STRUCTUUR_PADEN.has(path) ? "/structuur" : path); + // Koppel een menu-pad aan een echt scherm. Onbekende paden tonen een // placeholder (worden in een latere fase ingevuld). const PAGES = { "/rooster": RoosterWeergavePage, "/roostermaker": RoostermakerPage, + "/structuur": LeerpleinPage, "/personen": PersonenPage, "/functies": FunctiesPage, - "/groepen": GroepenPage, - "/subgroepen": SubgroepenPage, "/activiteiten": ActiviteitenPage, "/locaties": LocatiesPage, "/tijdsloten": TijdslotenPage, "/schooljaar": SchooljaarPage, "/afwezigheid": AfwezigheidPage, - "/leerplein": LeerpleinPage, "/stage": StagePage, "/gebruikers": GebruikersPage, }; @@ -134,94 +136,85 @@ function Shell({ user, onLogout }) { } } - const [openGroups, setOpenGroups] = useState({}); - // Bouw de navigatie op uit de menu-items die ACTIEVE modules aanbieden. - // Items met een `group` komen onder een inklapbaar submenu. De groep - // "Instellingen" wordt apart, subtiel onderaan, getoond. - const { topItems, groups, instellingenItems, alleItems } = useMemo(() => { - const items = []; + // Verouderde structuurpaden blijven werken, maar verschijnen als één tab. + const { tabs, instellingenTabs, alleItems } = useMemo(() => { + const perPad = new Map(); + const voegToe = (raw) => { + const pad = normaliseerPad(raw.path); + const item = pad === "/structuur" + ? { ...raw, ...STRUCTUUR_ITEM, module: raw.module } + : { ...raw, path: pad }; + const huidig = perPad.get(item.path); + if (!huidig || item.order < huidig.order) perPad.set(item.path, item); + }; for (const m of modules) { if (!m.enabled) continue; - for (const it of m.menu_items) items.push({ ...it, module: m.key }); + for (const it of m.menu_items) voegToe({ ...it, module: m.key }); } if (user.is_staff) { - items.push({ label: "Modulebeheer", path: "/modules", icon: "gear", order: 9999, group: "Instellingen" }); + voegToe({ label: "Modulebeheer", path: "/modules", icon: "gear", order: 9999, group: "Instellingen" }); } + const items = [...perPad.values()]; items.sort((a, b) => a.order - b.order); - const top = items.filter((i) => !i.group); - const grouped = {}; - const settings = []; - for (const i of items) { - if (i.group === "Instellingen") settings.push(i); - else if (i.group) (grouped[i.group] = grouped[i.group] || []).push(i); - } - return { topItems: top, groups: grouped, instellingenItems: settings, alleItems: items }; + return { + tabs: items.filter((i) => i.group !== "Instellingen"), + instellingenTabs: items.filter((i) => i.group === "Instellingen"), + alleItems: items, + }; }, [modules, user.is_staff]); - function NavKnop({ it, indent }) { + const activePad = normaliseerPad(active); + const Page = PAGES[activePad]; + + function TabKnop({ it, compact }) { + const pad = normaliseerPad(it.path); return ( ); } - const Page = PAGES[active]; - return (
- + + -
+
{error &&
⚠ {error}
} {loading ? (

Laden…

- ) : active === "/modules" && user.is_staff ? ( + ) : activePad === "/modules" && user.is_staff ? ( ) : Page ? ( ) : ( - + )}
diff --git a/frontend/src/pages.jsx b/frontend/src/pages.jsx index b6b256e..fd65113 100644 --- a/frontend/src/pages.jsx +++ b/frontend/src/pages.jsx @@ -1400,11 +1400,20 @@ function BlokBewerker({ blok, ctx, onSluit, onKlaar }) { try { await deleteResource("roosterblokken", blok.id); await onKlaar(); } catch (e) { setError(e.message); } } return ( -
e.stopPropagation()}> -
- Bewerken - -
+
+
e.stopPropagation()}> +
+
+

{blok.activiteit_naam || "Roosterblok"}

+
{blok.doel_naam || "Bewerken en splitsen"}
+
+ +
+
+
+ Vak bewerken + Wijzig, splits of kopieer dit blok +