handle safari

This commit is contained in:
hamid zarghami
2025-12-15 16:58:31 +03:30
parent 2a07c722c9
commit b383e54c88
2 changed files with 83 additions and 17 deletions
+75 -15
View File
@@ -57,6 +57,17 @@ type BeforeInstallPromptEvent = Event & {
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>; 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) { function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeState }: Props) {
const menuStateMemo = useMemo(() => menuState, [menuState]); const menuStateMemo = useMemo(() => menuState, [menuState]);
const closeRef = useRef<HTMLDivElement>(null); const closeRef = useRef<HTMLDivElement>(null);
@@ -65,6 +76,8 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
const { state: shareModal, toggle: toggleShareModal } = useToggle(); const { state: shareModal, toggle: toggleShareModal } = useToggle();
const { state: installPwaModal, toggle: toggleInstallPwaModal } = useToggle(); const { state: installPwaModal, toggle: toggleInstallPwaModal } = useToggle();
const [deferredPrompt, setDeferredPrompt] = useState<BeforeInstallPromptEvent | null>(null); const [deferredPrompt, setDeferredPrompt] = useState<BeforeInstallPromptEvent | null>(null);
const [isIOSDevice, setIsIOSDevice] = useState(false);
const [isPWAInstalled, setIsPWAInstalled] = useState(false);
const params = useParams(); const params = useParams();
const { name } = params; const { name } = params;
@@ -85,16 +98,23 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
}; };
useEffect(() => { useEffect(() => {
const handleBeforeInstallPrompt = (e: Event) => { const ios = isIOS();
e.preventDefault(); const standalone = isStandalone();
setDeferredPrompt(e as BeforeInstallPromptEvent); setIsIOSDevice(ios);
}; setIsPWAInstalled(standalone);
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt); if (!ios) {
const handleBeforeInstallPrompt = (e: Event) => {
e.preventDefault();
setDeferredPrompt(e as BeforeInstallPromptEvent);
};
return () => { window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
}; return () => {
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
};
}
}, []); }, []);
const handleInstallPWA = async () => { const handleInstallPWA = async () => {
@@ -131,6 +151,7 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
.filter(item => { .filter(item => {
if (item.auth && !userIsAuthenticated) return false; if (item.auth && !userIsAuthenticated) return false;
if (item.guestOnly && userIsAuthenticated) return false; if (item.guestOnly && userIsAuthenticated) return false;
if (item.href === '?installpwa' && isPWAInstalled) return false;
return true; return true;
}) })
.map(({ icon: Icon, ...item }, index) => { .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} /> <DirectInbox className="inline-block ml-2 mb-1.5 stroke-primary dark:stroke-foreground" size={24} />
{tInstallPwaModal('Heading')} {tInstallPwaModal('Heading')}
</h2> </h2>
<p className="text-xs font-medium mt-6"> {isPWAInstalled ? (
{tInstallPwaModal('Description')} <p className="mt-6 text-xs font-medium text-center text-foreground/80 dark:text-neutral-200">
</p> {tInstallPwaModal('AlreadyInstalled')}
</p>
<Button onClick={handleInstallPWA} className="text-sm mt-8" disabled={!deferredPrompt}> ) : isIOSDevice ? (
<span className="font-light">{tInstallPwaModal('ButtonOk')}</span> <div className="mt-5 rounded-3xl bg-black/5 px-4 py-5 backdrop-blur-sm dark:bg-white/5">
</Button> <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> </Modal>
</> </>
+8 -2
View File
@@ -50,8 +50,14 @@
}, },
"InstallPwaModal": { "InstallPwaModal": {
"Heading": "نصب اپلیکیشن", "Heading": "نصب اپلیکیشن",
"Description": "برای نصب کلیک کنید.", "Description": "برای نصب اپلیکیشن روی دستگاه خود، از دکمه زیر استفاده کنید.",
"ButtonOk": "نصب کن" "ButtonOk": "نصب کن",
"AlreadyInstalled": "اپلیکیشن قبلاً روی دستگاه شما نصب شده است.",
"IOSDescription": "برای نصب اپلیکیشن در Safari مراحل زیر را انجام دهید:",
"IOSStep1": "از نوار پایین، روی دکمه اشتراک‌گذاری (Share) بزنید.",
"IOSStep2": "در منوی باز شده، گزینه «Add to Home Screen» را انتخاب کنید.",
"IOSStep3": "در صفحه بعدی روی دکمه «Add» در گوشه بالا بزنید.",
"ChromeFallback": "اگر دکمه نصب را نمی‌بینید، یا اپلیکیشن قبلاً نصب شده است یا مرورگر هنوز امکان نصب را فعال نکرده است. کمی بعد دوباره تلاش کنید یا از منوی مرورگر گزینه نصب در صفحه اصلی را انتخاب کنید."
}, },
"SearchPlaceholder": "جستجو" "SearchPlaceholder": "جستجو"
} }