yuki-api / src /components /ErrorBoundary.tsx
OhMyDitzzy
Feat: add project
6d9f36a
import React, { Component, ReactNode } from "react";
import { Button } from "./ui/button";
import { AlertTriangle, RefreshCw, Home, Code } from "lucide-react";
interface Props {
children: ReactNode;
fallback?: ReactNode;
}
interface State {
hasError: boolean;
error: Error | null;
errorInfo: React.ErrorInfo | null;
}
export class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null,
};
}
static getDerivedStateFromError(error: Error): Partial<State> {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error("Error caught by boundary:", error, errorInfo);
this.setState({
error,
errorInfo,
});
}
handleReset = () => {
this.setState({
hasError: false,
error: null,
errorInfo: null,
});
};
render() {
if (this.state.hasError) {
if (this.props.fallback) {
return this.props.fallback;
}
return (
<div className="min-h-screen flex items-center justify-center bg-background px-4 py-8">
<div className="max-w-3xl w-full">
{/* Main Error Card */}
<div className="bg-white/[0.02] border border-white/10 rounded-xl overflow-hidden backdrop-blur-sm">
{/* Header with Gradient */}
<div className="bg-gradient-to-r from-red-500/20 via-orange-500/20 to-yellow-500/20 border-b border-white/10 p-8">
<div className="flex items-start gap-4">
{/* Animated Icon */}
<div className="flex-shrink-0">
<div className="w-16 h-16 bg-red-500/20 rounded-2xl flex items-center justify-center border border-red-500/30 backdrop-blur-sm animate-pulse">
<AlertTriangle className="w-8 h-8 text-red-400" />
</div>
</div>
<div className="flex-1 min-w-0">
<h1 className="text-3xl font-bold text-white mb-2 flex items-center gap-2">
Oops! Something went wrong
</h1>
<p className="text-gray-400 text-base">
Don't worry, your data is safe. The error has been logged and we'll look into it.
</p>
</div>
</div>
</div>
{/* Error Details */}
<div className="p-8 space-y-6">
{this.state.error && (
<div className="space-y-4">
{/* Error Message */}
<div>
<h3 className="text-sm font-semibold text-gray-400 mb-2 flex items-center gap-2">
<Code className="w-4 h-4" />
Error Message
</h3>
<div className="bg-black/50 border border-red-500/30 rounded-lg p-4 overflow-x-auto">
<pre className="text-sm text-red-300 whitespace-pre-wrap break-words">
{this.state.error.toString()}
</pre>
</div>
</div>
{/* Stack Trace (Dev Only) */}
{import.meta.env.DEV && this.state.errorInfo && (
<details className="group">
<summary className="cursor-pointer text-sm font-semibold text-gray-400 hover:text-gray-300 transition-colors select-none flex items-center gap-2 mb-2">
<svg
className="w-4 h-4 transition-transform group-open:rotate-90"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
Stack Trace (Development Mode)
</summary>
<div className="bg-black/50 border border-white/10 rounded-lg p-4 overflow-x-auto">
<pre className="text-xs text-gray-400 whitespace-pre-wrap">
{this.state.errorInfo.componentStack}
</pre>
</div>
</details>
)}
</div>
)}
{/* Action Buttons */}
<div className="flex flex-wrap gap-3 pt-4">
<Button
onClick={this.handleReset}
className="bg-purple-500 hover:bg-purple-600 text-white gap-2"
>
<RefreshCw className="w-4 h-4" />
Try Again
</Button>
<Button
onClick={() => window.location.reload()}
variant="outline"
className="border-white/10 text-gray-300 hover:bg-white/5 gap-2"
>
<RefreshCw className="w-4 h-4" />
Refresh Page
</Button>
<Button
onClick={() => (window.location.href = "/")}
variant="outline"
className="border-white/10 text-gray-300 hover:bg-white/5 gap-2"
>
<Home className="w-4 h-4" />
Go Home
</Button>
</div>
{/* Help Text */}
<div className="pt-4 border-t border-white/10">
<p className="text-xs text-gray-500">
If this problem persists, please contact support or check the console for more details.
</p>
</div>
</div>
</div>
{/* Additional Help Card */}
<div className="mt-6 bg-white/[0.02] border border-white/10 rounded-xl p-6">
<h3 className="text-sm font-semibold text-white mb-3">Quick Troubleshooting</h3>
<ul className="space-y-2 text-sm text-gray-400">
<li className="flex items-start gap-2">
<span className="text-purple-400 mt-0.5"></span>
<span>Try clearing your browser cache and cookies</span>
</li>
<li className="flex items-start gap-2">
<span className="text-purple-400 mt-0.5"></span>
<span>Check your internet connection</span>
</li>
<li className="flex items-start gap-2">
<span className="text-purple-400 mt-0.5"></span>
<span>Make sure you're using a supported browser</span>
</li>
<li className="flex items-start gap-2">
<span className="text-purple-400 mt-0.5"></span>
<span>Disable browser extensions that might interfere</span>
</li>
</ul>
</div>
</div>
</div>
);
}
return this.props.children;
}
}