From 95ea5b3e2de752f8e82b43f4357df6f508c86fda Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Wed, 12 Feb 2025 22:01:23 +0100 Subject: [PATCH] fix: masquer l'invite d'installation en mode PWA --- src/components/ui/InstallPWA.tsx | 68 ++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/src/components/ui/InstallPWA.tsx b/src/components/ui/InstallPWA.tsx index 6e12fd5..ae37838 100644 --- a/src/components/ui/InstallPWA.tsx +++ b/src/components/ui/InstallPWA.tsx @@ -1,38 +1,74 @@ "use client"; import { useEffect, useState } from "react"; -import { Download } from "lucide-react"; +import { Download, X } from "lucide-react"; interface BeforeInstallPromptEvent extends Event { prompt: () => Promise; userChoice: Promise<{ outcome: "accepted" | "dismissed" }>; } +const DISMISS_KEY = "pwa-install-dismissed"; +const DISMISS_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 jours en millisecondes + export function InstallPWA() { const [deferredPrompt, setDeferredPrompt] = useState(null); const [isInstallable, setIsInstallable] = useState(false); const [isIOS, setIsIOS] = useState(false); + const [isDismissed, setIsDismissed] = useState(true); + const [isStandalone, setIsStandalone] = useState(true); // Par défaut true pour éviter le flash useEffect(() => { + // Vérifier si on est en mode standalone (PWA) + const checkStandalone = () => { + return ( + window.matchMedia("(display-mode: standalone)").matches || + (window.navigator as any).standalone || + document.referrer.includes("android-app://") + ); + }; + + // Vérifier si l'invite a été fermée récemment + const checkDismissed = () => { + const dismissedAt = localStorage.getItem(DISMISS_KEY); + if (dismissedAt) { + const dismissedTime = parseInt(dismissedAt, 10); + const now = Date.now(); + if (now - dismissedTime < DISMISS_DURATION) { + return true; + } + } + return false; + }; + // Détecter si c'est un appareil iOS - const isIOSDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; + const isIOSDevice = /iPad|iPhone|iPod/.test(navigator.userAgent); setIsIOS(isIOSDevice); + // Initialiser les états + setIsStandalone(checkStandalone()); + setIsDismissed(checkDismissed()); + const handleBeforeInstallPrompt = (e: Event) => { e.preventDefault(); setDeferredPrompt(e as BeforeInstallPromptEvent); - setIsInstallable(true); + if (!checkDismissed() && !checkStandalone()) { + setIsInstallable(true); + } }; window.addEventListener("beforeinstallprompt", handleBeforeInstallPrompt); - // Vérifier si l'app est déjà installée - if (window.matchMedia("(display-mode: standalone)").matches) { - setIsInstallable(false); - } + // Écouter les changements de mode d'affichage + const displayModeQuery = window.matchMedia("(display-mode: standalone)"); + const handleDisplayModeChange = (e: MediaQueryListEvent) => { + setIsStandalone(e.matches); + }; + displayModeQuery.addEventListener("change", handleDisplayModeChange); return () => { window.removeEventListener("beforeinstallprompt", handleBeforeInstallPrompt); + displayModeQuery.removeEventListener("change", handleDisplayModeChange); }; }, []); @@ -53,7 +89,16 @@ export function InstallPWA() { setDeferredPrompt(null); }; - if (!isInstallable && !isIOS) return null; + const handleDismiss = () => { + localStorage.setItem(DISMISS_KEY, Date.now().toString()); + setIsDismissed(true); + }; + + // Ne pas afficher si : + // - L'app n'est pas installable ET ce n'est pas iOS + // - OU si l'invite a été fermée + // - OU si on est en mode standalone (PWA) + if ((!isInstallable && !isIOS) || isDismissed || isStandalone) return null; return (
@@ -81,6 +126,13 @@ export function InstallPWA() { )}
+