(async function () { const root = document.getElementById("app"); await setLang(detectInitialLang()); // If already signed in, skip the login form. try { const u = await API.me(); if (u) { navigate(u.must_change_password ? "forcePassword" : "competitions"); return; } } catch (e) {} function render() { clearNode(root); const usernameInput = el("input", { type: "text", autocomplete: "username", placeholder: t("username"), oninput: (e) => { e.target.value = e.target.value.toLowerCase(); } }); const passwordInput = el("input", { type: "password", autocomplete: "current-password", placeholder: t("password") }); const errorBox = el("div", { class: "muted", style: { color: "var(--danger)", display: "none" } }); const langSelect = el("select", { onchange: async (e) => { await setLang(e.target.value); render(); } }, ...I18N_AVAILABLE.map((l) => el("option", { value: l, selected: l === CURRENT_LANG }, I18N_NAMES[l])) ); async function doLogin(e) { e.preventDefault(); errorBox.style.display = "none"; try { const u = await API.login(usernameInput.value, passwordInput.value); if (u.must_change_password) navigate("forcePassword"); else navigate("competitions"); } catch (err) { if (err.status === 429) errorBox.textContent = t("too_many_attempts"); else if (err.status === 401) errorBox.textContent = t("invalid_credentials"); else errorBox.textContent = err.message || t("invalid_credentials"); errorBox.style.display = "block"; } } const form = el("form", { onsubmit: doLogin, class: "col" }, el("h1", null, t("login_title")), el("div", { class: "field" }, el("label", null, t("username")), usernameInput), el("div", { class: "field" }, el("label", null, t("password")), passwordInput), errorBox, el("button", { type: "submit", class: "primary" }, t("sign_in")), el("div", { class: "field", style: { marginTop: "0.5rem" } }, el("label", null, t("language")), langSelect ), ); root.appendChild(el("div", { class: "login-wrap" }, el("div", { class: "login-box" }, form))); usernameInput.focus(); } render(); })();