60 lines
1.7 KiB
TypeScript
Executable File
60 lines
1.7 KiB
TypeScript
Executable File
import { useState, useEffect } from 'react';
|
|
|
|
interface BeforeInstallPromptEvent extends Event {
|
|
prompt(): Promise<void>;
|
|
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
|
|
}
|
|
|
|
export function usePWAInstall() {
|
|
const [deferredPrompt, setDeferredPrompt] = useState<BeforeInstallPromptEvent | null>(null);
|
|
const [isInstallable, setIsInstallable] = useState(false);
|
|
const [isInstalled, setIsInstalled] = useState(false);
|
|
|
|
useEffect(() => {
|
|
// Check if app is already installed
|
|
if (window.matchMedia('(display-mode: standalone)').matches) {
|
|
setIsInstalled(true);
|
|
}
|
|
|
|
const handleBeforeInstallPrompt = (e: BeforeInstallPromptEvent) => {
|
|
e.preventDefault();
|
|
setDeferredPrompt(e);
|
|
setIsInstallable(true);
|
|
};
|
|
|
|
const handleAppInstalled = () => {
|
|
setIsInstalled(true);
|
|
setIsInstallable(false);
|
|
setDeferredPrompt(null);
|
|
};
|
|
|
|
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt as EventListener);
|
|
window.addEventListener('appinstalled', handleAppInstalled);
|
|
|
|
return () => {
|
|
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt as EventListener);
|
|
window.removeEventListener('appinstalled', handleAppInstalled);
|
|
};
|
|
}, []);
|
|
|
|
const install = async (): Promise<'accepted' | 'dismissed' | 'unavailable'> => {
|
|
if (!deferredPrompt) {
|
|
return 'unavailable';
|
|
}
|
|
|
|
await deferredPrompt.prompt();
|
|
const { outcome } = await deferredPrompt.userChoice;
|
|
|
|
setDeferredPrompt(null);
|
|
setIsInstallable(false);
|
|
|
|
return outcome;
|
|
};
|
|
|
|
return {
|
|
isInstallable,
|
|
isInstalled,
|
|
install,
|
|
canInstall: isInstallable && !isInstalled
|
|
};
|
|
} |