diff --git a/assets/app.js b/assets/app.js index 0de7354..22650d7 100644 --- a/assets/app.js +++ b/assets/app.js @@ -4,18 +4,18 @@ import '@grafikart/drop-files-element' import {PaymentForm} from './PaymentForm' import * as Sentry from "@sentry/browser"; -// --- CLÉS DE STOCKAGE ET VAPID --- +// --- CONFIGURATION ET ETAT --- const VAPID_PUBLIC_KEY = "BKz0kdcsG6kk9KxciPpkfP8kEDAd408inZecij5kBDbQ1ZGZSNwS4KZ8FerC28LFXvgSqpDXtor3ePo0zBCdNqo"; const COOKIE_STORAGE_KEY = 'cookies_accepted'; +let userMenuTimeout; // Pour gérer le délai de fermeture du menu -// --- MESSAGES ET TRADUCTIONS --- const MESSAGES = { fr: { notificationTitle: "🔔 Activer les notifications", notificationText: "Recevez les nouvelles, les promotions et les événements de l'association.", notificationButton: "Activer", notificationClose: "Fermer la notification", - cookieText: 'Ce site utilise uniquement des cookies de fonctionnement et de sécurité essentiels. Aucune donnée personnelle n\'est collectée.', + cookieText: 'Ce site utilise uniquement des cookies de fonctionnement et de sécurité essentiels.', cookieLink: "Politique de cookies", cookieButton: "Accepter", }, @@ -24,7 +24,7 @@ const MESSAGES = { notificationText: "Receive news, promotions, and association events.", notificationButton: "Enable", notificationClose: "Close notification", - cookieText: 'This website only uses functional and security cookies. No personal data is collected.', + cookieText: 'This website only uses functional and security cookies.', cookieLink: "Cookie Policy", cookieButton: "Accept", } @@ -62,12 +62,10 @@ function toggleMenu(button, menu) { * Initialisation de l'UI */ function initializeUI() { - // Reset des menus au chargement document.querySelectorAll('#mobile-menu, #userMenuDesktop, #userMenuMobile').forEach(menu => { menu.classList.add('hidden'); }); - // Panier Latéral const cartSidebar = document.getElementById('cartSidebar'); const cartBackdrop = document.getElementById('cartBackdrop'); @@ -78,7 +76,6 @@ function initializeUI() { cartSidebar.classList.remove('translate-x-full'); cartSidebar.classList.add('translate-x-0'); }; - window.closeCart = () => { document.body.style.overflow = ''; cartSidebar.classList.remove('translate-x-0'); @@ -89,7 +86,6 @@ function initializeUI() { }; } - // Update counters const updateCartDisplay = (count) => { const desktopCounter = document.getElementById('cartCountDesktop'); const mobileCounter = document.getElementById('cartCountMobile'); @@ -98,20 +94,47 @@ function initializeUI() { }; updateCartDisplay(0); + // Initialisation spécifique au menu utilisateur (Desktop) + setupUserMenuHover(); + if ('Notification' in window && Notification.permission === 'granted') { subscribeAndSave(); } } -// --- LOGIQUE PUSH NOTIFICATIONS --- +/** + * Gestion du survol du menu utilisateur pour éviter la fermeture brutale + */ +function setupUserMenuHover() { + const btn = document.getElementById('userMenuButtonDesktop'); + const menu = document.getElementById('userMenuDesktop'); + + if (!btn || !menu) return; + + const open = () => { + clearTimeout(userMenuTimeout); + menu.classList.remove('hidden'); + }; + + const close = () => { + userMenuTimeout = setTimeout(() => { + menu.classList.add('hidden'); + }, 200); // Délai de 200ms pour laisser le temps de passer du bouton au menu + }; + + btn.addEventListener('mouseenter', open); + btn.addEventListener('mouseleave', close); + menu.addEventListener('mouseenter', open); + menu.addEventListener('mouseleave', close); +} + +// --- LOGIQUE PUSH & BANNIÈRES (Inchangé) --- async function subscribeAndSave() { if (!('Notification' in window) || Notification.permission !== 'granted') return; if (!('serviceWorker' in navigator)) return; - try { const registration = await navigator.serviceWorker.ready; let subscription = await registration.pushManager.getSubscription(); - if (!subscription) { const applicationServerKey = urlBase64ToUint8Array(VAPID_PUBLIC_KEY); subscription = await registration.pushManager.subscribe({ @@ -119,15 +142,12 @@ async function subscribeAndSave() { applicationServerKey: applicationServerKey }); } - await fetch('/notificationSub', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ subscription: subscription.toJSON() }) }); - } catch (error) { - console.error("Push Error:", error); - } + } catch (error) { console.error("Push Error:", error); } } async function promptForPermissionAndSubscribe() { @@ -135,18 +155,14 @@ async function promptForPermissionAndSubscribe() { try { const permission = await Notification.requestPermission(); if (permission === 'granted') await subscribeAndSave(); - } catch (error) { - console.error("Permission Error:", error); - } + } catch (error) { console.error("Permission Error:", error); } } -// --- OPTIMISATION PERFORMANCE --- function isPerformanceTestAgent() { const ua = navigator.userAgent; return ua.includes('Lighthouse') || ua.includes('PageSpeed'); } -// --- BANNIÈRES --- function handleNotificationBanner() { if (isPerformanceTestAgent()) return; const BANNER_ID = 'notification-prompt-banner'; @@ -157,7 +173,6 @@ function handleNotificationBanner() { const banner = document.createElement('div'); banner.id = BANNER_ID; banner.className = `fixed bottom-4 left-4 z-50 p-4 max-w-xs bg-indigo-600 text-white rounded-xl shadow-2xl transition-all duration-500 transform opacity-0 translate-y-full md:left-8 md:bottom-8 border-2 border-black`; - banner.innerHTML = `
${M.notificationTitle}
@@ -170,13 +185,11 @@ function handleNotificationBanner() { ${M.notificationButton} `; - document.body.appendChild(banner); setTimeout(() => { banner.classList.remove('opacity-0', 'translate-y-full'); banner.classList.add('opacity-100', 'translate-y-0'); }, 100); - document.getElementById('closeNotificationBanner').addEventListener('click', () => banner.remove()); document.getElementById('activateNotifications').addEventListener('click', async () => { await promptForPermissionAndSubscribe(); @@ -189,12 +202,10 @@ function handleCookieBanner() { if (localStorage.getItem(COOKIE_STORAGE_KEY) === 'true') return; const BANNER_ID = 'cookie-banner'; if (document.getElementById(BANNER_ID)) return; - const M = getLanguageMessages(); const banner = document.createElement('div'); banner.id = BANNER_ID; banner.className = `fixed bottom-4 right-4 z-50 p-6 max-w-sm bg-white border-4 border-black shadow-[10px_10px_0px_rgba(0,0,0,1)] transition-all duration-500 transform opacity-0 translate-y-full`; - banner.innerHTML = `${M.cookieText}