All checks were successful
Gitea CI / test-build (push) Successful in 11m38s
- Add WebGL support detection in ShaderGradientBackground to prevent console errors - Add .catch() fallback to ShaderGradientBackground dynamic import - Remove hardcoded aria-label from consent banner minimize button (fixes label-content-name-mismatch) - Use rewrite instead of redirect for root locale routing (eliminates one redirect hop) - Change n8n API cache headers from no-store to no-cache (enables bfcache) - Add three and @react-three/fiber to optimizePackageImports for better tree-shaking Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import React, { useEffect, useState } from "react";
|
|
import { usePathname } from "next/navigation";
|
|
import dynamic from "next/dynamic";
|
|
import { ToastProvider } from "@/components/Toast";
|
|
import ErrorBoundary from "@/components/ErrorBoundary";
|
|
import { ConsentProvider } from "./ConsentProvider";
|
|
import { ThemeProvider } from "./ThemeProvider";
|
|
import { motion, AnimatePresence } from "framer-motion";
|
|
|
|
const BackgroundBlobs = dynamic(() => import("@/components/BackgroundBlobs").catch(() => ({ default: () => null })), {
|
|
ssr: false,
|
|
loading: () => null,
|
|
});
|
|
|
|
const ShaderGradientBackground = dynamic(
|
|
() => import("./ShaderGradientBackground").catch(() => ({ default: () => null })),
|
|
{ ssr: false, loading: () => null }
|
|
);
|
|
|
|
export default function ClientProviders({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
const [mounted, setMounted] = useState(false);
|
|
const [is404Page, setIs404Page] = useState(false);
|
|
const pathname = usePathname();
|
|
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
// Check if we're on a 404 page by looking for the data attribute or pathname
|
|
const check404 = () => {
|
|
try {
|
|
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
const has404Component = document.querySelector('[data-404-page]');
|
|
const is404Path = pathname === '/404' || (window.location && (window.location.pathname === '/404' || window.location.pathname.includes('404')));
|
|
setIs404Page(!!has404Component || is404Path);
|
|
}
|
|
} catch (error) {
|
|
// Silently fail - 404 detection is not critical
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.warn('Error checking 404 status:', error);
|
|
}
|
|
}
|
|
};
|
|
// Check immediately and after a short delay
|
|
try {
|
|
check404();
|
|
const timeout = setTimeout(check404, 100);
|
|
const interval = setInterval(check404, 500);
|
|
return () => {
|
|
try {
|
|
clearTimeout(timeout);
|
|
clearInterval(interval);
|
|
} catch {
|
|
// Silently fail during cleanup
|
|
}
|
|
};
|
|
} catch (error) {
|
|
// If setup fails, just return empty cleanup
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.warn('Error setting up 404 check:', error);
|
|
}
|
|
return () => {};
|
|
}
|
|
}, [pathname]);
|
|
|
|
// Wrap in multiple error boundaries to isolate failures
|
|
return (
|
|
<ErrorBoundary>
|
|
<ErrorBoundary>
|
|
<ConsentProvider>
|
|
<ThemeProvider attribute="class" defaultTheme="light" enableSystem={false}>
|
|
<GatedProviders mounted={mounted} is404Page={is404Page}>
|
|
<AnimatePresence mode="wait" initial={false}>
|
|
<motion.div
|
|
key={pathname}
|
|
initial={{ opacity: 0, y: 10 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: -10 }}
|
|
transition={{ duration: 0.4, ease: "easeInOut" }}
|
|
>
|
|
{children}
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</GatedProviders>
|
|
</ThemeProvider>
|
|
</ConsentProvider>
|
|
</ErrorBoundary>
|
|
</ErrorBoundary>
|
|
);
|
|
}
|
|
|
|
function GatedProviders({
|
|
children,
|
|
mounted,
|
|
}: {
|
|
children: React.ReactNode;
|
|
mounted: boolean;
|
|
is404Page: boolean;
|
|
}) {
|
|
return (
|
|
<ErrorBoundary>
|
|
<ToastProvider>
|
|
{mounted && <BackgroundBlobs />}
|
|
{mounted && <ShaderGradientBackground />}
|
|
<div className="relative z-10">{children}</div>
|
|
</ToastProvider>
|
|
</ErrorBoundary>
|
|
);
|
|
}
|