55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
'use client';
|
|
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { ThemeProvider, useTheme } from 'next-themes';
|
|
import { useState } from 'react';
|
|
import { Toaster } from 'sonner';
|
|
|
|
// Filter out the React 19 warning caused by next-themes
|
|
if (typeof window !== 'undefined' && process.env.NODE_ENV === 'development') {
|
|
const orig = console.error;
|
|
console.error = (...args: unknown[]) => {
|
|
if (typeof args[0] === 'string' && args[0].includes('Encountered a script tag')) {
|
|
return;
|
|
}
|
|
orig.apply(console, args);
|
|
};
|
|
}
|
|
|
|
function ThemedToaster() {
|
|
const { resolvedTheme } = useTheme();
|
|
return (
|
|
<Toaster
|
|
position="top-right"
|
|
closeButton
|
|
richColors
|
|
theme={resolvedTheme === 'dark' ? 'dark' : 'light'}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function AppProviders({ children }: { children: React.ReactNode }) {
|
|
// Create query client once in component state to maintain caching integrity across routing
|
|
const [queryClient] = useState(
|
|
() =>
|
|
new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 30 * 1000, // 30 seconds stale-while-revalidate threshold
|
|
gcTime: 5 * 60 * 1000, // 5 minutes caching lifetime before garbage collection
|
|
refetchOnWindowFocus: false, // Disable automatic refetching on click to avoid redundant API loads
|
|
retry: 1, // Restrict retry attempts to 1 for responsive offline detection
|
|
},
|
|
},
|
|
})
|
|
);
|
|
|
|
return (
|
|
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
|
<QueryClientProvider client={queryClient}>
|
|
{children}
|
|
<ThemedToaster />
|
|
</QueryClientProvider>
|
|
</ThemeProvider>
|
|
);
|
|
}
|