Files
gh-hopeoverture-worldbuildi…/skills/sentry-and-otel-setup/assets/error-boundary.tsx
2025-11-29 18:46:44 +08:00

72 lines
1.9 KiB
TypeScript

'use client';
import * as Sentry from '@sentry/nextjs';
import { Component, type ReactNode } from 'react';
interface Props {
children: ReactNode;
fallback?: ReactNode;
}
interface State {
hasError: boolean;
error?: Error;
}
export class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// Log error to Sentry
Sentry.captureException(error, {
contexts: {
react: {
componentStack: errorInfo.componentStack,
},
},
});
}
render() {
if (this.state.hasError) {
// Render custom fallback UI
if (this.props.fallback) {
return this.props.fallback;
}
return (
<div className="flex min-h-screen items-center justify-center p-4">
<div className="max-w-md rounded-lg border border-red-200 bg-red-50 p-6">
<h2 className="mb-2 text-xl font-semibold text-red-900">
Something went wrong
</h2>
<p className="mb-4 text-red-700">
An error occurred while rendering this component.
</p>
{process.env.NODE_ENV === 'development' && this.state.error && (
<pre className="mb-4 overflow-auto rounded bg-red-100 p-2 text-xs text-red-900">
{this.state.error.message}
</pre>
)}
<button
onClick={() => this.setState({ hasError: false, error: undefined })}
className="rounded bg-red-600 px-4 py-2 text-white hover:bg-red-700"
>
Try again
</button>
</div>
</div>
);
}
return this.props.children;
}
}