"use client"; import { useEffect, useState } from "react"; import { X, Download, Share } from "lucide-react"; import { Button } from "@/components/ui/button"; const DISMISSED_KEY = "epicure:install-prompt-dismissed"; const IOS_DISMISSED_KEY = "epicure:ios-install-hint-dismissed"; type BeforeInstallPromptEvent = Event & { prompt: () => Promise; userChoice: Promise<{ outcome: "accepted" | "dismissed" }>; }; function isStandalone(): boolean { return window.matchMedia("(display-mode: standalone)").matches || (navigator as { standalone?: boolean }).standalone === true; } /** iOS Safari has no beforeinstallprompt and no programmatic install API at * all (Apple restriction, not a capability gap we can code around) — the * only path is the user manually using the Share sheet, so the best we can * do is tell them that. */ function isIosSafari(): boolean { const ua = navigator.userAgent; const isIos = /iPad|iPhone|iPod/.test(ua) || (ua.includes("Macintosh") && navigator.maxTouchPoints > 1); const isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(ua); return isIos && isSafari; } /** Chromium (Chrome/Edge/Android) shows an "Install" button driven by the * real beforeinstallprompt event; iOS Safari — which never fires it — gets * a static instructional banner instead. Both are no-ops once the app is * already installed (standalone display mode). */ export function InstallPrompt() { const [deferredEvent, setDeferredEvent] = useState(null); const [dismissed, setDismissed] = useState(() => typeof localStorage !== "undefined" && localStorage.getItem(DISMISSED_KEY) === "true"); const [showIosHint, setShowIosHint] = useState( () => typeof window !== "undefined" && isIosSafari() && !isStandalone() && localStorage.getItem(IOS_DISMISSED_KEY) !== "true" ); useEffect(() => { function handler(e: Event) { e.preventDefault(); setDeferredEvent(e as BeforeInstallPromptEvent); } window.addEventListener("beforeinstallprompt", handler); return () => window.removeEventListener("beforeinstallprompt", handler); }, []); function dismiss() { localStorage.setItem(DISMISSED_KEY, "true"); setDismissed(true); } function dismissIosHint() { localStorage.setItem(IOS_DISMISSED_KEY, "true"); setShowIosHint(false); } async function install() { if (!deferredEvent) return; await deferredEvent.prompt(); await deferredEvent.userChoice; setDeferredEvent(null); } if (showIosHint) { return (

Install Epicure

Tap Share, then "Add to Home Screen".

); } if (!deferredEvent || dismissed) return null; return (

Install Epicure

Add to your home screen for quick access.

); }