61 lines
1.8 KiB
TypeScript
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);
|
|
}
|
|
});
|
|
});
|