69 lines
1.8 KiB
JavaScript
Executable file
69 lines
1.8 KiB
JavaScript
Executable file
(function () {
|
|
'use strict';
|
|
|
|
document.getElementById('login-year').textContent = new Date().getFullYear();
|
|
|
|
const form = document.getElementById('login-form');
|
|
const errorBox = document.getElementById('login-error');
|
|
const btn = document.getElementById('login-btn');
|
|
|
|
// If already authenticated, skip to app
|
|
fetch('/auth/me', { credentials: 'same-origin' })
|
|
.then(r => { if (r.ok) window.location.replace('/'); })
|
|
.catch(() => { /* not logged in, stay here */ });
|
|
|
|
// Show expired-session message
|
|
const params = new URLSearchParams(location.search);
|
|
if (params.get('expired') === '1') {
|
|
showError('Your session expired. Please sign in again.');
|
|
}
|
|
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
hideError();
|
|
|
|
const username = document.getElementById('username').value.trim();
|
|
const password = document.getElementById('password').value;
|
|
|
|
if (!username || !password) {
|
|
showError('Username and password are required.');
|
|
return;
|
|
}
|
|
|
|
btn.disabled = true;
|
|
btn.textContent = 'Signing in\u2026';
|
|
|
|
try {
|
|
const res = await fetch('/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'same-origin',
|
|
body: JSON.stringify({ username, password }),
|
|
});
|
|
|
|
const data = await res.json();
|
|
|
|
if (!res.ok) {
|
|
showError(data.error || 'Login failed.');
|
|
return;
|
|
}
|
|
|
|
const dest = params.get('next') || '/';
|
|
window.location.replace(dest);
|
|
} catch {
|
|
showError('Network error. Please try again.');
|
|
} finally {
|
|
btn.disabled = false;
|
|
btn.textContent = 'Sign In';
|
|
}
|
|
});
|
|
|
|
function showError(msg) {
|
|
errorBox.textContent = msg;
|
|
errorBox.hidden = false;
|
|
}
|
|
|
|
function hideError() {
|
|
errorBox.hidden = true;
|
|
}
|
|
})();
|