Spaces:
Sleeping
Sleeping
| "use client" | |
| import { useState, Suspense } from "react" | |
| import { useRouter, useSearchParams } from "next/navigation" | |
| import { Button } from "@/components/ui/button" | |
| import { Input } from "@/components/ui/input" | |
| import { Label } from "@/components/ui/label" | |
| import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" | |
| const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5000/api'; | |
| function ResetPasswordForm() { | |
| const router = useRouter() | |
| const searchParams = useSearchParams() | |
| const token = searchParams.get("token") | |
| const [password, setPassword] = useState("") | |
| const [confirmPassword, setConfirmPassword] = useState("") | |
| const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle") | |
| const [errorMessage, setErrorMessage] = useState("") | |
| const handleSubmit = async (e: React.FormEvent) => { | |
| e.preventDefault() | |
| if (password !== confirmPassword) { | |
| setErrorMessage("Passwords do not match") | |
| return | |
| } | |
| if (!token) { | |
| setErrorMessage("Missing reset token") | |
| return | |
| } | |
| setStatus("loading") | |
| setErrorMessage("") | |
| try { | |
| const res = await fetch(`${API_URL}/auth/reset-password`, { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ token, password }), | |
| }) | |
| const data = await res.json() | |
| if (res.ok) { | |
| setStatus("success") | |
| setTimeout(() => { | |
| router.push("/admin/login") | |
| }, 2000) | |
| } else { | |
| setStatus("error") | |
| setErrorMessage(data.error || "Failed to reset password") | |
| } | |
| } catch (error) { | |
| setStatus("error") | |
| setErrorMessage("An error occurred") | |
| } | |
| } | |
| if (!token) { | |
| return ( | |
| <div className="text-destructive"> | |
| Invalid link. Missing token. | |
| </div> | |
| ) | |
| } | |
| return ( | |
| <form onSubmit={handleSubmit} className="space-y-4"> | |
| {status === "error" && ( | |
| <div className="bg-destructive/15 text-destructive p-3 rounded-md text-sm"> | |
| {errorMessage} | |
| </div> | |
| )} | |
| {status === "success" && ( | |
| <div className="bg-green-100 text-green-700 p-3 rounded-md text-sm"> | |
| Password updated! Redirecting to login... | |
| </div> | |
| )} | |
| <div className="space-y-2"> | |
| <Label htmlFor="password">New Password</Label> | |
| <Input | |
| id="password" | |
| type="password" | |
| required | |
| value={password} | |
| onChange={(e) => setPassword(e.target.value)} | |
| disabled={status === "loading" || status === "success"} | |
| /> | |
| </div> | |
| <div className="space-y-2"> | |
| <Label htmlFor="confirmPassword">Confirm Password</Label> | |
| <Input | |
| id="confirmPassword" | |
| type="password" | |
| required | |
| value={confirmPassword} | |
| onChange={(e) => setConfirmPassword(e.target.value)} | |
| disabled={status === "loading" || status === "success"} | |
| /> | |
| </div> | |
| <Button type="submit" className="w-full" disabled={status === "loading" || status === "success"}> | |
| {status === "loading" ? "Resetting..." : "Reset Password"} | |
| </Button> | |
| </form> | |
| ) | |
| } | |
| export default function ResetPasswordPage() { | |
| return ( | |
| <div className="flex min-h-screen items-center justify-center bg-muted/50 p-4"> | |
| <Card className="w-full max-w-md"> | |
| <CardHeader> | |
| <CardTitle className="text-2xl font-bold">Reset Password</CardTitle> | |
| <CardDescription> | |
| Enter your new password below. | |
| </CardDescription> | |
| </CardHeader> | |
| <CardContent> | |
| <Suspense fallback={<div>Loading...</div>}> | |
| <ResetPasswordForm /> | |
| </Suspense> | |
| </CardContent> | |
| </Card> | |
| </div> | |
| ) | |
| } | |