handle safari
This commit is contained in:
@@ -57,6 +57,17 @@ type BeforeInstallPromptEvent = Event & {
|
||||
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
|
||||
};
|
||||
|
||||
const isIOS = () => {
|
||||
if (typeof window === 'undefined') return false;
|
||||
return /iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
||||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
||||
};
|
||||
|
||||
const isStandalone = () => {
|
||||
if (typeof window === 'undefined') return false;
|
||||
return ('standalone' in window.navigator) && (window.navigator as { standalone?: boolean }).standalone === true;
|
||||
};
|
||||
|
||||
function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeState }: Props) {
|
||||
const menuStateMemo = useMemo(() => menuState, [menuState]);
|
||||
const closeRef = useRef<HTMLDivElement>(null);
|
||||
@@ -65,6 +76,8 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
|
||||
const { state: shareModal, toggle: toggleShareModal } = useToggle();
|
||||
const { state: installPwaModal, toggle: toggleInstallPwaModal } = useToggle();
|
||||
const [deferredPrompt, setDeferredPrompt] = useState<BeforeInstallPromptEvent | null>(null);
|
||||
const [isIOSDevice, setIsIOSDevice] = useState(false);
|
||||
const [isPWAInstalled, setIsPWAInstalled] = useState(false);
|
||||
|
||||
const params = useParams();
|
||||
const { name } = params;
|
||||
@@ -85,16 +98,23 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleBeforeInstallPrompt = (e: Event) => {
|
||||
e.preventDefault();
|
||||
setDeferredPrompt(e as BeforeInstallPromptEvent);
|
||||
};
|
||||
const ios = isIOS();
|
||||
const standalone = isStandalone();
|
||||
setIsIOSDevice(ios);
|
||||
setIsPWAInstalled(standalone);
|
||||
|
||||
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
|
||||
if (!ios) {
|
||||
const handleBeforeInstallPrompt = (e: Event) => {
|
||||
e.preventDefault();
|
||||
setDeferredPrompt(e as BeforeInstallPromptEvent);
|
||||
};
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
|
||||
};
|
||||
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleInstallPWA = async () => {
|
||||
@@ -131,6 +151,7 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
|
||||
.filter(item => {
|
||||
if (item.auth && !userIsAuthenticated) return false;
|
||||
if (item.guestOnly && userIsAuthenticated) return false;
|
||||
if (item.href === '?installpwa' && isPWAInstalled) return false;
|
||||
return true;
|
||||
})
|
||||
.map(({ icon: Icon, ...item }, index) => {
|
||||
@@ -293,13 +314,52 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
|
||||
<DirectInbox className="inline-block ml-2 mb-1.5 stroke-primary dark:stroke-foreground" size={24} />
|
||||
{tInstallPwaModal('Heading')}
|
||||
</h2>
|
||||
<p className="text-xs font-medium mt-6">
|
||||
{tInstallPwaModal('Description')}
|
||||
</p>
|
||||
|
||||
<Button onClick={handleInstallPWA} className="text-sm mt-8" disabled={!deferredPrompt}>
|
||||
<span className="font-light">{tInstallPwaModal('ButtonOk')}</span>
|
||||
</Button>
|
||||
{isPWAInstalled ? (
|
||||
<p className="mt-6 text-xs font-medium text-center text-foreground/80 dark:text-neutral-200">
|
||||
{tInstallPwaModal('AlreadyInstalled')}
|
||||
</p>
|
||||
) : isIOSDevice ? (
|
||||
<div className="mt-5 rounded-3xl bg-black/5 px-4 py-5 backdrop-blur-sm dark:bg-white/5">
|
||||
<p className="text-xs font-medium leading-relaxed text-center text-foreground/80 dark:text-neutral-200">
|
||||
{tInstallPwaModal('IOSDescription')}
|
||||
</p>
|
||||
<ol className="mt-5 space-y-3 text-xs font-medium rtl:text-right">
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="mt-0.5 flex h-5 w-5 items-center justify-center rounded-full bg-primary/10 text-[11px] font-bold text-primary">
|
||||
۱
|
||||
</span>
|
||||
<span>{tInstallPwaModal('IOSStep1')}</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="mt-0.5 flex h-5 w-5 items-center justify-center rounded-full bg-primary/10 text-[11px] font-bold text-primary">
|
||||
۲
|
||||
</span>
|
||||
<span>{tInstallPwaModal('IOSStep2')}</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="mt-0.5 flex h-5 w-5 items-center justify-center rounded-full bg-primary/10 text-[11px] font-bold text-primary">
|
||||
۳
|
||||
</span>
|
||||
<span>{tInstallPwaModal('IOSStep3')}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<p className="mt-6 text-xs font-medium leading-relaxed text-center text-foreground/80 dark:text-neutral-200">
|
||||
{tInstallPwaModal('Description')}
|
||||
</p>
|
||||
{deferredPrompt ? (
|
||||
<Button onClick={handleInstallPWA} className="mt-8 text-sm">
|
||||
<span className="font-light">{tInstallPwaModal('ButtonOk')}</span>
|
||||
</Button>
|
||||
) : (
|
||||
<p className="mt-4 text-[11px] font-medium leading-relaxed text-center text-foreground/60 dark:text-neutral-300">
|
||||
{tInstallPwaModal('ChromeFallback')}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
</Modal>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user