mission-control/app/reset-password/page.tsx

152 lines
4.8 KiB
TypeScript

"use client"
import { useEffect, useState, Suspense } from "react"
import { useRouter, useSearchParams } from "next/navigation"
import { Button } from "@/components/ui/button"
function ResetPasswordForm() {
const router = useRouter()
const searchParams = useSearchParams()
const token = searchParams.get("token")
const email = searchParams.get("email")
const [password, setPassword] = useState("")
const [confirmPassword, setConfirmPassword] = useState("")
const [isSubmitting, setIsSubmitting] = useState(false)
const [error, setError] = useState<string | null>(null)
const [success, setSuccess] = useState(false)
useEffect(() => {
if (!token || !email) {
setError("Invalid or missing reset link")
}
}, [token, email])
const handleSubmit = async () => {
setError(null)
if (!password || !confirmPassword) {
setError("Please enter and confirm your new password")
return
}
if (password.length < 8) {
setError("Password must be at least 8 characters")
return
}
if (password !== confirmPassword) {
setError("Passwords do not match")
return
}
setIsSubmitting(true)
try {
const res = await fetch("/api/auth/reset-password", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token, email, password }),
})
const data = await res.json()
if (!res.ok) {
setError(data.error || "Failed to reset password")
return
}
setSuccess(true)
// Redirect to login after 3 seconds
setTimeout(() => {
router.push("/login")
}, 3000)
} catch {
setError("Failed to reset password")
} finally {
setIsSubmitting(false)
}
}
if (success) {
return (
<div className="min-h-screen bg-slate-950 text-slate-100 flex items-center justify-center p-4">
<div className="w-full max-w-md border border-green-800 rounded-xl bg-green-900/20 p-6 text-center">
<div className="w-12 h-12 rounded-full bg-green-500/20 flex items-center justify-center mx-auto mb-4">
<svg className="w-6 h-6 text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
</div>
<h1 className="text-xl font-semibold text-white mb-2">Password Reset!</h1>
<p className="text-slate-300 mb-4">
Your password has been successfully reset.
</p>
<p className="text-sm text-slate-400">
Redirecting to login...
</p>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-slate-950 text-slate-100 flex items-center justify-center p-4">
<div className="w-full max-w-md border border-slate-800 rounded-xl bg-slate-900/70 p-6">
<h1 className="text-2xl font-semibold text-white mb-2">Reset Password</h1>
<p className="text-sm text-slate-400 mb-6">
Enter your new password below.
</p>
{error && (
<div className="mb-4 p-3 bg-red-900/30 border border-red-700 rounded-lg">
<p className="text-sm text-red-400">{error}</p>
</div>
)}
<div className="space-y-4">
<div>
<label className="block text-sm text-slate-300 mb-1">New Password</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white"
placeholder="At least 8 characters"
/>
</div>
<div>
<label className="block text-sm text-slate-300 mb-1">Confirm Password</label>
<input
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="w-full px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white"
placeholder="Re-enter password"
/>
</div>
<Button onClick={handleSubmit} className="w-full" disabled={isSubmitting || !token || !email}>
{isSubmitting ? "Resetting..." : "Reset Password"}
</Button>
<Button onClick={() => router.push("/login")} variant="outline" className="w-full">
Back to Login
</Button>
</div>
</div>
</div>
)
}
export default function ResetPasswordPage() {
return (
<Suspense fallback={
<div className="min-h-screen bg-slate-950 text-slate-100 flex items-center justify-center p-4">
<div className="text-center">
<p className="text-slate-400">Loading...</p>
</div>
</div>
}>
<ResetPasswordForm />
</Suspense>
)
}