- main.tsx: on vite:preloadError (stale index.html referencing removed hashed chunks after a redeploy) reload the page immediately. - New ErrorBoundary around the whole router: render errors show a Persian fallback with «تلاش مجدد» instead of wiping the DOM. - nginx: index.html served with Cache-Control no-cache,no-store, must-revalidate (verified live); /assets/* stays public, immutable.
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
import { Component, type ErrorInfo, type ReactNode } from "react";
|
|
|
|
interface Props {
|
|
children: ReactNode;
|
|
}
|
|
|
|
interface State {
|
|
error: Error | null;
|
|
}
|
|
|
|
// خطای رندر/لود ماژول نباید کل DOM را خالی کند — با این باکس، بهجای صفحهی
|
|
// سفید، پیام + دکمهی «تلاش مجدد» (بارگذاری مجدد صفحه) نمایش داده میشود.
|
|
export class ErrorBoundary extends Component<Props, State> {
|
|
state: State = { error: null };
|
|
|
|
static getDerivedStateFromError(error: Error): State {
|
|
return { error };
|
|
}
|
|
|
|
componentDidCatch(error: Error, info: ErrorInfo) {
|
|
console.error("ErrorBoundary caught:", error, info);
|
|
}
|
|
|
|
private retry = () => {
|
|
this.setState({ error: null });
|
|
window.location.reload();
|
|
};
|
|
|
|
render() {
|
|
if (!this.state.error) return this.props.children;
|
|
return (
|
|
<div className="flex min-h-screen flex-col items-center justify-center gap-4 bg-bg px-6 text-center text-ink">
|
|
<div className="text-4xl">⚠️</div>
|
|
<h1 className="text-lg font-bold">خطایی در نمایش صفحه رخ داد</h1>
|
|
<p className="max-w-md text-sm text-muted">
|
|
{this.state.error.message || "مشکلی پیش آمد — لطفاً دوباره تلاش کنید."}
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={this.retry}
|
|
className="cursor-pointer rounded-lg bg-accent px-5 py-2.5 text-sm font-bold text-white transition-colors hover:bg-accent-dark"
|
|
>
|
|
تلاش مجدد
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
}
|