148 lines
4.2 KiB
TypeScript
148 lines
4.2 KiB
TypeScript
import React, { Component, ErrorInfo, ReactNode } from 'react';
|
|
import {
|
|
Box,
|
|
Typography,
|
|
Button,
|
|
Paper,
|
|
Alert,
|
|
AlertTitle
|
|
} from '@mui/material';
|
|
import { Refresh, BugReport, Home } from '@mui/icons-material';
|
|
|
|
interface Props {
|
|
children: ReactNode;
|
|
}
|
|
|
|
interface State {
|
|
hasError: boolean;
|
|
error?: Error;
|
|
errorInfo?: ErrorInfo;
|
|
}
|
|
|
|
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: ErrorInfo) {
|
|
console.error('Error caught by boundary:', error, errorInfo);
|
|
this.setState({ error, errorInfo });
|
|
|
|
// Log error to monitoring service (e.g., Sentry)
|
|
// logErrorToService(error, errorInfo);
|
|
}
|
|
|
|
handleRetry = () => {
|
|
this.setState({ hasError: false, error: undefined, errorInfo: undefined });
|
|
};
|
|
|
|
handleGoHome = () => {
|
|
window.location.href = '/';
|
|
};
|
|
|
|
render() {
|
|
if (this.state.hasError) {
|
|
return (
|
|
<Box
|
|
sx={{
|
|
minHeight: '100vh',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
p: 3,
|
|
}}
|
|
>
|
|
<Paper
|
|
elevation={24}
|
|
sx={{
|
|
maxWidth: 500,
|
|
p: 4,
|
|
borderRadius: 3,
|
|
background: 'rgba(255, 255, 255, 0.95)',
|
|
backdropFilter: 'blur(10px)',
|
|
border: '1px solid rgba(255, 255, 255, 0.2)',
|
|
}}
|
|
>
|
|
<Alert severity="error" sx={{ mb: 3 }}>
|
|
<AlertTitle>Something went wrong</AlertTitle>
|
|
We encountered an unexpected error. Please try again.
|
|
</Alert>
|
|
|
|
<Typography variant="h5" gutterBottom sx={{ fontWeight: 600 }}>
|
|
Oops! Something went wrong
|
|
</Typography>
|
|
|
|
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
|
|
We're sorry, but something unexpected happened. Our team has been notified and is working to fix this issue.
|
|
</Typography>
|
|
|
|
{process.env.NODE_ENV === 'development' && this.state.error && (
|
|
<Box sx={{ mb: 3, p: 2, bgcolor: 'rgba(0,0,0,0.05)', borderRadius: 1 }}>
|
|
<Typography variant="body2" fontFamily="monospace" sx={{ fontSize: '0.75rem' }}>
|
|
{this.state.error.toString()}
|
|
</Typography>
|
|
</Box>
|
|
)}
|
|
|
|
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
|
|
<Button
|
|
variant="contained"
|
|
onClick={this.handleRetry}
|
|
startIcon={<Refresh />}
|
|
sx={{
|
|
borderRadius: 2,
|
|
textTransform: 'none',
|
|
fontWeight: 600,
|
|
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
'&:hover': {
|
|
background: 'linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%)',
|
|
}
|
|
}}
|
|
>
|
|
Try Again
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outlined"
|
|
onClick={this.handleGoHome}
|
|
startIcon={<Home />}
|
|
sx={{
|
|
borderRadius: 2,
|
|
textTransform: 'none',
|
|
fontWeight: 600,
|
|
}}
|
|
>
|
|
Go Home
|
|
</Button>
|
|
|
|
<Button
|
|
variant="text"
|
|
startIcon={<BugReport />}
|
|
onClick={() => {
|
|
// Open support ticket or contact form
|
|
window.open('mailto:support@alwrity.com?subject=Error Report', '_blank');
|
|
}}
|
|
sx={{
|
|
textTransform: 'none',
|
|
fontWeight: 600,
|
|
}}
|
|
>
|
|
Report Issue
|
|
</Button>
|
|
</Box>
|
|
</Paper>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
return this.props.children;
|
|
}
|
|
}
|
|
|
|
export default ErrorBoundary;
|