import { ExclamationCircle, SquareTwoStack } from "@medusajs/icons" import { toast, Text, IconButton, Tooltip } from "@medusajs/ui" import copy from "copy-to-clipboard" import { useTranslation } from "react-i18next" import { Navigate, useLocation, useRouteError } from "react-router-dom" import { isFetchError } from "../../../lib/is-fetch-error" export const ErrorBoundary = () => { const error = useRouteError() const location = useLocation() const { t } = useTranslation() let code: number | null = null if (isFetchError(error)) { if (error.status === 401) { return } code = error.status ?? null } // In development mode, show detailed error information const isDevelopment = process.env.NODE_ENV === "development" const errorMessage = error instanceof Error ? error.message : String(error) const errorStack = error instanceof Error ? error.stack : undefined /** * Log error in development mode. * * react-router-dom will sometimes swallow the error, * so this ensures that we always log it. */ if (process.env.NODE_ENV === "development") { console.error(error) const fileDetails = errorStack?.split("\n")[1]?.trim() const filename = fileDetails?.match(/([^/\\?]+)(?:\?[^:]*)?:\d+:\d+\)/)?.[1] || "unknown" const lineno = fileDetails?.match(/(?:\?[^:]*)?:(\d+):\d+\)/)?.[1] || "unknown" const colno = fileDetails?.match(/(?:\?[^:]*)?:\d+:(\d+)\)/)?.[1] || "unknown" window.parent.postMessage( { data: { type: "RUNTIME_ERROR", level: "error", message: errorMessage, stack: errorStack, logged_at: new Date().toISOString(), filename, lineno, colno, }, }, "*" ) } let title: string let message: string switch (code) { case 400: title = t("errorBoundary.badRequestTitle") message = t("errorBoundary.badRequestMessage") break case 404: title = t("errorBoundary.notFoundTitle") message = t("errorBoundary.notFoundMessage") break case 500: title = t("errorBoundary.internalServerErrorTitle") message = t("errorBoundary.internalServerErrorMessage") break default: title = t("errorBoundary.defaultTitle") message = t("errorBoundary.defaultMessage") break } const handleCopyError = () => { const errorText = `Error: ${errorMessage}\n\n${ errorStack || "No stack trace available" }` const success = copy(errorText) if (success) { toast.success("Error details copied to clipboard") } else { toast.error("Failed to copy error details") } } return (
{title} {message}
{isDevelopment && errorMessage && (
Error Details (Development Mode)
{errorMessage}
{errorStack && (
Stack Trace
                    {errorStack}
                  
)}
)}
) }