'use client'; import * as Sentry from '@sentry/nextjs'; import { Component, type ErrorInfo, type ReactNode } from 'react'; export interface ErrorBoundaryFallbackProps { error: Error; reset: () => void; } export interface ErrorBoundaryProps { children: ReactNode; /** Custom fallback component. Receives the caught error and a reset callback. */ fallback?: (props: ErrorBoundaryFallbackProps) => ReactNode; /** Called when an error is caught. Useful for additional logging / side effects. */ onError?: (error: Error, info: ErrorInfo) => void; } interface ErrorBoundaryState { error: Error | null; } /** * Generic class-based React Error Boundary. * * Captures exceptions via Sentry and renders a Vietnamese-language fallback UI * with a "Thử lại" (retry) button when no custom fallback is provided. */ export class ErrorBoundary extends Component { override state: ErrorBoundaryState = { error: null }; static getDerivedStateFromError(error: Error): ErrorBoundaryState { return { error }; } override componentDidCatch(error: Error, info: ErrorInfo) { Sentry.captureException(error, { extra: { componentStack: info.componentStack } }); if (process.env.NODE_ENV !== 'production') { console.error('[ErrorBoundary] caught:', error, info); } this.props.onError?.(error, info); } reset = () => { this.setState({ error: null }); }; override render() { const { error } = this.state; const { children, fallback } = this.props; if (error) { if (fallback) { return fallback({ error, reset: this.reset }); } return ; } return children; } } function DefaultErrorFallback({ error, reset }: ErrorBoundaryFallbackProps) { return (

Đã xảy ra lỗi

{process.env.NODE_ENV !== 'production' && error.message && (

{error.message}

)}
); }