74 lines
2.1 KiB
React
74 lines
2.1 KiB
React
import React from 'react'
|
||
import { logger } from '../lib/logger.js'
|
||
|
||
export default class ErrorBoundary extends React.Component {
|
||
constructor(props) {
|
||
super(props)
|
||
this.state = { hasError: false, error: null }
|
||
}
|
||
|
||
static getDerivedStateFromError(error) {
|
||
return { hasError: true, error }
|
||
}
|
||
|
||
componentDidCatch(error, errorInfo) {
|
||
logger.error('React component error', {
|
||
stack: (error?.stack || '') + '\n\nComponent stack:\n' + (errorInfo?.componentStack || ''),
|
||
})
|
||
}
|
||
|
||
render() {
|
||
if (this.state.hasError) {
|
||
return (
|
||
<div style={{
|
||
minHeight: '100vh',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
padding: '2rem',
|
||
fontFamily: 'sans-serif',
|
||
background: '#f8fafc',
|
||
color: '#0f172a',
|
||
}}>
|
||
<div style={{ maxWidth: 600, textAlign: 'center' }}>
|
||
<h1 style={{ fontSize: '1.5rem', marginBottom: '0.5rem' }}>
|
||
⚠️ 頁面發生錯誤 / Something went wrong
|
||
</h1>
|
||
<p style={{ color: '#64748b', marginBottom: '1.5rem' }}>
|
||
已經將錯誤自動回報俾 IT狗。請 reload 或者返回上一頁。
|
||
</p>
|
||
<button
|
||
onClick={() => window.location.reload()}
|
||
style={{
|
||
padding: '0.5rem 1rem',
|
||
background: '#2563eb',
|
||
color: 'white',
|
||
border: 'none',
|
||
borderRadius: '0.375rem',
|
||
cursor: 'pointer',
|
||
}}
|
||
>
|
||
Reload Page
|
||
</button>
|
||
{this.state.error?.message && (
|
||
<pre style={{
|
||
marginTop: '1.5rem',
|
||
padding: '1rem',
|
||
background: '#f1f5f9',
|
||
borderRadius: '0.375rem',
|
||
fontSize: '0.75rem',
|
||
textAlign: 'left',
|
||
whiteSpace: 'pre-wrap',
|
||
wordBreak: 'break-word',
|
||
}}>
|
||
{this.state.error.message}
|
||
</pre>
|
||
)}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
return this.props.children
|
||
}
|
||
}
|