"use client"; import React, { Component, ReactNode } from "react"; import { useTranslations } from "next-intl"; import { debug } from "@/lib/debug"; export interface FallbackProps { error: Error; resetError: () => void; t: (key: string) => string; } interface ErrorBoundaryProps { children: ReactNode; fallback: (props: FallbackProps) => ReactNode; onError?: (error: Error, errorInfo: React.ErrorInfo) => void; onReset?: () => void; } interface ErrorBoundaryState { hasError: boolean; error: Error | null; } /** * Core error boundary class component (React requirement). * Receives translation function as prop from the functional wrapper. */ class ErrorBoundaryCore extends Component< ErrorBoundaryProps & { t: (key: string) => string }, ErrorBoundaryState > { state: ErrorBoundaryState = { hasError: false, error: null }; static getDerivedStateFromError(error: Error): ErrorBoundaryState { return { hasError: true, error }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void { // Always log errors debug.error("[ErrorBoundary]", error.message, { stack: error.stack, componentStack: errorInfo.componentStack, }); // Call optional error handler this.props.onError?.(error, errorInfo); } resetError = (): void => { this.props.onReset?.(); this.setState({ hasError: false, error: null }); }; render(): ReactNode { if (this.state.hasError && this.state.error) { return this.props.fallback({ error: this.state.error, resetError: this.resetError, t: this.props.t, }); } return this.props.children; } } /** * Functional wrapper that injects translations into the error boundary. * Use this component to wrap any part of your UI that might throw errors. * * @example * * * */ export function ErrorBoundary({ children, fallback, onError, onReset, }: ErrorBoundaryProps) { const t = useTranslations("errors"); return ( {children} ); }