Verbeter anatomie en plaatsing van avataraccessoires (v0.4.46-beta) #1
3 changed files with 57 additions and 53 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
0.3.93-beta
|
0.3.94-beta
|
||||||
|
|
|
||||||
|
|
@ -359,7 +359,8 @@
|
||||||
|
|
||||||
/* het bewerkformulier van één gebruiker; wordt gebruikt door het
|
/* het bewerkformulier van één gebruiker; wordt gebruikt door het
|
||||||
detailpaneel (gebruikers) én inline door het Systeem-tabblad (subrijen) */
|
detailpaneel (gebruikers) én inline door het Systeem-tabblad (subrijen) */
|
||||||
function userTools(u){
|
function userTools(u, note){
|
||||||
|
note = note || msg;
|
||||||
const tools = h("div","am-tools");
|
const tools = h("div","am-tools");
|
||||||
const actions = h("div","am-actions");
|
const actions = h("div","am-actions");
|
||||||
const isStaff = ["teacher","admin","super"].includes(u.role);
|
const isStaff = ["teacher","admin","super"].includes(u.role);
|
||||||
|
|
@ -373,7 +374,7 @@
|
||||||
ss.value = u.schoolId ?? "";
|
ss.value = u.schoolId ?? "";
|
||||||
ss.addEventListener("change", async ()=>{
|
ss.addEventListener("change", async ()=>{
|
||||||
try{ await api("/admin/users/"+u.id, {method:"PATCH", body:{ schoolId: ss.value ? +ss.value : null }}); reload(); }
|
try{ await api("/admin/users/"+u.id, {method:"PATCH", body:{ schoolId: ss.value ? +ss.value : null }}); reload(); }
|
||||||
catch(e){ msg(e.message); ss.value = u.schoolId ?? ""; }
|
catch(e){ note(e.message); ss.value = u.schoolId ?? ""; }
|
||||||
});
|
});
|
||||||
tools.appendChild(field("amFieldSchool", ss));
|
tools.appendChild(field("amFieldSchool", ss));
|
||||||
}
|
}
|
||||||
|
|
@ -385,7 +386,7 @@
|
||||||
rs.value = u.role;
|
rs.value = u.role;
|
||||||
rs.addEventListener("change", async ()=>{
|
rs.addEventListener("change", async ()=>{
|
||||||
try{ await api("/admin/users/"+u.id, {method:"PATCH", body:{role: rs.value}}); reload(); }
|
try{ await api("/admin/users/"+u.id, {method:"PATCH", body:{role: rs.value}}); reload(); }
|
||||||
catch(e){ msg(e.message); }
|
catch(e){ note(e.message); }
|
||||||
});
|
});
|
||||||
tools.appendChild(field("amFieldRole", rs));
|
tools.appendChild(field("amFieldRole", rs));
|
||||||
}
|
}
|
||||||
|
|
@ -403,7 +404,7 @@
|
||||||
x.title = T("amClassRemove");
|
x.title = T("amClassRemove");
|
||||||
x.addEventListener("click", async ()=>{
|
x.addEventListener("click", async ()=>{
|
||||||
try{ await api("/admin/classes/"+cid+"/teachers", {body:{ userId: u.id, remove:true }}); reload(); }
|
try{ await api("/admin/classes/"+cid+"/teachers", {body:{ userId: u.id, remove:true }}); reload(); }
|
||||||
catch(e){ msg(e.message); }
|
catch(e){ note(e.message); }
|
||||||
});
|
});
|
||||||
chip.appendChild(x);
|
chip.appendChild(x);
|
||||||
wrap.appendChild(chip);
|
wrap.appendChild(chip);
|
||||||
|
|
@ -416,7 +417,7 @@
|
||||||
addSel.addEventListener("change", async ()=>{
|
addSel.addEventListener("change", async ()=>{
|
||||||
if(!addSel.value) return;
|
if(!addSel.value) return;
|
||||||
try{ await api("/admin/classes/"+addSel.value+"/teachers", {body:{ userId: u.id }}); reload(); }
|
try{ await api("/admin/classes/"+addSel.value+"/teachers", {body:{ userId: u.id }}); reload(); }
|
||||||
catch(e){ msg(e.message); }
|
catch(e){ note(e.message); }
|
||||||
});
|
});
|
||||||
wrap.appendChild(addSel);
|
wrap.appendChild(addSel);
|
||||||
}
|
}
|
||||||
|
|
@ -427,7 +428,7 @@
|
||||||
const cs = classSel(u.classId);
|
const cs = classSel(u.classId);
|
||||||
cs.addEventListener("change", async ()=>{
|
cs.addEventListener("change", async ()=>{
|
||||||
try{ await api("/admin/users/"+u.id, {method:"PATCH", body:{classId: cs.value ? +cs.value : null}}); }
|
try{ await api("/admin/users/"+u.id, {method:"PATCH", body:{classId: cs.value ? +cs.value : null}}); }
|
||||||
catch(e){ msg(e.message); }
|
catch(e){ note(e.message); }
|
||||||
});
|
});
|
||||||
tools.appendChild(field("amFieldClass", cs));
|
tools.appendChild(field("amFieldClass", cs));
|
||||||
/* wachtwoord inzien en aanpassen - alleen zichtbaar zolang de leerling
|
/* wachtwoord inzien en aanpassen - alleen zichtbaar zolang de leerling
|
||||||
|
|
@ -440,7 +441,7 @@
|
||||||
pw.addEventListener("change", async ()=>{
|
pw.addEventListener("change", async ()=>{
|
||||||
if(pw.value.length < 4) return;
|
if(pw.value.length < 4) return;
|
||||||
try{ await api("/admin/users/"+u.id, {method:"PATCH", body:{password: pw.value}}); reload(); }
|
try{ await api("/admin/users/"+u.id, {method:"PATCH", body:{password: pw.value}}); reload(); }
|
||||||
catch(e){ msg(e.message); }
|
catch(e){ note(e.message); }
|
||||||
});
|
});
|
||||||
pwWrap.appendChild(pw);
|
pwWrap.appendChild(pw);
|
||||||
const pwCopy = h("button","am-btn", T("amCopy"));
|
const pwCopy = h("button","am-btn", T("amCopy"));
|
||||||
|
|
@ -456,7 +457,7 @@
|
||||||
rowResults.set(u.id, { label: T("amResultPw"), value: password });
|
rowResults.set(u.id, { label: T("amResultPw"), value: password });
|
||||||
selectedUserKey = "u:"+u.id;
|
selectedUserKey = "u:"+u.id;
|
||||||
reload();
|
reload();
|
||||||
}catch(e){ msg(e.message); }
|
}catch(e){ note(e.message); }
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
/* eenmalige ouder-code waarmee een ouder dit kind aan het eigen
|
/* eenmalige ouder-code waarmee een ouder dit kind aan het eigen
|
||||||
|
|
@ -467,7 +468,7 @@
|
||||||
rowResults.set(u.id, { label: T("amResultParentCode"), value: r.parentCode });
|
rowResults.set(u.id, { label: T("amResultParentCode"), value: r.parentCode });
|
||||||
selectedUserKey = "u:"+u.id;
|
selectedUserKey = "u:"+u.id;
|
||||||
reload();
|
reload();
|
||||||
}catch(e){ msg(e.message); }
|
}catch(e){ note(e.message); }
|
||||||
}));
|
}));
|
||||||
}else{
|
}else{
|
||||||
if(u.pending && u.linkCode){
|
if(u.pending && u.linkCode){
|
||||||
|
|
@ -480,7 +481,7 @@
|
||||||
rowResults.set(u.id, { label: T("amResultCode"), value: r.linkCode });
|
rowResults.set(u.id, { label: T("amResultCode"), value: r.linkCode });
|
||||||
selectedUserKey = "u:"+u.id;
|
selectedUserKey = "u:"+u.id;
|
||||||
reload();
|
reload();
|
||||||
}catch(e){ msg(e.message); }
|
}catch(e){ note(e.message); }
|
||||||
}));
|
}));
|
||||||
/* direct een nieuw wachtwoord zetten, zonder de koppelcode-activatie */
|
/* direct een nieuw wachtwoord zetten, zonder de koppelcode-activatie */
|
||||||
actions.appendChild(dangerBtn(T("amNewPw"), "amNewPwWarn", async ()=>{
|
actions.appendChild(dangerBtn(T("amNewPw"), "amNewPwWarn", async ()=>{
|
||||||
|
|
@ -489,14 +490,14 @@
|
||||||
rowResults.set(u.id, { label: T("amResultPw"), value: r.password });
|
rowResults.set(u.id, { label: T("amResultPw"), value: r.password });
|
||||||
selectedUserKey = "u:"+u.id;
|
selectedUserKey = "u:"+u.id;
|
||||||
reload();
|
reload();
|
||||||
}catch(e){ msg(e.message); }
|
}catch(e){ note(e.message); }
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(u.id !== currentUser.id){
|
if(u.id !== currentUser.id){
|
||||||
const del = dangerBtn(T("amDelete"), "amDeleteWarn", async ()=>{
|
const del = dangerBtn(T("amDelete"), "amDeleteWarn", async ()=>{
|
||||||
try{ await api("/admin/users/"+u.id, {method:"DELETE"}); selectedUserKey = null; reload(); }
|
try{ await api("/admin/users/"+u.id, {method:"DELETE"}); selectedUserKey = null; reload(); }
|
||||||
catch(e){ msg(e.message); }
|
catch(e){ note(e.message); }
|
||||||
});
|
});
|
||||||
actions.appendChild(del);
|
actions.appendChild(del);
|
||||||
}
|
}
|
||||||
|
|
@ -580,7 +581,11 @@
|
||||||
detailHost.appendChild(detailHead(u.displayName, T(roleKey(u.role)) + (u.displayName!==u.username ? ` · ${u.username}` : "")));
|
detailHost.appendChild(detailHead(u.displayName, T(roleKey(u.role)) + (u.displayName!==u.username ? ` · ${u.username}` : "")));
|
||||||
const badge = resultBadge(u);
|
const badge = resultBadge(u);
|
||||||
if(badge) detailHost.appendChild(badge);
|
if(badge) detailHost.appendChild(badge);
|
||||||
detailHost.appendChild(userTools(u));
|
/* fouten (bv. verwijderen mislukt) tonen we hier, waar de beheerder kijkt,
|
||||||
|
niet alleen bovenaan het paneel (daar valt het buiten beeld) */
|
||||||
|
const note = h("div","am-detail-msg formMsg");
|
||||||
|
detailHost.appendChild(note);
|
||||||
|
detailHost.appendChild(userTools(u, (t)=>{ note.textContent = t || ""; }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(selectedUserKey && selectedUserKey.startsWith("req:")){
|
if(selectedUserKey && selectedUserKey.startsWith("req:")){
|
||||||
|
|
@ -1297,25 +1302,10 @@
|
||||||
master.appendChild(thead);
|
master.appendChild(thead);
|
||||||
|
|
||||||
const list = h("div","am-list am-userlist");
|
const list = h("div","am-list am-userlist");
|
||||||
/* losse accounts (ooit aan een school gekoppeld, nu zonder): alleen
|
/* inklapbare groepskop; standaard dicht tenzij defaultOpen (dan onthoudt
|
||||||
relevant voor de systeemmanager in de alle-scholen-weergave */
|
closedGroups een bewuste dichtklap). Zoeken kijkt door alle groepen heen. */
|
||||||
const showLoose = currentUser.role==="super" && !selSchool;
|
const group = (key, label, us, defaultOpen)=>{
|
||||||
const isLoose = u=>showLoose && ["teacher","admin","pupil"].includes(u.role) && u.schoolId==null;
|
if(defaultOpen && !closedGroups.has(key)) openGroups.add(key);
|
||||||
const staffGroups = [["super", T("amSuperGroup")], ["admin", T("roleAdmin")], ["teacher", T("roleTeacher")]];
|
|
||||||
staffGroups.forEach(([role, label])=>{
|
|
||||||
const us = USERS.filter(u=>u.role===role && !isLoose(u));
|
|
||||||
if(!us.length) return;
|
|
||||||
list.appendChild(h("div","am-group", `${label} (${us.length})`));
|
|
||||||
us.forEach(u=>list.appendChild(userCells(u)));
|
|
||||||
});
|
|
||||||
|
|
||||||
const pupils = USERS.filter(u=>u.role==="pupil" && !isLoose(u));
|
|
||||||
const schoolChosen = schoolChosenTop;
|
|
||||||
|
|
||||||
/* leerlingen staan onder inklapbare groepskoppen (standaard dicht): zo
|
|
||||||
blijft de lijst overzichtelijk bij grote scholen; zoeken kijkt altijd
|
|
||||||
door alle groepen heen (zie applyUserFilter) */
|
|
||||||
const pupilGroup = (key, label, us)=>{
|
|
||||||
const g = h("div","am-group am-group-toggle");
|
const g = h("div","am-group am-group-toggle");
|
||||||
g.dataset.collapsible = "1";
|
g.dataset.collapsible = "1";
|
||||||
g.dataset.gkey = key;
|
g.dataset.gkey = key;
|
||||||
|
|
@ -1331,27 +1321,41 @@
|
||||||
us.forEach(u=>list.appendChild(userCells(u)));
|
us.forEach(u=>list.appendChild(userCells(u)));
|
||||||
};
|
};
|
||||||
|
|
||||||
/* per-klas indeling heeft alleen zin met één gekozen school (CLASSES is dan
|
if(currentUser.role==="super" && !selSchool){
|
||||||
betrouwbaar); zonder gekozen school (super, alle scholen) of voor groepsleiding
|
/* ALLE SCHOLEN: groepeer per school zodat je meteen ziet wie waar hoort;
|
||||||
één groep - anders vallen leerlingen met een classId die niet in
|
daarna systeemmanagers, ouders en losse accounts apart */
|
||||||
de (dan lege) CLASSES-lijst voorkomt onterecht helemaal weg */
|
const roleOrder = { admin:0, teacher:1, pupil:2 };
|
||||||
if(currentUser.role==="teacher" || !schoolChosen){
|
SCHOOLS.forEach(sc=>{
|
||||||
if(pupils.length) pupilGroup("pupils", T("amPupils"), pupils);
|
const us = USERS.filter(u=>Number(u.schoolId)===Number(sc.id))
|
||||||
}else{
|
.sort((a,b)=>(roleOrder[a.role]??9)-(roleOrder[b.role]??9) || a.displayName.localeCompare(b.displayName));
|
||||||
CLASSES.forEach(c=>{
|
if(us.length) group("gschool:"+sc.id, sc.name, us);
|
||||||
const us = pupils.filter(u=>u.classId===c.id);
|
|
||||||
/* met een gekozen school staan de klasgroepen standaard open - de
|
|
||||||
schoolkeuze wás al het filter; dichtklappen wordt onthouden */
|
|
||||||
if(us.length && !closedGroups.has("class:"+c.id)) openGroups.add("class:"+c.id);
|
|
||||||
if(us.length) pupilGroup("class:"+c.id, c.name, us);
|
|
||||||
});
|
});
|
||||||
const noClass = pupils.filter(u=>!u.classId);
|
const supers = USERS.filter(u=>u.role==="super");
|
||||||
if(noClass.length) pupilGroup("class:none", T("amNoClass"), noClass);
|
if(supers.length) group("gsys", T("amSuperGroup"), supers);
|
||||||
|
const parents = USERS.filter(u=>u.role==="parent");
|
||||||
|
if(parents.length) group("gparents", T("amParents"), parents);
|
||||||
|
const loose = USERS.filter(u=>["teacher","admin","pupil"].includes(u.role) && u.schoolId==null);
|
||||||
|
if(loose.length) group("gnoschool", T("amNoSchoolGroup"), loose);
|
||||||
|
}else{
|
||||||
|
/* één school gekozen: groepeer op rol, leerlingen per klas */
|
||||||
|
[["admin", T("roleAdmin")], ["teacher", T("roleTeacher")]].forEach(([role, label])=>{
|
||||||
|
const us = USERS.filter(u=>u.role===role);
|
||||||
|
if(us.length) group("role:"+role, label, us, true);
|
||||||
|
});
|
||||||
|
const pupils = USERS.filter(u=>u.role==="pupil");
|
||||||
|
if(currentUser.role==="teacher"){
|
||||||
|
if(pupils.length) group("pupils", T("amPupils"), pupils, true);
|
||||||
|
}else{
|
||||||
|
CLASSES.forEach(c=>{
|
||||||
|
const us = pupils.filter(u=>u.classId===c.id);
|
||||||
|
if(us.length) group("class:"+c.id, c.name, us, true);
|
||||||
|
});
|
||||||
|
const noClass = pupils.filter(u=>!u.classId);
|
||||||
|
if(noClass.length) group("class:none", T("amNoClass"), noClass, true);
|
||||||
|
}
|
||||||
|
const parents = USERS.filter(u=>u.role==="parent");
|
||||||
|
if(parents.length) group("parents", T("amParents"), parents);
|
||||||
}
|
}
|
||||||
const parents = USERS.filter(u=>u.role==="parent");
|
|
||||||
if(parents.length) pupilGroup("parents", T("amParents"), parents);
|
|
||||||
const loose = USERS.filter(isLoose);
|
|
||||||
if(loose.length) pupilGroup("noschool", T("amNoSchoolGroup"), loose);
|
|
||||||
master.appendChild(list);
|
master.appendChild(list);
|
||||||
split.appendChild(master);
|
split.appendChild(master);
|
||||||
split.appendChild(detail);
|
split.appendChild(detail);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
/* version — shown until /api/version resolves (or if the fetch fails, e.g. offline).
|
/* version — shown until /api/version resolves (or if the fetch fails, e.g. offline).
|
||||||
Kept in sync by hand with the VERSION file at the repo root on every release. */
|
Kept in sync by hand with the VERSION file at the repo root on every release. */
|
||||||
const VERSION = "0.3.93-beta";
|
const VERSION = "0.3.94-beta";
|
||||||
(function(){
|
(function(){
|
||||||
const tag = document.getElementById("verTag");
|
const tag = document.getElementById("verTag");
|
||||||
tag.textContent = "v"+VERSION;
|
tag.textContent = "v"+VERSION;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue