jacquardSnapshot

← snapshot

2271 bytes
"use client";

import { useEffect } from "react";

/**
 * The last resort: a render that threw all the way out.
 *
 * `BugReporter`'s window listeners do not see errors React caught, so this
 * boundary reports them itself. It also has to say something true to the
 * person looking at it — a blank page after a crash is the worst of both,
 * since they learn nothing and neither does anyone else.
 */
export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    void fetch("/api/telemetry/bug", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        message: error.message || "render threw",
        stack: error.stack,
        pathname: window.location.pathname,
        kind: "boundary",
      }),
      keepalive: true,
    }).catch(() => {
      /* reporting a bug must never itself become one */
    });
  }, [error]);

  return (
    <html lang="en">
      <body style={{ margin: 0 }}>
        <div style={{ maxWidth: 560, margin: "18vh auto", padding: "0 24px" }}>
          <h1 style={{ fontSize: 22, fontWeight: 500 }}>This screen broke.</h1>
          <p style={{ lineHeight: 1.65, opacity: 0.75 }}>
            The failure has been reported. Nothing you did was lost — this
            surface holds everything in memory for the life of the server
            process, and that process is still running.
          </p>
          <p
            style={{
              fontFamily: "ui-monospace, SF Mono, Menlo, monospace",
              fontSize: 12.5,
              opacity: 0.6,
              wordBreak: "break-word",
            }}
          >
            {error.message}
            {error.digest ? ` · ${error.digest}` : ""}
          </p>
          <button
            type="button"
            onClick={reset}
            style={{
              marginTop: 14,
              padding: "8px 18px",
              borderRadius: 999,
              border: "1px solid currentColor",
              background: "transparent",
              color: "inherit",
              cursor: "pointer",
            }}
          >
            Try again
          </button>
        </div>
      </body>
    </html>
  );
}