'use client'; import { useEffect, useRef, useSyncExternalStore } from 'react'; /** The `?debug=1` flag lives in the URL, which React does not own. */ const subscribeToNothing = () => () => {}; const readDebugFlag = () => new URLSearchParams(window.location.search).get('debug') === '1'; // Server snapshot: the flag is unknowable until there is a `window`, and claiming `false` // keeps server and client output identical until React re-renders on the client. const debugFlagOnServer = () => false; interface ErrorFallbackProps { error: Error & { digest?: string }; reset: () => void; } /** * What a visitor sees when a client-side exception escapes to an error boundary. * * Without a boundary Next.js renders its own bare "Application error: a client-side * exception has occurred" stub, which tells the visitor nothing and — more importantly — * leaves us with no record that anything happened at all. * * Raw exception text is deliberately **not** shown by default. Next.js strips server error * messages in production and substitutes `digest` precisely so internals do not leak, and * this is a public site. Visitors get the digest as a short reference; the full message and * stack go to the server log, and are additionally rendered inline when the URL carries * `?debug=1` so the fault can be read straight off a phone or tablet with no devtools. */ export default function ErrorFallback({ error, reset }: ErrorFallbackProps) { const showDetail = useSyncExternalStore( subscribeToNothing, readDebugFlag, debugFlagOnServer, ); // Reporting is idempotent per mount: React may re-render the boundary (e.g. Strict Mode // double-invokes effects in development) and one fault should produce one log line. const reported = useRef(false); useEffect(() => { if (reported.current) return; reported.current = true; // Fire-and-forget. A failure to report must never surface to the visitor or throw from // inside the boundary that is already handling an error. `keepalive` lets the request // outlive the page if they navigate away immediately. try { void fetch('/api/client-error', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: error.message, stack: error.stack, digest: error.digest, pathname: window.location.pathname + window.location.search, userAgent: navigator.userAgent, }), keepalive: true, }).catch(() => {}); } catch { // Ignore: serialisation or a blocked request must not escalate. } }, [error]); return (

Something went wrong

This page hit an unexpected error. Trying again usually works — the rankings and forecast data themselves are unaffected.

{/* Deliberately a plain anchor, not next/link. The rule exists to avoid full page reloads, but a full reload is the point here: client-side navigation would route within the same broken runtime the boundary just caught, and `global-error` renders when the root layout itself failed. */} {/* eslint-disable-next-line @next/next/no-html-link-for-pages */} Back to homepage
{error.digest && (

Reference: {error.digest} Quote this if you report the problem to us.

)} {showDetail && (

Debug detail

{error.message || '(no message)'}

{error.stack && (
                  {error.stack}
                
)}
)}
); }