/** * Configuración del floating banner */ const BANNER_CONFIG = { storageKey: 'floating_banner_closed', defaultExpirationDays: 1, // Días por defecto antes de volver a mostrar }; /** * Verifica si un banner debe mostrarse basándose en localStorage * @param {string} bannerId - ID del banner * @returns {boolean} - true si debe mostrarse, false si está cerrado */ function shouldShowBanner(bannerId) { try { const stored = localStorage.getItem(BANNER_CONFIG.storageKey); if (!stored) return true; const closedBanners = JSON.parse(stored); const bannerData = closedBanners[bannerId]; if (!bannerData) return true; // Verificar si ha expirado el tiempo de cierre const now = Date.now(); if (now > bannerData.expiresAt) { // Ha expirado, eliminar del storage y mostrar delete closedBanners[bannerId]; localStorage.setItem(BANNER_CONFIG.storageKey, JSON.stringify(closedBanners)); return true; } // Aún está dentro del período de cierre return false; } catch (error) { console.error('Error checking banner visibility:', error); return true; // En caso de error, mostrar el banner } } /** * Mueve el floating banner al body para asegurar posicionamiento correcto * Esto evita que el contenedor padre (ej: header) limite el posicionamiento */ function initFloatingBanner() { const banner = document.querySelector('.floating-banner'); if (!banner) return; // Obtener el ID del banner const bannerId = banner.id.replace('floating-banner-', ''); // Verificar si debe mostrarse if (!shouldShowBanner(bannerId)) { banner.remove(); return; } // Mover al body si no está ya ahí if (banner.parentElement.tagName !== 'BODY') { document.body.appendChild(banner); } // Agregar clase para activar la animación después del reposicionamiento requestAnimationFrame(() => { banner.classList.add('is-ready'); }); } /** * Cierra el floating banner y guarda el estado en localStorage * @param {string} id - ID del banner a cerrar * @param {number} expirationDays - Días antes de volver a mostrar (opcional) */ function closeFloatingBanner(id, expirationDays = BANNER_CONFIG.defaultExpirationDays) { const banner = document.getElementById(`floating-banner-${id}`); if (!banner) return; try { // Obtener datos existentes const stored = localStorage.getItem(BANNER_CONFIG.storageKey); const closedBanners = stored ? JSON.parse(stored) : {}; // Calcular fecha de expiración const now = Date.now(); const expiresAt = now + (expirationDays * 24 * 60 * 60 * 1000); // Guardar información del banner cerrado closedBanners[id] = { closedAt: now, expiresAt: expiresAt, bannerId: id, }; // Guardar en localStorage localStorage.setItem(BANNER_CONFIG.storageKey, JSON.stringify(closedBanners)); // Ocultar el banner con animación banner.style.animation = 'slideOutToBottom 0.3s ease-in'; setTimeout(() => { banner.remove(); }, 300); } catch (error) { console.error('Error closing banner:', error); // Fallback: solo ocultar sin persistencia banner.style.display = 'none'; } } /** * Limpia banners expirados del localStorage * Se ejecuta al cargar la página para mantener el storage limpio */ function cleanupExpiredBanners() { try { const stored = localStorage.getItem(BANNER_CONFIG.storageKey); if (!stored) return; const closedBanners = JSON.parse(stored); const now = Date.now(); let hasChanges = false; Object.keys(closedBanners).forEach(bannerId => { if (now > closedBanners[bannerId].expiresAt) { delete closedBanners[bannerId]; hasChanges = true; } }); if (hasChanges) { if (Object.keys(closedBanners).length === 0) { localStorage.removeItem(BANNER_CONFIG.storageKey); } else { localStorage.setItem(BANNER_CONFIG.storageKey, JSON.stringify(closedBanners)); } } } catch (error) { console.error('Error cleaning up expired banners:', error); } } // Ejecutar cuando el DOM esté listo if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { cleanupExpiredBanners(); initFloatingBanner(); }); } else { // DOM ya está listo cleanupExpiredBanners(); initFloatingBanner(); }