Personen+Functies samengevoegd (tab), Indeling-tab weg + subgroep aanmaken vanuit blok, 'dit vak laten vervallen' + hele dag laten vervallen in weekrooster
This commit is contained in:
parent
8841fd5698
commit
95a04f3ca1
4 changed files with 57 additions and 20 deletions
|
|
@ -74,9 +74,9 @@ volgt.
|
|||
|
||||
- [ ] **Vrije/vakantie-/studiedagen kunnen niet gebruikt worden** in de
|
||||
Roostermaker (geen blokken plannen op die dagen).
|
||||
- [ ] De actie **"Deze dag laten vervallen"** subtieler wegwerken **en de tekst
|
||||
corrigeren** — het is per *blok*, niet per dag.
|
||||
- [ ] Mogelijkheid om **een hele dag op vervallen** te zetten (i.p.v. per blok).
|
||||
- [x] De actie heet nu **"dit vak laten vervallen"** (per blok, juiste tekst).
|
||||
- [x] Een **hele dag laten vervallen** kan direct in het weekrooster (knop in de
|
||||
dagkop; maakt een vrije dag aan, met "weer lesdag" om te herstellen).
|
||||
|
||||
## Later
|
||||
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@ class CoreConfig(AppConfig):
|
|||
# Hoofdniveau: Rooster = weergave, Roostermaker = aanpasser.
|
||||
MenuItem("Rooster", "/rooster", icon="calendar", order=10),
|
||||
MenuItem("Roostermaker", "/roostermaker", icon="calendar", order=12),
|
||||
# Submenu Personen
|
||||
# Submenu Personen (functies zitten als tab in het Personen-scherm)
|
||||
MenuItem("Personen", "/personen", icon="users", order=20, group="Personen"),
|
||||
MenuItem("Functies", "/functies", icon="badge", order=25, group="Personen"),
|
||||
MenuItem("Afwezigheid", "/afwezigheid", icon="away", order=28, group="Personen"),
|
||||
# Submenu Groepen
|
||||
MenuItem("Groepen", "/groepen", icon="layers", order=30, group="Groepen"),
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ export function PersonenPage() {
|
|||
const [form, setForm] = useState(leegLeerling);
|
||||
const [editId, setEditId] = useState(null);
|
||||
const [filter, setFilter] = useState("");
|
||||
const [hoofdtab, setHoofdtab] = useState("personen");
|
||||
|
||||
function laadHulplijsten() {
|
||||
listResource("groepen").then(setGroepen).catch(() => {});
|
||||
|
|
@ -354,9 +355,26 @@ export function PersonenPage() {
|
|||
: filter === "medewerker" ? items.filter((p) => p.rol !== "leerling")
|
||||
: items;
|
||||
|
||||
if (hoofdtab === "functies") {
|
||||
return (
|
||||
<section>
|
||||
<h1>Personen</h1>
|
||||
<h1>Personen & functies</h1>
|
||||
<div className="tabbar">
|
||||
<button className="tab" onClick={() => setHoofdtab("personen")}>Personen</button>
|
||||
<button className="tab on" onClick={() => setHoofdtab("functies")}>Functies</button>
|
||||
</div>
|
||||
<FunctiesPage />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<h1>Personen & functies</h1>
|
||||
<div className="tabbar">
|
||||
<button className="tab on" onClick={() => setHoofdtab("personen")}>Personen</button>
|
||||
<button className="tab" onClick={() => setHoofdtab("functies")}>Functies</button>
|
||||
</div>
|
||||
<p className="muted">Personeel en leerlingen staan los van elkaar. Kies wat je wilt toevoegen.</p>
|
||||
<Foutmelding msg={error} />
|
||||
|
||||
|
|
@ -1224,7 +1242,19 @@ function BlokBewerker({ blok, ctx, onSluit, onKlaar }) {
|
|||
});
|
||||
const [kopieDoelen, setKopieDoelen] = useState([]);
|
||||
const [error, setError] = useState(null);
|
||||
const doelOpties = f.doel_type === "groep" ? groepen : f.doel_type === "subgroep" ? subgroepen : leerlingen;
|
||||
const [subs, setSubs] = useState(subgroepen);
|
||||
const [nieuweSub, setNieuweSub] = useState("");
|
||||
const doelOpties = f.doel_type === "groep" ? groepen : f.doel_type === "subgroep" ? subs : leerlingen;
|
||||
|
||||
async function maakSubgroep() {
|
||||
if (!nieuweSub.trim()) return;
|
||||
try {
|
||||
const s = await createResource("subgroepen", { naam: nieuweSub.trim(), groep: f.doel_type === "groep" && f.doel ? f.doel : null });
|
||||
setSubs([...subs, s]);
|
||||
setF({ ...f, doel_type: "subgroep", doel: s.id });
|
||||
setNieuweSub("");
|
||||
} catch (e) { setError(e.message); }
|
||||
}
|
||||
const toggleBeg = (id) => setF((s) => s.begeleiders.includes(id) ? { ...s, begeleiders: s.begeleiders.filter((x) => x !== id) } : { ...s, begeleiders: [...s.begeleiders, id] });
|
||||
const toggleKopie = (id) => setKopieDoelen((d) => d.includes(id) ? d.filter((x) => x !== id) : [...d, id]);
|
||||
const doelPayload = () => ({
|
||||
|
|
@ -1273,6 +1303,12 @@ function BlokBewerker({ blok, ctx, onSluit, onKlaar }) {
|
|||
{doelOpties.map((o) => <option key={o.id} value={o.id}>{o.naam || o.volledige_naam}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
{f.doel_type === "subgroep" && (
|
||||
<div className="form-row">
|
||||
<input placeholder="Nieuwe subgroep" value={nieuweSub} onChange={(e) => setNieuweSub(e.target.value)} />
|
||||
<button type="button" className="btn" onClick={maakSubgroep}>+ Subgroep aanmaken</button>
|
||||
</div>
|
||||
)}
|
||||
<div className="leden-keuze">
|
||||
<div className="muted small">Begeleiders:</div>
|
||||
<div className="chips">
|
||||
|
|
@ -1528,6 +1564,14 @@ export function RoosterScherm({ mode }) {
|
|||
async function herstel(uitId) {
|
||||
try { await deleteResource("blok-uitzonderingen", uitId); await laadWeek(); } catch (err) { setError(err.message); }
|
||||
}
|
||||
async function dagVervallen(iso) {
|
||||
try { await createResource("kalenderdagen", { schooljaar, datum: iso, type: "vrije_dag", omschrijving: "vervallen" }); await laadBlokken(); }
|
||||
catch (err) { setError(err.message); }
|
||||
}
|
||||
async function dagHerstel(kalId) {
|
||||
try { await deleteResource("kalenderdagen", kalId); await laadBlokken(); }
|
||||
catch (err) { setError(err.message); }
|
||||
}
|
||||
|
||||
// Hulpfuncties voor het effectieve rooster.
|
||||
const kalenderOp = (iso) => kalender.find((k) => k.datum === iso);
|
||||
|
|
@ -1590,7 +1634,6 @@ export function RoosterScherm({ mode }) {
|
|||
{edit && (
|
||||
<div className="tabbar no-print">
|
||||
<button className={tab === "week" ? "tab on" : "tab"} onClick={() => setTab("week")}>Weekrooster</button>
|
||||
<button className={tab === "indeling" ? "tab on" : "tab"} onClick={() => setTab("indeling")}>Indeling</button>
|
||||
<button className={tab === "conflicten" ? "tab on" : "tab"} onClick={() => setTab("conflicten")}>Conflicten</button>
|
||||
<button className={tab === "schooljaar" ? "tab on" : "tab"} onClick={() => setTab("schooljaar")}>Schooljaar</button>
|
||||
<button className={tab === "instellingen" ? "tab on" : "tab"} onClick={() => setTab("instellingen")}>Instellingen</button>
|
||||
|
|
@ -1650,6 +1693,10 @@ export function RoosterScherm({ mode }) {
|
|||
<div className="rooster-dag">
|
||||
{d.label} <span className="muted">{fmtDM(datum)}</span>
|
||||
{kal && <div className={`tag dag-${kal.type}`}>{kal.type_label}{kal.omschrijving ? `: ${kal.omschrijving}` : ""}</div>}
|
||||
{edit && (kal
|
||||
? <button className="link small no-print dag-actie" onClick={() => dagHerstel(kal.id)}>weer lesdag</button>
|
||||
: <button className="link danger small no-print dag-actie" onClick={() => dagVervallen(iso)}>dag laten vervallen</button>
|
||||
)}
|
||||
</div>
|
||||
{slots.length === 0 && <div className="muted small">—</div>}
|
||||
{slots.map((t) => {
|
||||
|
|
@ -1688,7 +1735,7 @@ export function RoosterScherm({ mode }) {
|
|||
{!kal && uit && uit.vervalt && <div className="small rb-status">Vervalt {uit.opmerking ? `(${uit.opmerking})` : ""}{edit && <> · <button className="link" onClick={(e) => { e.stopPropagation(); herstel(uit.id); }}>herstel</button></>}</div>}
|
||||
{!kal && uit && !uit.vervalt && uit.vervanger_naam && <div className="small rb-verv">↪ Vervanger: {uit.vervanger_naam}</div>}
|
||||
{edit && !kal && !uit && (
|
||||
<button className="link danger small rb-verval no-print" onClick={(e) => { e.stopPropagation(); laatVervallen(b, iso); }}>deze dag laten vervallen</button>
|
||||
<button className="link danger small rb-verval no-print" onClick={(e) => { e.stopPropagation(); laatVervallen(b, iso); }}>dit vak laten vervallen</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -1702,17 +1749,6 @@ export function RoosterScherm({ mode }) {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{edit && tab === "indeling" && (
|
||||
<Groepsindeling
|
||||
groepen={groepen}
|
||||
leerpleinen={leerpleinen}
|
||||
subgroepen={subgroepen}
|
||||
medewerkers={medewerkers}
|
||||
blokken={blokken}
|
||||
onWijzig={async () => { try { setSubgroepen(await listResource("subgroepen")); } catch (e) { setError(e.message); } }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{schooljaar && tab === "conflicten" && <Conflicten schooljaar={schooljaar} />}
|
||||
|
||||
{tab === "schooljaar" && (
|
||||
|
|
|
|||
|
|
@ -147,6 +147,8 @@ input[type="color"] { padding: 2px; width: 44px; min-width: 44px; height: 38px;
|
|||
|
||||
.drag-ghost { position: fixed; z-index: 1000; pointer-events: none; background: var(--brand); color: #fff; padding: 6px 12px; border-radius: 8px; font-size: 13px; font-weight: 600; box-shadow: 0 6px 18px rgba(0,0,0,.25); }
|
||||
|
||||
.dag-actie { display: block; margin-top: 4px; font-size: 11px; }
|
||||
|
||||
/* --- Groepsindeling --- */
|
||||
.indeling { margin-top: 12px; }
|
||||
.indeling-hoofd { background: var(--brand); color: #fff; border-radius: 10px; padding: 12px 16px; font-weight: 700; font-size: 16px; text-align: center; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue