import { auth } from './auth.js';
const SESSION_TIMEOUT_MS = Number(import.meta.env.VITE_SESSION_TIMEOUT_MS || 15 * 60 * 1000);
const SESSION_WARNING_MS = Number(import.meta.env.VITE_SESSION_WARNING_MS || 60 * 1000);
let inactivityTimer = null;
let warningTimer = null;
let warningCountdownTimer = null;
let warningEndsAt = null;
let warningOverlay = null;
let hasInitialized = false;
let fetchIsPatched = false;
function isAuthenticated() {
return Boolean(localStorage.getItem('token'));
}
function clearTimers() {
if (inactivityTimer) {
clearTimeout(inactivityTimer);
inactivityTimer = null;
}
if (warningTimer) {
clearTimeout(warningTimer);
warningTimer = null;
}
if (warningCountdownTimer) {
clearInterval(warningCountdownTimer);
warningCountdownTimer = null;
}
}
function removeWarningOverlay() {
if (warningOverlay) {
warningOverlay.remove();
warningOverlay = null;
}
warningEndsAt = null;
if (warningCountdownTimer) {
clearInterval(warningCountdownTimer);
warningCountdownTimer = null;
}
}
function getRemainingSeconds() {
if (!warningEndsAt) return 0;
return Math.max(0, Math.ceil((warningEndsAt - Date.now()) / 1000));
}
function forceSessionExpiration(message = 'Tu sesion ha expirado. Inicia sesion de nuevo.') {
removeWarningOverlay();
clearTimers();
auth.logout();
sessionStorage.setItem('session-expired-message', message);
window.location.hash = '#login';
}
function showWarningOverlay() {
if (!isAuthenticated()) return;
removeWarningOverlay();
const overlay = document.createElement('div');
overlay.className = 'session-warning-overlay';
overlay.innerHTML = `
Tu sesion va a expirar
Por inactividad, se cerrara tu sesion automaticamente en .
`;
const continueBtn = overlay.querySelector('.session-warning-continue');
const logoutBtn = overlay.querySelector('.session-warning-logout');
const countdownEl = overlay.querySelector('#session-warning-countdown');
continueBtn?.addEventListener('click', () => {
removeWarningOverlay();
resetSessionTimers();
});
logoutBtn?.addEventListener('click', () => {
forceSessionExpiration('Sesion finalizada por inactividad.');
});
warningEndsAt = Date.now() + SESSION_WARNING_MS;
const updateCountdown = () => {
const seconds = getRemainingSeconds();
const mins = String(Math.floor(seconds / 60)).padStart(2, '0');
const secs = String(seconds % 60).padStart(2, '0');
if (countdownEl) {
countdownEl.textContent = `${mins}:${secs}`;
}
if (seconds <= 0) {
forceSessionExpiration();
}
};
updateCountdown();
warningCountdownTimer = setInterval(updateCountdown, 1000);
warningOverlay = overlay;
document.body.appendChild(overlay);
}
function resetSessionTimers() {
clearTimers();
if (!isAuthenticated()) {
removeWarningOverlay();
return;
}
const warningDelay = Math.max(SESSION_TIMEOUT_MS - SESSION_WARNING_MS, 1000);
warningTimer = setTimeout(showWarningOverlay, warningDelay);
inactivityTimer = setTimeout(() => forceSessionExpiration(), SESSION_TIMEOUT_MS);
}
function patchFetchFor401AndActivity() {
if (fetchIsPatched) return;
const originalFetch = window.fetch.bind(window);
window.fetch = async (...args) => {
const requestUrl = typeof args[0] === 'string' ? args[0] : (args[0]?.url || '');
const isLoginEndpoint = requestUrl.includes('/api/Auth/login');
if (!isLoginEndpoint && isAuthenticated()) {
resetSessionTimers();
}
const response = await originalFetch(...args);
if (response.status === 401 && !isLoginEndpoint && isAuthenticated()) {
forceSessionExpiration('Tu sesion ha expirado o ya no es valida. Inicia sesion de nuevo.');
}
return response;
};
fetchIsPatched = true;
}
function bindActivityListeners() {
const events = ['mousemove', 'mousedown', 'keydown', 'touchstart', 'scroll'];
const onActivity = () => {
if (isAuthenticated()) {
resetSessionTimers();
}
};
events.forEach(eventName => {
window.addEventListener(eventName, onActivity, { passive: true });
});
}
function bindAuthListeners() {
window.addEventListener('auth:login', () => {
removeWarningOverlay();
resetSessionTimers();
});
window.addEventListener('auth:logout', () => {
removeWarningOverlay();
clearTimers();
});
}
export function initSessionManager() {
if (hasInitialized) return;
patchFetchFor401AndActivity();
bindActivityListeners();
bindAuthListeners();
resetSessionTimers();
hasInitialized = true;
}