once load splash

This commit is contained in:
hamid zarghami
2026-06-06 10:04:47 +03:30
parent e948b00f55
commit 2ae99faca9
12 changed files with 201 additions and 64 deletions
+15
View File
@@ -0,0 +1,15 @@
'use client';
import { useEffect } from 'react';
export default function PwaServiceWorker() {
useEffect(() => {
if (!('serviceWorker' in navigator)) return;
navigator.serviceWorker.register('/sw.js', { scope: '/' }).catch(() => {
// Registration can fail on unsupported contexts (e.g. in-app browsers)
});
}, []);
return null;
}
+25 -11
View File
@@ -69,7 +69,16 @@ const isIOS = () => {
const isStandalone = () => {
if (typeof window === 'undefined') return false;
return ('standalone' in window.navigator) && (window.navigator as { standalone?: boolean }).standalone === true;
const isIOSStandalone =
('standalone' in window.navigator) &&
(window.navigator as { standalone?: boolean }).standalone === true;
const isDisplayModeStandalone =
window.matchMedia('(display-mode: standalone)').matches ||
window.matchMedia('(display-mode: fullscreen)').matches;
return isIOSStandalone || isDisplayModeStandalone;
};
function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeState }: Props) {
@@ -114,18 +123,23 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS
setIsIOSDevice(ios);
setIsPWAInstalled(standalone);
if (!ios) {
const handleBeforeInstallPrompt = (e: Event) => {
e.preventDefault();
setDeferredPrompt(e as BeforeInstallPromptEvent);
};
const handleBeforeInstallPrompt = (e: Event) => {
e.preventDefault();
setDeferredPrompt(e as BeforeInstallPromptEvent);
};
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
const handleAppInstalled = () => {
setDeferredPrompt(null);
setIsPWAInstalled(true);
};
return () => {
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
};
}
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
window.addEventListener('appinstalled', handleAppInstalled);
return () => {
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
window.removeEventListener('appinstalled', handleAppInstalled);
};
}, []);
const handleInstallPWA = async () => {
+39 -8
View File
@@ -2,10 +2,19 @@
import usePreference from '@/hooks/helpers/usePreference';
import React, { useCallback, useEffect, useState } from 'react';
import { useParams } from 'next/navigation';
import { useGetAbout } from '@/app/[name]/(Main)/about/hooks/useAboutData';
import SplashScreen from '@/components/overlays/SplashScreen';
import { hexToOklch, calculateBrightness } from '@/lib/helpers/colorUtils';
function getSplashStorageKey(restaurantSlug: string) {
return `splash-seen:${restaurantSlug}`;
}
function getSplashFingerprint(logo?: string | null, name?: string | null) {
return `${logo ?? ''}|${name ?? ''}`;
}
type Props = {
children: React.ReactNode
}
@@ -24,6 +33,9 @@ function applyPrimaryColor(colorHex: string) {
}
function PreferenceWrapper({ children }: Props) {
const params = useParams();
const restaurantSlug = typeof params.name === 'string' ? params.name : '';
const { state: nightMode } = usePreference('night-mode', false);
const { data: aboutData } = useGetAbout();
@@ -34,7 +46,14 @@ function PreferenceWrapper({ children }: Props) {
const handleSplashDismiss = useCallback(() => {
setShowSplash(false);
}, []);
if (!restaurantSlug) return;
const logo = aboutData?.data?.logo || cachedLogo;
const name = aboutData?.data?.name || cachedName;
const fingerprint = getSplashFingerprint(logo, name);
localStorage.setItem(getSplashStorageKey(restaurantSlug), fingerprint);
}, [aboutData?.data?.logo, aboutData?.data?.name, cachedLogo, cachedName, restaurantSlug]);
useEffect(() => {
setMounted(true);
@@ -49,16 +68,15 @@ function PreferenceWrapper({ children }: Props) {
if (savedLogo) setCachedLogo(savedLogo);
if (savedName) setCachedName(savedName);
const navigationEntries = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[];
const isReload = navigationEntries.length > 0 && navigationEntries[0].type === 'reload';
const isFirstLoadInSession = !sessionStorage.getItem('app-loaded') || isReload;
if (!restaurantSlug) return;
if (isFirstLoadInSession) {
const currentFingerprint = getSplashFingerprint(savedLogo, savedName);
const seenFingerprint = localStorage.getItem(getSplashStorageKey(restaurantSlug));
if (seenFingerprint !== currentFingerprint) {
setShowSplash(true);
}
sessionStorage.setItem('app-loaded', 'true');
}, []);
}, [restaurantSlug]);
useEffect(() => {
if (aboutData?.data?.menuColor) {
@@ -76,6 +94,19 @@ function PreferenceWrapper({ children }: Props) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [aboutData?.data?.menuColor]);
useEffect(() => {
if (!restaurantSlug || showSplash) return;
const logo = aboutData?.data?.logo || cachedLogo;
const name = aboutData?.data?.name || cachedName;
const fingerprint = getSplashFingerprint(logo, name);
const seenFingerprint = localStorage.getItem(getSplashStorageKey(restaurantSlug));
if (seenFingerprint === '|' && fingerprint !== '|') {
localStorage.setItem(getSplashStorageKey(restaurantSlug), fingerprint);
}
}, [aboutData?.data?.logo, aboutData?.data?.name, cachedLogo, cachedName, restaurantSlug, showSplash]);
useEffect(() => {
document.documentElement.setAttribute('data-theme', nightMode ? 'dark' : 'light');
}, [nightMode]);