"use client"; import { useEffect, useState } from "react"; import { X, Download } from "lucide-react"; import { useConfig } from "@/hooks/use-config"; import { withBasePath } from "@/lib/browser-navigation"; interface BeforeInstallPromptEvent extends Event { prompt: () => Promise; userChoice: Promise<{ outcome: "accepted" | "dismissed" }>; } const DISMISSED_KEY = "pwa-install-dismissed"; export function PWAInstallPrompt() { const [deferredPrompt, setDeferredPrompt] = useState(null); const [showPrompt, setShowPrompt] = useState(false); const { appName, faviconUrl, appLogoLightUrl, appLogoDarkUrl } = useConfig(); useEffect(() => { if (localStorage.getItem(DISMISSED_KEY)) return; const handler = (e: Event) => { e.preventDefault(); setDeferredPrompt(e as BeforeInstallPromptEvent); setShowPrompt(true); }; window.addEventListener("beforeinstallprompt", handler); return () => { window.removeEventListener("beforeinstallprompt", handler); }; }, []); const handleInstall = async () => { if (!deferredPrompt) return; deferredPrompt.prompt(); const { outcome } = await deferredPrompt.userChoice; if (outcome === "accepted") { setDeferredPrompt(null); setShowPrompt(false); } }; const handleDismiss = () => { setShowPrompt(false); }; const handleDismissForever = () => { localStorage.setItem(DISMISSED_KEY, "1"); setShowPrompt(false); }; if (!showPrompt || !deferredPrompt) { return null; } const logoSrc = withBasePath(appLogoLightUrl || faviconUrl); const darkLogoSrc = withBasePath(appLogoDarkUrl || faviconUrl); return (
{logoSrc ? ( {appName} ) : ( )} {logoSrc && ( {appName} )}

Install {appName}

Install our app for quick access and offline support.

); }