"use client"; import { useEffect, useState, type ReactNode } from "react"; import { usePathname, useSearchParams } from "next/navigation"; import NavigationLoader from "./NavigationLoader"; import { isInternalNavigationClick, startNavigation, stopNavigation, subscribeNavigationLoading, } from "@/app/lib/navigation-loading"; const LOADING_TIMEOUT_MS = 12000; function shouldStartForHistoryUrl(nextUrl: string | URL | null | undefined) { if (!nextUrl) return false; try { const url = new URL(String(nextUrl), window.location.href); return ( url.pathname !== window.location.pathname || url.search !== window.location.search ); } catch { return true; } } export default function NavigationLoadingProvider({ children, }: { children: ReactNode; }) { const pathname = usePathname(); const searchParams = useSearchParams(); const [visible, setVisible] = useState(false); useEffect(() => subscribeNavigationLoading(setVisible), []); useEffect(() => { stopNavigation(); }, [pathname, searchParams]); useEffect(() => { if (!visible) return; const timeout = window.setTimeout(() => stopNavigation(), LOADING_TIMEOUT_MS); return () => window.clearTimeout(timeout); }, [visible]); useEffect(() => { const onDocumentClick = (event: MouseEvent) => { const target = event.target; if (!(target instanceof Element)) return; const anchor = target.closest("a"); if (!(anchor instanceof HTMLAnchorElement)) return; if (isInternalNavigationClick(event, anchor)) { startNavigation(); } }; const onPopState = () => startNavigation(); const originalPushState = history.pushState.bind(history); const originalReplaceState = history.replaceState.bind(history); history.pushState = (...args) => { if (shouldStartForHistoryUrl(args[2])) { startNavigation(); } return originalPushState(...args); }; history.replaceState = (...args) => { if (shouldStartForHistoryUrl(args[2])) { startNavigation(); } return originalReplaceState(...args); }; document.addEventListener("click", onDocumentClick, true); window.addEventListener("popstate", onPopState); return () => { document.removeEventListener("click", onDocumentClick, true); window.removeEventListener("popstate", onPopState); history.pushState = originalPushState; history.replaceState = originalReplaceState; }; }, []); return ( <> {children} {visible ? : null} ); }