93 lines
3.0 KiB
JavaScript
93 lines
3.0 KiB
JavaScript
import React from 'react';
|
||
import { logError } from '../utils/errorLogger';
|
||
|
||
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) {
|
||
const componentInfo = {
|
||
component: errorInfo?.componentStack || null,
|
||
props: this.props,
|
||
};
|
||
|
||
logError(error, componentInfo);
|
||
}
|
||
|
||
handleRetry = () => {
|
||
this.setState({ hasError: false, error: null });
|
||
};
|
||
|
||
handleReload = () => {
|
||
window.location.reload();
|
||
};
|
||
|
||
renderDefaultFallback() {
|
||
const { compact } = this.props;
|
||
|
||
if (compact) {
|
||
return (
|
||
<div className="rounded-[24px] border border-[var(--color-error)] bg-[var(--color-error-soft)] p-4 text-center">
|
||
<p className="text-sm text-[var(--color-text)]">Что-то пошло не так</p>
|
||
<button
|
||
onClick={this.handleRetry}
|
||
className="mt-2 rounded-xl bg-[var(--color-primary)] px-4 py-2 text-sm font-semibold text-white"
|
||
>
|
||
Попробовать снова
|
||
</button>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className="flex min-h-[460px] flex-col items-center justify-center p-8 text-center">
|
||
<div className="mb-4 text-5xl">⚠️</div>
|
||
<h2 className="mb-2 text-xl font-semibold text-[var(--color-text)]">
|
||
Что-то пошло не так
|
||
</h2>
|
||
<p className="mb-6 max-w-md text-sm text-[var(--color-text-muted)]">
|
||
Произошла непредвиденная ошибка. Попробуйте обновить страницу или вернуться позже.
|
||
</p>
|
||
{this.state.error && process.env.NODE_ENV === 'development' && (
|
||
<pre className="mb-4 max-h-32 overflow-auto rounded-xl bg-[var(--color-surface-strong)] p-3 text-left text-xs text-[var(--color-error)]">
|
||
{this.state.error.message}
|
||
</pre>
|
||
)}
|
||
<div className="flex gap-3">
|
||
<button
|
||
onClick={this.handleRetry}
|
||
className="rounded-xl bg-[var(--color-primary)] px-5 py-2.5 text-sm font-semibold text-white transition-colors hover:opacity-90"
|
||
>
|
||
Попробовать снова
|
||
</button>
|
||
<button
|
||
onClick={this.handleReload}
|
||
className="rounded-xl border border-[var(--color-border)] px-5 py-2.5 text-sm font-semibold text-[var(--color-text)] transition-colors hover:bg-[var(--color-surface)]"
|
||
>
|
||
Обновить страницу
|
||
</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
render() {
|
||
if (this.state.hasError) {
|
||
if (typeof this.props.fallback === 'function') {
|
||
return this.props.fallback(this.state.error, this.handleRetry);
|
||
}
|
||
|
||
return this.renderDefaultFallback();
|
||
}
|
||
|
||
return this.props.children;
|
||
}
|
||
}
|
||
|
||
export default ErrorBoundary; |