89 lines
3.1 KiB
JavaScript
89 lines
3.1 KiB
JavaScript
(() => {
|
|
const form = document.getElementById('admin-login-form');
|
|
const statusEl = document.getElementById('admin-login-status');
|
|
const userEl = document.getElementById('admin-username');
|
|
const passEl = document.getElementById('admin-password');
|
|
|
|
function setStatus(msg, isError = false) {
|
|
if (!statusEl) return;
|
|
statusEl.textContent = msg || '';
|
|
statusEl.style.color = isError ? 'var(--danger)' : 'inherit';
|
|
}
|
|
|
|
async function ensureSession() {
|
|
try {
|
|
// Include credentials explicitly so cookies are reliably sent/received across browsers
|
|
const res = await fetch('/api/admin/me', { credentials: 'same-origin' });
|
|
if (!res.ok) return;
|
|
const data = await res.json();
|
|
if (data && data.ok) {
|
|
const params = new URLSearchParams(window.location.search);
|
|
const next = params.get('next');
|
|
|
|
// Only redirect if we have a next parameter and we're not already on that page
|
|
if (next && typeof next === 'string' && next.startsWith('/') && window.location.pathname !== next) {
|
|
window.location.href = next;
|
|
} else if (!next) {
|
|
// If no next parameter, go to admin dashboard
|
|
window.location.href = '/admin';
|
|
}
|
|
}
|
|
} catch (_) {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
setStatus('Signing in...');
|
|
try {
|
|
const payload = {
|
|
username: userEl.value.trim(),
|
|
password: passEl.value.trim(),
|
|
};
|
|
// Ensure credentials are included so Set-Cookie is accepted and future requests send cookies
|
|
const res = await fetch('/api/admin/login', {
|
|
method: 'POST',
|
|
credentials: 'same-origin',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload),
|
|
});
|
|
const data = await res.json().catch(() => ({}));
|
|
if (!res.ok) throw new Error(data.error || 'Login failed');
|
|
setStatus('Success, redirecting...');
|
|
|
|
// Respect optional `next` parameter (e.g. /admin/login?next=/test-checkout)
|
|
const params = new URLSearchParams(window.location.search);
|
|
const next = params.get('next');
|
|
|
|
// Poll /api/admin/me to ensure the session cookie is active before redirecting.
|
|
// This avoids a race where the next page immediately checks /api/admin/me and gets 401.
|
|
let sessionActive = false;
|
|
for (let i = 0; i < 6; i++) {
|
|
try {
|
|
const meRes = await fetch('/api/admin/me', { credentials: 'same-origin' });
|
|
if (meRes.ok) {
|
|
sessionActive = true;
|
|
break;
|
|
}
|
|
} catch (_) {
|
|
// ignore
|
|
}
|
|
// small backoff
|
|
await new Promise((r) => setTimeout(r, 150 * (i + 1)));
|
|
}
|
|
|
|
// Redirect regardless (session will usually be active) but polling reduces redirect loops
|
|
if (next && typeof next === 'string' && next.startsWith('/')) {
|
|
window.location.href = next;
|
|
} else {
|
|
window.location.href = '/admin';
|
|
}
|
|
} catch (err) {
|
|
setStatus(err.message, true);
|
|
}
|
|
});
|
|
|
|
ensureSession();
|
|
})();
|