"use client"; import { useState, useEffect, Suspense } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { useAuth } from "@/lib/auth"; import { clientFetch } from "@/lib/api"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { Eye, EyeOff, Loader2, LogIn, UserPlus, KeyRound, Mail } from "lucide-react"; import { API_URL } from "@/lib/api"; import { UserRole } from "@/lib/types"; // Default export wraps the inner component in Suspense (required by Next.js // when useSearchParams() is used inside a "use client" page). export default function AuthPage() { return ( ); } function AuthPageInner() { const { currentUser, login, register, refresh } = useAuth(); const router = useRouter(); const searchParams = useSearchParams(); const resetToken = searchParams.get("token") || ""; const initialTab = resetToken ? "reset" : "signin"; const [loading, setLoading] = useState(false); const [showPwd, setShowPwd] = useState(false); // Redirect if already logged in useEffect(() => { if (currentUser) router.replace("/dashboard"); }, [currentUser, router]); // ── Sign In ─────────────────────────────────────────────────────────────── const handleSignIn = async (e: React.FormEvent) => { e.preventDefault(); const fd = new FormData(e.currentTarget); const email = fd.get("email") as string; const password = fd.get("password") as string; setLoading(true); try { await login(email, password); toast.success("Welcome back!"); router.push("/dashboard"); router.refresh(); } catch (err: unknown) { toast.error(err instanceof Error ? err.message : "Login failed"); } finally { setLoading(false); } }; // ── Sign Up ─────────────────────────────────────────────────────────────── const handleSignUp = async (e: React.FormEvent) => { e.preventDefault(); const fd = new FormData(e.currentTarget); const name = fd.get("name") as string; const email = fd.get("email") as string; const password = fd.get("password") as string; setLoading(true); try { await register(name, email, password); toast.success("Account created! Welcome!"); router.push("/dashboard"); router.refresh(); } catch (err: unknown) { toast.error(err instanceof Error ? err.message : "Registration failed"); } finally { setLoading(false); } }; // ── Magic Link ──────────────────────────────────────────────────────────── const handleMagicLink = async (e: React.FormEvent) => { e.preventDefault(); const fd = new FormData(e.currentTarget); const email = fd.get("email") as string; setLoading(true); try { await clientFetch("/auth/magic-link", { method: "POST", body: JSON.stringify({ email }), }); toast.success("Magic link sent! Check your email."); } catch (err: unknown) { toast.error(err instanceof Error ? err.message : "Failed to send magic link"); } finally { setLoading(false); } }; // ── Password Reset Request ──────────────────────────────────────────────── const handleResetRequest = async (e: React.FormEvent) => { e.preventDefault(); const fd = new FormData(e.currentTarget); const email = fd.get("email") as string; setLoading(true); try { await clientFetch("/auth/password-reset/request", { method: "POST", body: JSON.stringify({ email }), }); toast.success("Reset link sent! Check your email."); } catch (err: unknown) { toast.error(err instanceof Error ? err.message : "Failed"); } finally { setLoading(false); } }; // ── Password Reset Confirm ──────────────────────────────────────────────── const handleResetConfirm = async (e: React.FormEvent) => { e.preventDefault(); const fd = new FormData(e.currentTarget); const token = fd.get("token") as string; const password = fd.get("password") as string; setLoading(true); try { await clientFetch("/auth/password-reset/confirm", { method: "POST", body: JSON.stringify({ token, password }), }); toast.success("Password updated! You can now sign in."); } catch (err: unknown) { toast.error(err instanceof Error ? err.message : "Failed to reset password"); } finally { setLoading(false); } }; return ( Sign In Sign Up Reset {/* ── Sign In Tab ─────────────────────────────────────────────────── */} Sign In Sign in to your account to access the dashboard. Email Password setShowPwd((v) => !v)} > {showPwd ? ( ) : ( )} {loading && } Sign In Send magic link (window.location.href = `${API_URL}/auth/google`) } > Continue with Google {/* ── Sign Up Tab ─────────────────────────────────────────────────── */} Create Account New sign-ups are assigned the default MEMBER role. Full Name Email Password setShowPwd((v) => !v)} > {showPwd ? ( ) : ( )} {loading && } Create Account {/* ── Reset Password Tab ──────────────────────────────────────────── */} Reset Password {/* Step 1: Request */} Request reset link {loading && ( )} Send {/* Step 2: Confirm */} Confirm new password setShowPwd((v) => !v)} > {showPwd ? ( ) : ( )} {loading && } Update Password {/* ── Demo credentials card ─────────────────────────────────────────── */} Demo Admin Account Email: admin@gmail.com Password: Whatever123$ { const emailInput = document.getElementById( "signin-email" ) as HTMLInputElement | null; const pwdInput = document.getElementById( "signin-password" ) as HTMLInputElement | null; if (emailInput) emailInput.value = "admin@gmail.com"; if (pwdInput) pwdInput.value = "Whatever123$"; document.querySelector('[value="signin"]')?.click(); }} > Use these credentials Role Permissions MEMBER — View blog posts only MANAGER — View all + create (draft only) ADMIN — Full CRUD access + user management ); }
Demo Admin Account
Email: admin@gmail.com
Password: Whatever123$
Role Permissions
MEMBER — View blog posts only
MANAGER — View all + create (draft only)
ADMIN — Full CRUD access + user management