|
1 | | -/* eslint-disable @typescript-eslint/no-explicit-any */ |
2 | 1 | import { Link, isRouteErrorResponse, useRouteError } from 'react-router-dom' |
| 2 | +import { AlertTriangle, Home, RefreshCw, FileWarning, ServerCrash } from 'lucide-react' |
| 3 | +import { Button } from '../ui/button' |
| 4 | +import { Card, CardContent } from '../ui/card' |
| 5 | +import { IconBox } from '../layouts/IconBox' |
3 | 6 |
|
4 | 7 | export default function ErrorPage() { |
5 | | - const error = useRouteError() as any |
| 8 | + const error = useRouteError() as Error | Response | unknown |
6 | 9 | console.error(error) |
7 | 10 |
|
8 | | - let errorMessage = '' |
| 11 | + // Determine error type and message |
| 12 | + let errorMessage = 'An unexpected error occurred' |
| 13 | + let errorTitle = 'Something went wrong' |
| 14 | + let errorCode: string | number | null = null |
| 15 | + let ErrorIcon = AlertTriangle |
| 16 | + |
9 | 17 | if (isRouteErrorResponse(error)) { |
10 | | - errorMessage = error.statusText |
| 18 | + errorCode = error.status |
| 19 | + errorMessage = error.statusText || error.data?.message || 'Route error' |
| 20 | + |
| 21 | + if (error.status === 404) { |
| 22 | + errorTitle = 'Page not found' |
| 23 | + errorMessage = "The page you're looking for doesn't exist or has been moved." |
| 24 | + ErrorIcon = FileWarning |
| 25 | + } else if (error.status >= 500) { |
| 26 | + errorTitle = 'Server error' |
| 27 | + ErrorIcon = ServerCrash |
| 28 | + } |
11 | 29 | } else if (error instanceof Error) { |
12 | 30 | errorMessage = error.message |
13 | 31 | } |
14 | 32 |
|
| 33 | + const handleReload = () => { |
| 34 | + window.location.reload() |
| 35 | + } |
| 36 | + |
15 | 37 | return ( |
16 | | - <div className="text-center p-4 space-y-2 h-screen flex flex-col justify-center items-center rounded-lg"> |
17 | | - <h1 className="text-2xl font-bold">Oops!</h1> |
18 | | - <p>Sorry, an unexpected error has occurred.</p> |
19 | | - <p> |
20 | | - <i>{errorMessage}</i> |
21 | | - </p> |
22 | | - |
23 | | - <div className=""> |
24 | | - Back to{' '} |
25 | | - <Link to="/" className="hover:underline"> |
26 | | - Home |
27 | | - </Link> |
| 38 | + <div className="min-h-screen flex items-center justify-center p-6 bg-background"> |
| 39 | + <div className="w-full max-w-md animate-fade-in-up"> |
| 40 | + {/* Error Icon */} |
| 41 | + <div className="flex justify-center mb-6"> |
| 42 | + <div className="relative"> |
| 43 | + <div className="absolute inset-0 bg-rose-500/20 rounded-full blur-xl animate-pulse-soft" /> |
| 44 | + <IconBox icon={ErrorIcon} color="rose" size="xl" className="relative h-16 w-16" /> |
| 45 | + </div> |
| 46 | + </div> |
| 47 | + |
| 48 | + {/* Error Card */} |
| 49 | + <Card className="bg-gradient-to-br from-card to-card/80 border-rose-500/20"> |
| 50 | + <CardContent className="p-6 text-center space-y-4"> |
| 51 | + {/* Error Code Badge */} |
| 52 | + {errorCode && ( |
| 53 | + <div className="inline-flex items-center px-3 py-1 rounded-full bg-rose-500/10 text-rose-500 text-xs font-medium"> |
| 54 | + Error {errorCode} |
| 55 | + </div> |
| 56 | + )} |
| 57 | + |
| 58 | + {/* Title */} |
| 59 | + <h1 className="text-2xl font-bold tracking-tight">{errorTitle}</h1> |
| 60 | + |
| 61 | + {/* Message */} |
| 62 | + <p className="text-sm text-muted-foreground">{errorMessage}</p> |
| 63 | + |
| 64 | + {/* Technical Details (collapsible for developers) */} |
| 65 | + {error instanceof Error && error.stack && ( |
| 66 | + <details className="text-left mt-4"> |
| 67 | + <summary className="text-xs text-muted-foreground cursor-pointer hover:text-foreground transition-colors"> |
| 68 | + Technical details |
| 69 | + </summary> |
| 70 | + <pre className="mt-2 p-3 bg-muted/50 rounded-lg text-xs font-mono text-muted-foreground overflow-auto max-h-32"> |
| 71 | + {error.stack} |
| 72 | + </pre> |
| 73 | + </details> |
| 74 | + )} |
| 75 | + |
| 76 | + {/* Actions */} |
| 77 | + <div className="flex flex-col sm:flex-row gap-3 pt-4"> |
| 78 | + <Button |
| 79 | + variant="outline" |
| 80 | + className="flex-1" |
| 81 | + onClick={handleReload} |
| 82 | + leftIcon={<RefreshCw className="h-4 w-4" />} |
| 83 | + > |
| 84 | + Try Again |
| 85 | + </Button> |
| 86 | + <Button variant="gradient" className="flex-1" asChild> |
| 87 | + <Link to="/"> |
| 88 | + <Home className="h-4 w-4 mr-2" /> |
| 89 | + Go Home |
| 90 | + </Link> |
| 91 | + </Button> |
| 92 | + </div> |
| 93 | + </CardContent> |
| 94 | + </Card> |
| 95 | + |
| 96 | + {/* Help Text */} |
| 97 | + <p className="text-center text-xs text-muted-foreground mt-4"> |
| 98 | + If this problem persists, please contact support. |
| 99 | + </p> |
28 | 100 | </div> |
29 | 101 | </div> |
30 | 102 | ) |
|
0 commit comments