feat: add error boundary to prevent full app crashes
This commit is contained in:
parent
b69c4d3e4f
commit
b2973dc6ad
25
src/App.tsx
25
src/App.tsx
@ -5,20 +5,23 @@ import { AuthProvider } from './contexts/AuthContext';
|
|||||||
import { TLDrawProvider } from './contexts/TLDrawContext';
|
import { TLDrawProvider } from './contexts/TLDrawContext';
|
||||||
import { UserProvider } from './contexts/UserContext';
|
import { UserProvider } from './contexts/UserContext';
|
||||||
import AppRoutes from './AppRoutes';
|
import AppRoutes from './AppRoutes';
|
||||||
|
import { ErrorBoundary } from './components/ErrorBoundary';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const App = React.memo(() => (
|
const App = React.memo(() => (
|
||||||
<BrowserRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
|
<ErrorBoundary>
|
||||||
<ThemeProvider theme={theme}>
|
<BrowserRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
|
||||||
<AuthProvider>
|
<ThemeProvider theme={theme}>
|
||||||
<UserProvider>
|
<AuthProvider>
|
||||||
<TLDrawProvider>
|
<UserProvider>
|
||||||
<AppRoutes />
|
<TLDrawProvider>
|
||||||
</TLDrawProvider>
|
<AppRoutes />
|
||||||
</UserProvider>
|
</TLDrawProvider>
|
||||||
</AuthProvider>
|
</UserProvider>
|
||||||
</ThemeProvider>
|
</AuthProvider>
|
||||||
</BrowserRouter>
|
</ThemeProvider>
|
||||||
|
</BrowserRouter>
|
||||||
|
</ErrorBoundary>
|
||||||
));
|
));
|
||||||
|
|
||||||
App.displayName = import.meta.env.VITE_APP_NAME;
|
App.displayName = import.meta.env.VITE_APP_NAME;
|
||||||
|
|||||||
84
src/components/ErrorBoundary.tsx
Normal file
84
src/components/ErrorBoundary.tsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: ReactNode;
|
||||||
|
fallback?: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
hasError: boolean;
|
||||||
|
error: Error | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ErrorBoundary extends Component<Props, State> {
|
||||||
|
public state: State = {
|
||||||
|
hasError: false,
|
||||||
|
error: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static getDerivedStateFromError(error: Error): State {
|
||||||
|
return { hasError: true, error };
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||||
|
console.error('Uncaught error:', error, errorInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
if (this.state.hasError) {
|
||||||
|
if (this.props.fallback) {
|
||||||
|
return this.props.fallback;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
minHeight: '100vh',
|
||||||
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
||||||
|
padding: '2rem',
|
||||||
|
textAlign: 'center',
|
||||||
|
}}>
|
||||||
|
<h1 style={{ color: '#dc2626', marginBottom: '1rem' }}>Something went wrong</h1>
|
||||||
|
<p style={{ color: '#6b7280', marginBottom: '1.5rem' }}>
|
||||||
|
{this.state.error?.message || 'An unexpected error occurred'}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
this.setState({ hasError: false, error: null });
|
||||||
|
window.location.reload();
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
padding: '0.75rem 1.5rem',
|
||||||
|
backgroundColor: '#3b82f6',
|
||||||
|
color: 'white',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '0.5rem',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontSize: '1rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Reload Application
|
||||||
|
</button>
|
||||||
|
{import.meta.env.DEV && (
|
||||||
|
<details style={{ marginTop: '2rem', textAlign: 'left', maxWidth: '600px' }}>
|
||||||
|
<summary style={{ cursor: 'pointer', color: '#6b7280' }}>Error Details</summary>
|
||||||
|
<pre style={{
|
||||||
|
backgroundColor: '#f3f4f6',
|
||||||
|
padding: '1rem',
|
||||||
|
borderRadius: '0.5rem',
|
||||||
|
overflow: 'auto',
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
}}>
|
||||||
|
{this.state.error?.stack}
|
||||||
|
</pre>
|
||||||
|
</details>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user