| 'use client'; | |
| /** | |
| * PWA utilities: install prompt, registration, update detection. | |
| */ | |
| let deferredPrompt: BeforeInstallPromptEvent | null = null; | |
| interface BeforeInstallPromptEvent extends Event { | |
| prompt(): Promise<void>; | |
| userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>; | |
| } | |
| export function initPWA(): void { | |
| if (typeof window === 'undefined') return; | |
| window.addEventListener('beforeinstallprompt', (e: Event) => { | |
| e.preventDefault(); | |
| deferredPrompt = e as BeforeInstallPromptEvent; | |
| window.dispatchEvent(new CustomEvent('pwa-installable')); | |
| }); | |
| window.addEventListener('appinstalled', () => { | |
| deferredPrompt = null; | |
| window.dispatchEvent(new CustomEvent('pwa-installed')); | |
| }); | |
| } | |
| export function canInstallPWA(): boolean { | |
| return deferredPrompt !== null; | |
| } | |
| export async function installPWA(): Promise<boolean> { | |
| if (!deferredPrompt) return false; | |
| await deferredPrompt.prompt(); | |
| const { outcome } = await deferredPrompt.userChoice; | |
| deferredPrompt = null; | |
| return outcome === 'accepted'; | |
| } | |
| export function isPWAInstalled(): boolean { | |
| if (typeof window === 'undefined') return false; | |
| return ( | |
| window.matchMedia('(display-mode: standalone)').matches || | |
| (window.navigator as Navigator & { standalone?: boolean }).standalone === true | |
| ); | |
| } | |