diff --git a/src/front/Stores/WindowStore.ts b/src/front/Stores/WindowStore.ts index d15a1538..42abcabb 100644 --- a/src/front/Stores/WindowStore.ts +++ b/src/front/Stores/WindowStore.ts @@ -36,6 +36,10 @@ export default class WindowStore { } private iniEvents(): void { + if (typeof window === 'undefined' || typeof document === 'undefined') { + // SSR: do not bind browser events + return; + } window.addEventListener("scroll", (e: Event) => this.scrollYHandler()); window.addEventListener("resize", (e: Event) => this.resizeHandler()); document.addEventListener("click", (e: MouseEvent) => this.clickHandler(e), true); @@ -46,10 +50,11 @@ export default class WindowStore { } private scrollYHandler = (() => { - let previousY: number = window.scrollY; + let previousY: number = (typeof window !== 'undefined' ? window.scrollY : 0); let snapShotY: number = previousY; let previousYDirection: number = 1; return (): void => { + if (typeof window === 'undefined') return; const scrollYDirection = window.scrollY - previousY > 0 ? 1 : -1; if (previousYDirection !== scrollYDirection) { snapShotY = window.scrollY; @@ -62,6 +67,7 @@ export default class WindowStore { })(); private resizeHandler() { + if (typeof window === 'undefined') return; this.event.emit("resize", window); } } diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 4597a416..61464e44 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -6,11 +6,13 @@ import type { AppType, AppProps } from "next/app"; import { useEffect, useState, type ReactElement, type ReactNode } from "react"; import getConfig from "next/config"; import { GoogleTagManager } from "@next/third-parties/google"; +import dynamic from 'next/dynamic'; import Loader from "src/common/Api/LeCoffreApi/sdk/Loader"; import IframeReference from "src/sdk/IframeReference"; -import Iframe from "src/sdk/Iframe"; +// import Iframe from "src/sdk/Iframe"; +const IframeNoSSR = dynamic(() => import('src/sdk/Iframe'), { ssr: false }); import MessageBus from "src/sdk/MessageBus"; import User from "src/sdk/User"; @@ -80,26 +82,31 @@ const MyApp = (({ const [isConnected, setIsConnected] = useState(false); const [isReady, setIsReady] = useState(false); + const [mounted, setMounted] = useState(false); - const targetOrigin = (() => { - try { - return new URL(_4nkUrl).origin; - } catch { - return _4nkUrl; - } - })(); - IframeReference.setTargetOrigin(targetOrigin); + // Configure iframe target and URL on client-side only + useEffect(() => { + setMounted(true); + try { + if (_4nkUrl && typeof _4nkUrl === 'string' && _4nkUrl.trim().length > 0) { + const origin = (() => { + try { return new URL(_4nkUrl).origin; } catch { return _4nkUrl; } + })(); + IframeReference.setTargetOrigin(origin); - // Configure full iframe URL if provided (falls back to origin) - const iframeUrl = (() => { - const candidate = (publicRuntimeConfig as any).NEXT_PUBLIC_4NK_IFRAME_URL ?? _4nkUrl; - try { - return new URL(candidate).toString(); - } catch { - return targetOrigin; - } - })(); - IframeReference.setIframeUrl(iframeUrl); + const candidate = (publicRuntimeConfig as any).NEXT_PUBLIC_4NK_IFRAME_URL ?? _4nkUrl; + const iframe = (() => { + try { return new URL(candidate).toString(); } catch { return origin; } + })(); + IframeReference.setIframeUrl(iframe); + } else { + console.warn('[MyApp] NEXT_PUBLIC_4NK_URL is missing; skipping iframe setup'); + } + } catch (e) { + console.error('[MyApp] Failed to initialize IframeReference', e); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); useEffect(() => { const isAuthenticated = User.getInstance().isAuthenticated(); @@ -117,7 +124,12 @@ const MyApp = (({ return () => { }; }, []); - // Hotjar supprimé + // Empêcher le rendu SSR du contenu qui dépend du navigateur + if (!mounted) { + return ; + } + + // Hotjar supprimé return getLayout( <> @@ -126,7 +138,7 @@ const MyApp = (({ } - {isConnected &&