Component Details
Auth Component 05

AuthErrorContent.tsx
Next.js•Tailwind CSS
1// app/auth/error/error-content.tsx - The actual component with useSearchParams
2"use client";
3
4import { useEffect, useState } from "react";
5import { useRouter, useSearchParams } from "next/navigation";
6import Link from "next/link";
7import { Button } from "@/components/ui/button";
8import {
9 Card,
10 CardContent,
11 CardHeader,
12 CardTitle,
13 CardDescription,
14} from "@/components/ui/card";
15import { Alert, AlertDescription } from "@/components/ui/alert";
16import { AlertCircle, Home, RefreshCw } from "lucide-react";
17
18export default function AuthErrorContent() {
19 const [error, setError] = useState<string>("");
20 const [errorDescription, setErrorDescription] = useState<string>("");
21 const searchParams = useSearchParams();
22 const router = useRouter();
23
24 useEffect(() => {
25 // Get error from query parameters
26 const errorParam = searchParams.get("error");
27 const errorDescParam = searchParams.get("error_description");
28
29 if (errorParam) {
30 setError(decodeURIComponent(errorParam));
31 }
32 if (errorDescParam) {
33 setErrorDescription(decodeURIComponent(errorDescParam));
34 }
35 }, [searchParams]);
36
37 // Common error messages and solutions
38 const commonErrors = [
39 {
40 code: "invalid_credentials",
41 message: "Invalid email or password",
42 solution: "Check your credentials and try again",
43 },
44 {
45 code: "email_not_confirmed",
46 message: "Email not confirmed",
47 solution: "Check your inbox for the confirmation email",
48 },
49 {
50 code: "user_already_exists",
51 message: "User already exists",
52 solution: "Try signing in instead of signing up",
53 },
54 {
55 code: "weak_password",
56 message: "Password is too weak",
57 solution: "Use a stronger password with at least 8 characters",
58 },
59 {
60 code: "oauth_error",
61 message: "OAuth authentication failed",
62 solution: "Try another sign-in method",
63 },
64 {
65 code: "magic_link_expired",
66 message: "Magic link has expired",
67 solution: "Request a new magic link",
68 },
69 {
70 code: "rate_limit_exceeded",
71 message: "Too many attempts. Please try again later",
72 solution: "Wait a few minutes before trying again",
73 },
74 ];
75
76 const getErrorSolution = (errorMsg: string) => {
77 const foundError = commonErrors.find(
78 (err) =>
79 errorMsg.toLowerCase().includes(err.code) ||
80 errorMsg.toLowerCase().includes(err.message.toLowerCase())
81 );
82 return foundError?.solution || "Please try again or contact support.";
83 };
84
85 return (
86 <div className="flex flex-col">
87 <main className="flex-1 flex items-center justify-center px-4 py-12">
88 <div className="w-full max-w-md">
89 <div className="text-center mb-8">
90 <h1 className="text-3xl font-bold mb-2">Authentication Error</h1>
91 <p className="text-muted-foreground">
92 Something went wrong during authentication
93 </p>
94 </div>
95
96 <Card className="border shadow-sm">
97 <CardHeader className="space-y-1">
98 <CardTitle className="text-2xl">Error Details</CardTitle>
99 <CardDescription>
100 Here's what went wrong and how to fix it
101 </CardDescription>
102 </CardHeader>
103
104 <CardContent className="space-y-4">
105 {/* Error Message */}
106 <Alert variant="destructive">
107 <AlertCircle className="h-4 w-4" />
108 <AlertDescription>
109 {error || "An unknown authentication error occurred"}
110 </AlertDescription>
111 </Alert>
112
113 {/* Error Description */}
114 {errorDescription && (
115 <div className="p-3 bg-muted rounded-lg">
116 <p className="text-sm text-muted-foreground">
117 <span className="font-medium">Details:</span>{" "}
118 {errorDescription}
119 </p>
120 </div>
121 )}
122
123 {/* Suggested Solution */}
124 <div className="p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg">
125 <h3 className="font-medium text-blue-800 dark:text-blue-300 mb-2">
126 How to fix this:
127 </h3>
128 <p className="text-sm text-blue-700 dark:text-blue-400">
129 {getErrorSolution(error || errorDescription)}
130 </p>
131 </div>
132
133 {/* Action Buttons */}
134 <div className="space-y-3">
135 <Button
136 onClick={() => router.push("/signin")}
137 className="w-full"
138 >
139 <RefreshCw className="mr-2 h-4 w-4" />
140 Try Again
141 </Button>
142
143 <Button variant="outline" className="w-full" asChild>
144 <Link href="/">
145 <Home className="mr-2 h-4 w-4" />
146 Go Home
147 </Link>
148 </Button>
149 </div>
150
151 {/* Common Error Solutions */}
152 <div className="mt-4">
153 <h3 className="text-sm font-medium mb-2">Common Solutions:</h3>
154 <ul className="text-sm text-muted-foreground space-y-2">
155 <li className="flex items-start gap-2">
156 <div className="w-1 h-1 mt-2 rounded-full bg-muted-foreground" />
157 Clear browser cookies and cache
158 </li>
159 <li className="flex items-start gap-2">
160 <div className="w-1 h-1 mt-2 rounded-full bg-muted-foreground" />
161 Try a different browser
162 </li>
163 <li className="flex items-start gap-2">
164 <div className="w-1 h-1 mt-2 rounded-full bg-muted-foreground" />
165 Check your internet connection
166 </li>
167 <li className="flex items-start gap-2">
168 <div className="w-1 h-1 mt-2 rounded-full bg-muted-foreground" />
169 Disable browser extensions temporarily
170 </li>
171 </ul>
172 </div>
173 </CardContent>
174 </Card>
175
176 {/* Contact Support */}
177 <div className="mt-6">
178 <div className="relative">
179 <div className="absolute inset-0 flex items-center">
180 <div className="w-full border-t"></div>
181 </div>
182 <div className="relative flex justify-center text-xs">
183 <span className="bg-background px-2 text-muted-foreground">
184 Still having issues?
185 </span>
186 </div>
187 </div>
188
189 <div className="mt-4">
190 <Button variant="outline" className="w-full" asChild>
191 <Link href="/contact">Contact our support team</Link>
192 </Button>
193 </div>
194 </div>
195 </div>
196 </main>
197 </div>
198 );
199}
200
201// app/auth/error/page.tsx
202import { Suspense } from "react";
203import AuthErrorContent from "./error-content";
204
205export default function AuthErrorPage() {
206 return (
207 <Suspense fallback={<AuthErrorSkeleton />}>
208 <AuthErrorContent />
209 </Suspense>
210 );
211}
212
213// Skeleton loading component
214function AuthErrorSkeleton() {
215 return (
216 <div className="flex flex-col">
217 <main className="flex-1 flex items-center justify-center px-4 py-12">
218 <div className="w-full max-w-md">
219 <div className="text-center mb-8">
220 <h1 className="text-3xl font-bold mb-2">Loading...</h1>
221 <p className="text-muted-foreground">Preparing error details</p>
222 </div>
223 <div className="animate-pulse space-y-4">
224 <div className="h-48 bg-gray-200 dark:bg-gray-800 rounded-lg"></div>
225 <div className="h-24 bg-gray-200 dark:bg-gray-800 rounded-lg"></div>
226 <div className="h-12 bg-gray-200 dark:bg-gray-800 rounded-lg"></div>
227 </div>
228 </div>
229 </main>
230 </div>
231 );
232}