// src/pwaInstall.js /** * Détecte si l'application est déjà installée et lancée en mode PWA */ export function isRunningAsPWA() { // Vérifie si l'app est en mode standalone (PWA installé) if (window.matchMedia('(display-mode: standalone)').matches) { return true; } // Vérifie navigator.standalone (iOS) if (window.navigator.standalone === true) { return true; } // Vérifie si lancé depuis un raccourci installé if (document.referrer.includes('android-app://')) { return true; } return false; } /** * Vérifie si l'installation a déjà été faite (localStorage) */ function isAlreadyInstalled() { try { return localStorage.getItem('pwa-installed') === 'true'; } catch { return false; } } /** * Marque l'app comme installée dans localStorage */ function markAsInstalled() { try { localStorage.setItem('pwa-installed', 'true'); } catch (e) { console.warn('Could not save PWA install state:', e); } } let deferredPrompt = null; let promptShown = false; let iosHintShown = false; function isIOS() { if (typeof navigator === "undefined") return false; const ua = navigator.userAgent || ""; const iOSDevice = /iphone|ipad|ipod/i.test(ua); const iPadOS = ua.includes("Mac") && "ontouchend" in document; return iOSDevice || iPadOS; } function isSafari() { if (typeof navigator === "undefined") return false; const ua = navigator.userAgent || ""; const isIOSChrome = /crios/i.test(ua); const isIOSFirefox = /fxios/i.test(ua); const isIOSEdge = /edgios/i.test(ua); const isSafariUA = /safari/i.test(ua); return isSafariUA && !isIOSChrome && !isIOSFirefox && !isIOSEdge; } function showIOSInstallHint() { if (iosHintShown) return; iosHintShown = true; alert( "iOS: pour installer l'app, ouvre le menu Partager (icône carré + flèche), puis choisis “Sur l’écran d’accueil”." ); } // Écoute l'événement d'installation window.addEventListener('beforeinstallprompt', (e) => { // Ne rien faire si déjà en mode PWA if (isRunningAsPWA()) { console.log('Already running as PWA, skipping install prompt'); return; } // Ne rien faire si déjà installé if (isAlreadyInstalled()) { console.log('PWA already installed, skipping prompt'); return; } e.preventDefault(); deferredPrompt = e; console.log('PWA install prompt ready - waiting for manual click'); // Pas de prompt automatique - l'utilisateur cliquera sur le bouton s'il veut installer }); // Écoute l'événement quand l'app est installée window.addEventListener('appinstalled', () => { console.log('PWA was installed'); markAsInstalled(); deferredPrompt = null; }); /** * Affiche le prompt d'installation */ function showInstallPrompt() { if (!deferredPrompt || promptShown || isRunningAsPWA()) { return; } deferredPrompt.prompt(); promptShown = true; deferredPrompt.userChoice.then((choice) => { console.log('Install outcome:', choice.outcome); if (choice.outcome === 'accepted') { markAsInstalled(); } deferredPrompt = null; }); } /** * Fonction exportée pour déclencher manuellement l'installation * IMPORTANT: Le clic manuel ignore promptShown pour permettre de réessayer */ export function promptInstall() { if (isRunningAsPWA()) { console.log('Already running as PWA, no need to install'); alert('App is already installed!'); return false; } if (isIOS() && isSafari()) { showIOSInstallHint(); return true; } if (deferredPrompt) { // Clic manuel - force l'affichage même si déjà montré console.log('Showing install prompt (manual trigger)'); deferredPrompt.prompt(); deferredPrompt.userChoice.then((choice) => { console.log('Install outcome:', choice.outcome); if (choice.outcome === 'accepted') { markAsInstalled(); } deferredPrompt = null; }); return true; } else { console.log('No install prompt available - browser may not support PWA install or already installed'); if (isIOS() && isSafari()) { showIOSInstallHint(); return true; } alert('PWA installation not available. Make sure you are using a supported browser (Chrome, Edge, Safari).'); return false; } } /** * Vérifie si le prompt d'installation est disponible */ export function canInstall() { if (isRunningAsPWA() || isAlreadyInstalled()) return false; if (isIOS() && isSafari()) return true; return deferredPrompt !== null; }