Files
webui-develop/static/login.ts

61 lines
1.8 KiB
TypeScript

/* Login page — external script, no inline handlers.
* Loaded by the /login route. Reads data attributes from the form for
* i18n strings so the server does not need to inject JS literals.
*/
interface LoginForm extends HTMLFormElement {
'data-invalid-pw': string;
'data-conn-failed': string;
}
document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('login-form') as LoginForm | null;
const input = document.getElementById('pw') as HTMLInputElement | null;
if (!form || !input) return;
const invalidPw = form.getAttribute('data-invalid-pw') || 'Invalid password';
const connFailed = form.getAttribute('data-conn-failed') || 'Connection failed';
function showErr(msg: string): void {
const err = document.getElementById('err');
if (err) { err.textContent = msg; err.style.display = 'block'; }
}
function hideErr(): void {
const err = document.getElementById('err');
if (err) { err.style.display = 'none'; }
}
async function doLogin(e: Event): Promise<void> {
e.preventDefault();
const pw = input!.value;
hideErr();
try {
const res = await fetch('api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password: pw }),
credentials: 'include',
});
let data: { ok?: boolean; error?: string } = {};
try { data = await res.json(); } catch (_) { /* ignore */ }
if (res.ok && data.ok) {
window.location.href = './';
} else {
showErr(data.error || invalidPw);
}
} catch (ex) {
showErr(connFailed);
}
}
form.addEventListener('submit', doLogin);
input.addEventListener('keydown', function (e: KeyboardEvent) {
if (e.key === 'Enter') {
e.preventDefault();
doLogin(e);
}
});
});