👁️
at main 101 lines 3.5 kB view raw
1import type { ErrorComponentProps } from "@tanstack/react-router"; 2import { Link, useRouter } from "@tanstack/react-router"; 3import { AlertTriangle, Check, Copy, Home, RefreshCw } from "lucide-react"; 4import { useState } from "react"; 5 6export function RouteErrorComponent({ 7 error, 8 info, 9 reset, 10}: ErrorComponentProps) { 11 const router = useRouter(); 12 const [copied, setCopied] = useState(false); 13 14 const copyErrorDetails = async () => { 15 const details = [ 16 `Error: ${error.message}`, 17 `URL: ${window.location.href}`, 18 `Time: ${new Date().toISOString()}`, 19 `User Agent: ${navigator.userAgent}`, 20 "", 21 "Stack Trace:", 22 error.stack || "(no stack trace)", 23 "", 24 ...(info?.componentStack 25 ? ["Component Stack:", info.componentStack] 26 : []), 27 ].join("\n"); 28 29 await navigator.clipboard.writeText(details); 30 setCopied(true); 31 setTimeout(() => setCopied(false), 2000); 32 }; 33 34 return ( 35 <div className="min-h-screen bg-white dark:bg-zinc-900 flex items-center justify-center p-6"> 36 <div className="max-w-4xl w-full"> 37 <div className="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-6"> 38 <div className="flex items-start gap-4"> 39 <div className="p-2 bg-red-100 dark:bg-red-900/40 rounded-full"> 40 <AlertTriangle className="w-6 h-6 text-red-600 dark:text-red-400" /> 41 </div> 42 <div className="flex-1 min-w-0"> 43 <h1 className="text-xl font-bold text-red-900 dark:text-red-100 mb-2"> 44 Something went wrong 45 </h1> 46 <p className="text-red-700 dark:text-red-300 mb-4"> 47 {error.message || "An unexpected error occurred"} 48 </p> 49 50 <div className="flex flex-wrap gap-3 mb-4"> 51 <button 52 type="button" 53 onClick={() => { 54 reset(); 55 router.invalidate(); 56 }} 57 className="inline-flex items-center gap-2 px-4 py-2 bg-red-600 hover:bg-red-700 text-white font-medium rounded-lg transition-colors" 58 > 59 <RefreshCw className="w-4 h-4" /> 60 Try again 61 </button> 62 <button 63 type="button" 64 onClick={copyErrorDetails} 65 className="inline-flex items-center gap-2 px-4 py-2 bg-gray-200 dark:bg-zinc-700 hover:bg-gray-300 dark:hover:bg-zinc-600 text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 66 > 67 {copied ? ( 68 <Check className="w-4 h-4" /> 69 ) : ( 70 <Copy className="w-4 h-4" /> 71 )} 72 {copied ? "Copied!" : "Copy details"} 73 </button> 74 <Link 75 to="/" 76 className="inline-flex items-center gap-2 px-4 py-2 bg-gray-200 dark:bg-zinc-700 hover:bg-gray-300 dark:hover:bg-zinc-600 text-gray-900 dark:text-white font-medium rounded-lg transition-colors" 77 > 78 <Home className="w-4 h-4" /> 79 Go home 80 </Link> 81 </div> 82 83 {import.meta.env.DEV && ( 84 <div className="space-y-2"> 85 <pre className="text-xs bg-red-100 dark:bg-red-900/30 p-3 rounded overflow-x-auto text-red-800 dark:text-red-200 whitespace-pre-wrap break-words max-h-64 overflow-y-auto"> 86 {error.stack || error.message} 87 </pre> 88 {info?.componentStack && ( 89 <pre className="text-xs bg-red-100 dark:bg-red-900/30 p-3 rounded overflow-x-auto text-red-800 dark:text-red-200 whitespace-pre-wrap break-words max-h-48 overflow-y-auto"> 90 {info.componentStack} 91 </pre> 92 )} 93 </div> 94 )} 95 </div> 96 </div> 97 </div> 98 </div> 99 </div> 100 ); 101}