103 lines
2.7 KiB
JavaScript

async function readJsonResponse(response) {
const text = await response.text();
if (!text) {
return {};
}
try {
return JSON.parse(text);
} catch (error) {
throw new Error(text);
}
}
function nextLocation() {
const params = new URLSearchParams(window.location.search);
const candidate = (params.get("next") || "").trim();
if (candidate.startsWith("/") && !candidate.startsWith("//")) {
return candidate;
}
return "/select";
}
window.addEventListener("DOMContentLoaded", async () => {
const bootIndicator = document.getElementById("boot-indicator");
const root = document.getElementById("login-root");
const form = document.getElementById("login-form");
const usernameInput = document.getElementById("username");
const passwordInput = document.getElementById("password");
const submitButton = document.getElementById("login-submit");
const errorNode = document.getElementById("login-error");
const showForm = () => {
if (bootIndicator) {
bootIndicator.hidden = true;
}
if (root) {
root.hidden = false;
}
};
const setError = (message) => {
if (!errorNode) {
return;
}
errorNode.textContent = message || "";
errorNode.hidden = !message;
};
try {
const response = await fetch("/api/auth/session", {
cache: "no-store",
credentials: "same-origin",
});
if (response.ok) {
window.location.replace(nextLocation());
return;
}
if (response.status !== 401) {
const payload = await readJsonResponse(response);
setError(payload.error || `HTTP ${response.status}`);
}
} catch (error) {
setError(error instanceof Error ? error.message : String(error));
} finally {
showForm();
}
if (!form || !(usernameInput instanceof HTMLInputElement) || !(passwordInput instanceof HTMLInputElement)) {
return;
}
usernameInput.focus();
form.addEventListener("submit", async (event) => {
event.preventDefault();
setError("");
submitButton.disabled = true;
try {
const response = await fetch("/api/auth/login", {
method: "POST",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: usernameInput.value.trim(),
password: passwordInput.value,
}),
});
const payload = await readJsonResponse(response);
if (!response.ok) {
throw new Error(payload.error || `HTTP ${response.status}`);
}
window.location.replace(nextLocation());
} catch (error) {
setError(error instanceof Error ? error.message : String(error));
} finally {
submitButton.disabled = false;
}
});
});