- Complete UI refactor with charcoal/bone color palette - Add Space Grotesk font for headlines, Inter for body - Update all 24+ pages with new design system - Add LinearPrimitives reusable components - Improve dark mode support throughout - Add subtle micro-animations and transitions
153 lines
5.5 KiB
TypeScript
153 lines
5.5 KiB
TypeScript
import { Link, useRouteError, isRouteErrorResponse } from 'react-router-dom';
|
|
import { Home, RefreshCw, AlertTriangle, FileQuestion, ServerCrash } from 'lucide-react';
|
|
|
|
export function NotFoundPage() {
|
|
return (
|
|
<div className="min-h-screen bg-primary flex items-center justify-center p-6">
|
|
<div className="max-w-md w-full text-center animate-in">
|
|
<div className="w-20 h-20 mx-auto bg-warning-muted rounded-2xl flex items-center justify-center mb-8">
|
|
<FileQuestion size={40} className="text-warning" />
|
|
</div>
|
|
|
|
<h1 className="text-5xl font-bold text-primary mb-4 tracking-tight">
|
|
404
|
|
</h1>
|
|
|
|
<h2 className="text-xl font-semibold text-secondary mb-4">
|
|
Page Not Found
|
|
</h2>
|
|
|
|
<p className="text-tertiary mb-8">
|
|
The page you're looking for doesn't exist or has been moved.
|
|
</p>
|
|
|
|
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
|
<Link
|
|
to="/"
|
|
className="btn btn-primary h-11"
|
|
>
|
|
<Home size={16} />
|
|
Go to Dashboard
|
|
</Link>
|
|
<button
|
|
onClick={() => window.history.back()}
|
|
className="btn btn-secondary h-11"
|
|
>
|
|
Go Back
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function ServerErrorPage() {
|
|
return (
|
|
<div className="min-h-screen bg-primary flex items-center justify-center p-6">
|
|
<div className="max-w-md w-full text-center animate-in">
|
|
<div className="w-20 h-20 mx-auto bg-destructive-muted rounded-2xl flex items-center justify-center mb-8">
|
|
<ServerCrash size={40} className="text-destructive" />
|
|
</div>
|
|
|
|
<h1 className="text-5xl font-bold text-primary mb-4 tracking-tight">
|
|
500
|
|
</h1>
|
|
|
|
<h2 className="text-xl font-semibold text-secondary mb-4">
|
|
Server Error
|
|
</h2>
|
|
|
|
<p className="text-tertiary mb-8">
|
|
Something went wrong on our end. Our team has been notified.
|
|
</p>
|
|
|
|
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
|
<button
|
|
onClick={() => window.location.reload()}
|
|
className="btn btn-primary h-11"
|
|
>
|
|
<RefreshCw size={16} />
|
|
Try Again
|
|
</button>
|
|
<Link
|
|
to="/"
|
|
className="btn btn-secondary h-11"
|
|
>
|
|
<Home size={16} />
|
|
Go to Dashboard
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function getErrorMessage(error: unknown): string {
|
|
if (isRouteErrorResponse(error)) {
|
|
return `${error.status} ${error.statusText}`;
|
|
}
|
|
if (error instanceof Error) {
|
|
return error.message;
|
|
}
|
|
return String(error);
|
|
}
|
|
|
|
export function RouterErrorPage() {
|
|
const error = useRouteError();
|
|
|
|
if (isRouteErrorResponse(error) && error.status === 404) {
|
|
return <NotFoundPage />;
|
|
}
|
|
|
|
const errorMessage = getErrorMessage(error);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-primary flex items-center justify-center p-6">
|
|
<div className="max-w-md w-full text-center animate-in">
|
|
<div className="w-20 h-20 mx-auto bg-destructive-muted rounded-2xl flex items-center justify-center mb-8">
|
|
<AlertTriangle size={40} className="text-destructive" />
|
|
</div>
|
|
|
|
<h1 className="text-3xl font-bold text-primary mb-4 tracking-tight">
|
|
Oops!
|
|
</h1>
|
|
|
|
<h2 className="text-lg font-semibold text-secondary mb-4">
|
|
Something went wrong
|
|
</h2>
|
|
|
|
<p className="text-tertiary mb-6">
|
|
An unexpected error occurred. Please try again.
|
|
</p>
|
|
|
|
{import.meta.env.DEV && errorMessage && (
|
|
<details className="mb-6 text-left card p-4">
|
|
<summary className="cursor-pointer text-sm text-secondary font-medium">
|
|
Error Details
|
|
</summary>
|
|
<pre className="mt-2 text-xs text-destructive overflow-auto max-h-32 font-mono">
|
|
{errorMessage}
|
|
</pre>
|
|
</details>
|
|
)}
|
|
|
|
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
|
<button
|
|
onClick={() => window.location.reload()}
|
|
className="btn btn-primary h-11"
|
|
>
|
|
<RefreshCw size={16} />
|
|
Try Again
|
|
</button>
|
|
<Link
|
|
to="/"
|
|
className="btn btn-secondary h-11"
|
|
>
|
|
<Home size={16} />
|
|
Go Home
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|