/* ================================================================== Admin login — username + password → {apiBase}/teacher/login. ------------------------------------------------------------------ Rendered by app.jsx when window.APP.NEEDS_LOGIN is true. On success we store the bearer token via AppApi.setToken and re-bootstrap. Non-admin accounts are rejected here (the cockpit is the admin panel; teachers belong on the Teacher app). Name, mark and the help line come from window.BRAND (brand.js). ================================================================== */ const CockpitLogin = ({ onLoggedIn }) => { const [username, setUsername] = React.useState(""); const [password, setPassword] = React.useState(""); const [busy, setBusy] = React.useState(false); const [err, setErr] = React.useState(null); const B = window.BRAND || {}; const submit = async (e) => { e?.preventDefault(); if (!username.trim() || !password) return; setBusy(true); setErr(null); try { const r = await fetch(window.AppApi.base + "/teacher/login", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ username: username.trim(), password }), }); const data = await r.json().catch(() => ({})); if (!r.ok) throw new Error(data?.error || `login failed (${r.status})`); if (data?.teacher?.role !== "admin") { throw new Error("This panel is admin-only. Teachers should use the Teacher app."); } window.AppApi.setToken(data.token); onLoggedIn(); } catch (e) { setErr(String(e.message || e)); setBusy(false); } }; return (
{/* 380px + the wrapper's padding overflowed a 390px viewport, so the login screen itself scrolled sideways. Cap against the padding. */}
{B.orgName}
{B.appName}
setUsername(e.target.value)} autoComplete="username" style={{ width: "100%", marginBottom: 12 }}/> setPassword(e.target.value)} autoComplete="current-password" style={{ width: "100%" }}/> {err && (
{err}
)}

Teachers: use the Teacher app. This panel only accepts admin accounts.

{(B.supportEmail || B.supportPhone) && (

Need help? {[B.supportEmail, B.supportPhone].filter(Boolean).join(" · ")}

)} {B.poweredBy && (

Powered by {B.poweredBy}

)}
); }; window.CockpitLogin = CockpitLogin;