// App shell: the sign-in page, then the home of the role the person chose. A person with several roles gets a chip for each. import { api, ApiError } from "./api.js"; import { esc } from "./math.js"; import { ROLE_NAMES, visibleRoles } from "./roles.js"; import { clearRoute, leaveScreen } from "./router.js"; import * as session from "./session.js"; import { owl } from "./sky.js"; const CFG = JSON.parse(document.getElementById("config").textContent); const app = document.getElementById("app"); const nav = document.getElementById("nav"); const ROLE_KEY = "mathly2.role"; const SCREENS = { student: "./student.js", teacher: "./teacher.js", manager: "./manager.js", admin: "./admin.js", developer: "./developer.js" }; export const view = html => { app.innerHTML = html; }; const remembered = () => { try { return localStorage.getItem(ROLE_KEY) || ""; } catch { return ""; } }; const remember = role => { try { localStorage.setItem(ROLE_KEY, role); } catch { /* private window */ } }; function showSignIn(message = "", canRetry = false) { opened++; // a role screen still loading must not draw over the sign-in page leaveScreen(); nav.innerHTML = ""; view(`
${owl(72)}

${esc(message || "יש להיכנס כדי לפתוח את מסלול המתמטיקה.")}

${canRetry ? `

` : ""} ${CFG.devSignIn ? `

כניסת פיתוח (dev only): ללא Supabase, כל כתובת מייל מתקבלת.

` : canRetry ? "" : `

`}
`); document.getElementById("retry")?.addEventListener("click", () => boot()); document.getElementById("google")?.addEventListener("click", () => session.signInWithGoogle()); document.getElementById("dev")?.addEventListener("submit", event => { event.preventDefault(); session.signInDev(document.getElementById("email").value); boot(); }); } async function signOutAndShow(message) { await session.signOut(); showSignIn(message); } function header(me, current) { const roles = visibleRoles(me.roles); nav.innerHTML = `${esc(me.email)} ${roles.length > 1 ? `${roles.map(role => ``).join("")}` : ""} `; document.getElementById("out").addEventListener("click", () => signOutAndShow()); document.getElementById("access").addEventListener("click", async () => { clearRoute(); nav.querySelectorAll("[data-role]").forEach(b => b.setAttribute("aria-pressed", "false")); ++opened; // a role screen still loading must not draw over this one await (await import("./access.js")).show(me, view); }); nav.querySelectorAll("[data-role]").forEach(button => button.addEventListener("click", () => open(me, button.dataset.role))); } let opened = 0; // which role screen is open: a screen opened earlier never draws over a later one (its answers may come late) async function open(me, role, { keepAddress = false } = {}) { const mine = ++opened; const draw = html => { if (mine === opened) view(html); }; remember(role); clearRoute({ keepAddress }); header(me, role); draw(`

טוען…

`); try { await (await import(SCREENS[role])).show(me, draw); } catch (error) { if (error instanceof ApiError && error.status === 401) return signOutAndShow("ההתחברות פגה, יש להיכנס שוב"); draw(`
`); } } async function boot() { view(`

טוען…

`); try { await session.init(CFG); } catch { return showSignIn("לא הצלחנו להתחבר לשירות ההתחברות. בדקו את החיבור לרשת ונסו שוב.", true); } if (!await session.token()) return showSignIn(); try { const me = await api("/api/me"); const roles = visibleRoles(me.roles); await open(me, roles.includes(remembered()) ? remembered() : roles[0], { keepAddress: true }); // the first screen honours a link } catch (error) { if (error instanceof ApiError && error.status === 401) return signOutAndShow("ההתחברות פגה, יש להיכנס שוב"); if (error instanceof ApiError && error.status === 503) return showSignIn("שירות ההתחברות לא זמין כרגע.", true); view(`
`); } } boot();