File size: 3,013 Bytes
a7ffb22 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | // The admin's screen: the accounts the app knows, with their roles; give a role to any email (even one that never signed in) or take it away.
import { api } from "./api.js";
import { esc } from "./math.js";
import { ROLE_NAMES } from "./roles.js";
const GRANTABLE = ["student", "teacher", "manager", "admin"];
let draw;
async function showAccounts(message = "", error = "") {
const accounts = await api("/api/accounts");
draw(`<section id="accounts"><h2>ืชืคืงืืืื</h2>
<section class="card"><h3>ืืชื ืชืคืงืื</h3>
<p class="muted">ืืคืฉืจ ืืืงืืื ืื ืืชืืืช ืฉืขืื ืื ื ืื ืกื ืืืคืืืงืฆืื: ืืชืคืงืื ืืืื ืืืื ืืกื ืืจืืฉืื ื ืฉืื. ืฉืื ืื ืชืคืงืื ื ืงืื ืชืื ืืืฆื ืืงื.</p>
<form id="give"><label for="g-email">ืืืื</label><input id="g-email" type="email" dir="ltr" required autocomplete="off">
<label for="g-role">ืชืคืงืื</label><select id="g-role">${GRANTABLE.map(r => `<option value="${r}">${ROLE_NAMES[r]}</option>`).join("")}</select>
${error ? `<p class="error" role="alert">${esc(error)}</p>` : ""}${message ? `<p role="status">${esc(message)}</p>` : ""}
<p><button class="primary" type="submit">ืืชื ืืชืคืงืื</button></p></form></section>
<div class="tablewrap"><table class="data"><thead><tr><th>ืืฉืืื</th><th>ืชืคืงืืืื ืฉื ืืชื ื</th><th>ืืืืืืจืืช</th></tr></thead>
<tbody>${accounts.map(a => `<tr data-email="${esc(a.email)}"><td dir="ltr">${esc(a.email)}</td>
<td>${a.roles.map(r => `<span class="tag">${ROLE_NAMES[r]} <button type="button" data-take="${r}" aria-label="ืืกืจืช ืืชืคืงืื ${ROLE_NAMES[r]} ืึพ${esc(a.email)}">โ</button></span>`).join(" ") || '<span class="muted">โ</span>'}</td>
<td>${a.from_settings.map(r => `<span class="tag">${ROLE_NAMES[r]}</span>`).join(" ") || '<span class="muted">โ</span>'}</td></tr>`).join("")}</tbody></table></div></section>`);
document.getElementById("give").addEventListener("submit", async event => {
event.preventDefault();
const email = document.getElementById("g-email").value.trim(), role = document.getElementById("g-role").value;
try {
await api(`/api/accounts/${encodeURIComponent(email)}/roles/${role}`, { method: "POST" });
await showAccounts(`${email}: ื ืืชื ืืชืคืงืื ${ROLE_NAMES[role]}.`);
} catch (e) { await showAccounts("", e.message); }
});
document.querySelector("#accounts tbody").addEventListener("click", async event => {
const role = event.target.closest("[data-take]")?.dataset.take;
if (!role) return;
const email = event.target.closest("tr").dataset.email;
try {
await api(`/api/accounts/${encodeURIComponent(email)}/roles/${role}`, { method: "DELETE" });
await showAccounts(`${email}: ืืชืคืงืื ${ROLE_NAMES[role]} ืืืกืจ.`);
} catch (e) { await showAccounts("", e.message); }
});
}
export async function show(me, view) {
draw = view;
await showAccounts();
}
|