06/04 Optimize app

This commit is contained in:
2026-06-04 13:25:57 -04:00
parent 0608f874fc
commit 0190da30d4
8 changed files with 158 additions and 65 deletions
+48 -18
View File
@@ -24,9 +24,9 @@ function closeModal(id) {
}
}
// Close modal when clicking the backdrop
// Close modal when clicking the backdrop (skips modals with data-no-backdrop-close)
document.addEventListener('click', (e) => {
if (e.target.classList.contains('modal-overlay')) {
if (e.target.classList.contains('modal-overlay') && !e.target.hasAttribute('data-no-backdrop-close')) {
e.target.classList.remove('open');
document.body.style.overflow = '';
}
@@ -162,30 +162,60 @@ document.addEventListener('DOMContentLoaded', () => {
/* ── Session timeout warning ───────────────────────────────── */
(function sessionWarning() {
const WARN_BEFORE_MS = 5 * 60 * 1000; // warn 5 min before expiry
const SESSION_MS = 30 * 60 * 1000; // match Flask SESSION_LIFETIME
const WARN_BEFORE_MS = 5 * 60 * 1000;
const SESSION_MS = 30 * 60 * 1000;
let warningTimer = null;
let expireTimer = null;
var warningTimer = null, expireTimer = null, countdownInterval = null;
function isWarningShowing() {
var m = document.getElementById('modal-session-warning');
return m && m.classList.contains('open');
}
function clearCountdown() {
if (countdownInterval) { clearInterval(countdownInterval); countdownInterval = null; }
}
function startCountdown() {
var remaining = Math.round(WARN_BEFORE_MS / 1000);
var el = document.getElementById('session-countdown');
clearCountdown();
countdownInterval = setInterval(function() {
remaining--;
if (el) {
var m = Math.floor(remaining / 60), s = remaining % 60;
el.textContent = m + ':' + (s < 10 ? '0' : '') + s;
}
if (remaining <= 0) { clearCountdown(); window.location.href = '/login'; }
}, 1000);
}
function resetTimers() {
clearTimeout(warningTimer);
clearTimeout(expireTimer);
warningTimer = setTimeout(() => {
if (confirm('Your session will expire in 5 minutes. Click OK to stay logged in.')) {
fetch('/ping', { credentials: 'same-origin' }).catch(() => {});
resetTimers();
}
clearTimeout(warningTimer); clearTimeout(expireTimer); clearCountdown();
if (isWarningShowing()) closeModal('modal-session-warning');
warningTimer = setTimeout(function() {
openModal('modal-session-warning');
startCountdown();
}, SESSION_MS - WARN_BEFORE_MS);
expireTimer = setTimeout(() => {
alert('Your session has expired. You will be redirected to login.');
window.location.href = '/auth/login';
expireTimer = setTimeout(function() {
window.location.href = '/login';
}, SESSION_MS);
}
['click', 'keydown', 'mousemove', 'scroll', 'touchstart'].forEach(evt => {
document.addEventListener(evt, () => resetTimers(), { passive: true });
document.addEventListener('DOMContentLoaded', function() {
var btn = document.getElementById('btn-stay-logged-in');
if (btn) btn.addEventListener('click', function() {
fetch('/ping', { credentials: 'same-origin' }).catch(function(){});
resetTimers();
});
});
['click', 'keydown', 'mousemove', 'scroll', 'touchstart'].forEach(function(evt) {
document.addEventListener(evt, function() {
if (!isWarningShowing()) resetTimers();
}, { passive: true });
});
resetTimers();