Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 9x 10x 5x 1x 1x 1x 21x 21x 10x 2x 8x 1x 11x 1x | import { Component, type ErrorInfo, type ReactNode } from 'react'
import { Button } from '@core/components/ui/button'
import { RefreshCcw, Home } from 'lucide-react'
import { withTranslation, type WithTranslation } from 'react-i18next'
interface Props extends WithTranslation {
children?: ReactNode
fallback?: ReactNode
}
interface State {
hasError: boolean
error: Error | null
}
class ErrorBoundaryBase 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)
}
private handleReset = () => {
this.setState({ hasError: false, error: null })
window.location.reload()
}
public render() {
const { t, fallback } = this.props
if (this.state.hasError) {
if (fallback) {
return fallback
}
return (
<div className="min-h-screen flex items-center justify-center p-4 bg-muted/30">
<div className="max-w-md w-full bg-background border shadow-xl rounded-xl p-8 text-center space-y-6">
<div className="bg-destructive/10 w-16 h-16 rounded-full flex items-center justify-center mx-auto">
<RefreshCcw className="h-8 w-8 text-destructive animate-spin-slow" />
</div>
<div className="space-y-2">
<h2 className="text-2xl font-bold tracking-tight">
{t('error.title', 'Something went wrong')}
</h2>
<p className="text-muted-foreground text-sm">
{t(
'error.message',
"We encountered an unexpected error. Don't worry, your data is safe.",
)}
</p>
</div>
{import.meta.env.DEV && this.state.error && (
<div className="p-4 bg-muted rounded text-xs text-left overflow-auto max-h-32 font-mono">
{this.state.error.message}
</div>
)}
<div className="flex flex-col sm:flex-row gap-3">
<Button variant="default" className="flex-1" onClick={this.handleReset}>
<RefreshCcw className="mr-2 h-4 w-4" />
{t('error.reload', 'Try Again')}
</Button>
<Button
variant="outline"
className="flex-1"
onClick={() => (window.location.href = '/')}
>
<Home className="mr-2 h-4 w-4" />
{t('common.home', 'Go Home')}
</Button>
</div>
</div>
</div>
)
}
return this.props.children
}
}
export const ErrorBoundary = withTranslation('common')(ErrorBoundaryBase)
|