From a197f661faaf32a122f8a07898fc3b5587cb420e Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sun, 18 Jan 2026 00:57:34 +0000 Subject: [PATCH] Centralize PWA install prompt state --- src/components/PWAInstallPrompt.tsx | 36 ++++++++--------------------- src/hooks/use-pwa.ts | 32 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/components/PWAInstallPrompt.tsx b/src/components/PWAInstallPrompt.tsx index 9080312..86681af 100644 --- a/src/components/PWAInstallPrompt.tsx +++ b/src/components/PWAInstallPrompt.tsx @@ -1,4 +1,3 @@ -import { useState, useEffect } from 'react' import { Button } from '@/components/ui/button' import { Card } from '@/components/ui/card' import { Download, X, DeviceMobile, Desktop } from '@phosphor-icons/react' @@ -6,41 +5,26 @@ import { motion, AnimatePresence } from 'framer-motion' import { usePWA } from '@/hooks/use-pwa' export function PWAInstallPrompt() { - const { isInstallable, installApp } = usePWA() - const [dismissed, setDismissed] = useState(false) - const [showPrompt, setShowPrompt] = useState(false) - - useEffect(() => { - const hasBeenDismissed = localStorage.getItem('pwa-install-dismissed') - if (hasBeenDismissed) { - setDismissed(true) - } - - const timer = setTimeout(() => { - if (isInstallable && !hasBeenDismissed) { - setShowPrompt(true) - } - }, 3000) - - return () => clearTimeout(timer) - }, [isInstallable]) + const { + isInstallable, + isInstallPromptDismissed, + isInstallPromptVisible, + installApp, + dismissInstallPrompt, + } = usePWA() const handleInstall = async () => { const success = await installApp() - if (success) { - setShowPrompt(false) - } + if (success) return } const handleDismiss = () => { - setShowPrompt(false) - setDismissed(true) - localStorage.setItem('pwa-install-dismissed', 'true') + dismissInstallPrompt() } return ( - {isInstallable && !dismissed && showPrompt && ( + {isInstallable && !isInstallPromptDismissed && isInstallPromptVisible && ( ({ isInstallable: false, isInstalled: false, @@ -25,6 +27,10 @@ export function usePWA() { useEffect(() => { if (typeof window === 'undefined') return + const storedDismissed = window.localStorage.getItem('pwa-install-dismissed') + if (storedDismissed) { + setInstallPromptDismissed(true) + } const checkInstalled = () => { try { @@ -52,6 +58,7 @@ export function usePWA() { const handleAppInstalled = () => { setState(prev => ({ ...prev, isInstalled: true, isInstallable: false })) setDeferredPrompt(null) + setInstallPromptVisible(false) } const handleOnline = () => { @@ -104,10 +111,24 @@ export function usePWA() { } }, []) + useEffect(() => { + if (!state.isInstallable || state.isInstalled || isInstallPromptDismissed) { + setInstallPromptVisible(false) + return + } + + const timer = window.setTimeout(() => { + setInstallPromptVisible(true) + }, 3000) + + return () => window.clearTimeout(timer) + }, [state.isInstallable, state.isInstalled, isInstallPromptDismissed]) + const installApp = async () => { if (!deferredPrompt) return false try { + setInstallPromptVisible(false) await deferredPrompt.prompt() const choiceResult = await deferredPrompt.userChoice @@ -123,6 +144,14 @@ export function usePWA() { } } + const dismissInstallPrompt = () => { + setInstallPromptDismissed(true) + setInstallPromptVisible(false) + if (typeof window !== 'undefined') { + window.localStorage.setItem('pwa-install-dismissed', 'true') + } + } + const updateApp = () => { if (state.registration) { state.registration.waiting?.postMessage({ type: 'SKIP_WAITING' }) @@ -165,7 +194,10 @@ export function usePWA() { return { ...state, + isInstallPromptDismissed, + isInstallPromptVisible, installApp, + dismissInstallPrompt, updateApp, clearCache, requestNotificationPermission,