181 lines
5.9 KiB
TypeScript
181 lines
5.9 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import axios from 'axios';
|
|
import { useSearchParams, useRouter } from 'next/navigation';
|
|
import { ApiServerBaseUrl } from '@/utils/baseurl.utils';
|
|
|
|
// Import lucide icons directly
|
|
import { Eye, EyeOff } from 'lucide-react';
|
|
|
|
export default function ResetPasswordPage() {
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
|
|
const token = searchParams.get('token');
|
|
const email_user = searchParams.get('email');
|
|
|
|
const [password, setPassword] = useState('');
|
|
const [confirmPassword, setConfirmPassword] = useState('');
|
|
|
|
// 👁️ Toggles
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const [showConfirm, setShowConfirm] = useState(false);
|
|
|
|
const [msg, setMsg] = useState('');
|
|
const [err, setErr] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setErr('');
|
|
setMsg('');
|
|
|
|
if (!password || !confirmPassword) {
|
|
setErr('Please fill all fields');
|
|
return;
|
|
}
|
|
|
|
if (password !== confirmPassword) {
|
|
setErr('Passwords do not match');
|
|
return;
|
|
}
|
|
|
|
if (!token) {
|
|
setErr('Invalid or expired token');
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
|
|
try {
|
|
await axios.post(`${ApiServerBaseUrl}/auth/reset-password`, {
|
|
email: email_user,
|
|
token,
|
|
newPassword: password,
|
|
});
|
|
|
|
setMsg('Password reset successfully! Redirecting to login...');
|
|
setTimeout(() => router.push('/login'), 2000);
|
|
|
|
} catch (error: any) {
|
|
setErr(error.response?.data?.error || 'Something went wrong');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#0a0b17] flex items-center justify-center p-4 relative overflow-hidden">
|
|
|
|
{/* Background glows */}
|
|
<div className="absolute top-[180px] left-52 w-[100px] h-[100px] bg-[#1d8be0] rounded-full blur-2xl opacity-[1.5]" />
|
|
<div className="absolute top-10 left-0 w-[60px] h-[60px] bg-[#6cb655] rounded-full blur-2xl opacity-[1.5]" />
|
|
<div className="absolute -left-[80px] bottom-[140px] w-[100px] h-[200px] bg-[#db21d9] blur-3xl opacity-100" />
|
|
<div className="absolute bottom-20 right-[180px] w-[80px] h-[80px] bg-[#783e8d] rounded-full blur-2xl opacity-80" />
|
|
|
|
{/* Card */}
|
|
<div className="relative z-10 w-full max-w-md bg-[#0f1329] border border-white/10 rounded-3xl p-8 shadow-xl">
|
|
|
|
{/* Logo */}
|
|
<div className="flex flex-col items-center mb-4">
|
|
<img
|
|
src="/assets/images/logo_sb.png"
|
|
alt="Logo"
|
|
className="h-[120px] w-[120px]
|
|
drop-shadow-[0_0_6px_rgba(0,111,171,0.65),0_0_8px_rgba(243,195,56,0.55),
|
|
0_0_10px_rgba(226,50,118,0.50),0_0_10px_rgba(20,71,209,0.40)]"
|
|
/>
|
|
|
|
<h1
|
|
className="
|
|
text-2xl font-extrabold mt-4 text-center
|
|
bg-gradient-to-r from-blue-500 via-cyan-400 to-pink-500
|
|
bg-clip-text text-transparent
|
|
"
|
|
>
|
|
Reset Your Password
|
|
</h1>
|
|
|
|
<p className="text-sm text-gray-400 mt-2 text-center">
|
|
Enter your new password below
|
|
</p>
|
|
</div>
|
|
|
|
{err && <p className="text-red-500 text-sm mb-3 text-center">{err}</p>}
|
|
{msg && <p className="text-green-500 text-sm mb-3 text-center">{msg}</p>}
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
|
|
{/* 🔥 NEW PASSWORD FIELD */}
|
|
<div className="relative">
|
|
<input
|
|
type={showPassword ? "text" : "password"}
|
|
placeholder="New Password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
className="w-full bg-[#0a0b17] border border-gray-700 text-white rounded-lg px-4 py-3 pr-12 focus:outline-none focus:border-blue-500"
|
|
/>
|
|
|
|
{/* Eye Toggle */}
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowPassword(!showPassword)}
|
|
className="absolute right-4 top-1/2 -translate-y-1/2 text-gray-300"
|
|
>
|
|
<span className="w-5 h-5 flex items-center justify-center">
|
|
{showPassword ? (
|
|
<EyeOff size={20} strokeWidth={1.5} />
|
|
) : (
|
|
<Eye size={20} strokeWidth={1.5} />
|
|
)}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
{/* 🔥 CONFIRM PASSWORD FIELD */}
|
|
<div className="relative">
|
|
<input
|
|
type={showConfirm ? "text" : "password"}
|
|
placeholder="Confirm Password"
|
|
value={confirmPassword}
|
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
className="w-full bg-[#0a0b17] border border-gray-700 text-white rounded-lg px-4 py-3 pr-12 focus:outline-none focus:border-blue-500"
|
|
/>
|
|
|
|
{/* Eye Toggle */}
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowConfirm(!showConfirm)}
|
|
className="absolute right-4 top-1/2 -translate-y-1/2 text-gray-300"
|
|
>
|
|
<span className="w-5 h-5 flex items-center justify-center">
|
|
{showConfirm ? (
|
|
<EyeOff size={20} strokeWidth={1.5} />
|
|
) : (
|
|
<Eye size={20} strokeWidth={1.5} />
|
|
)}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Button */}
|
|
<button
|
|
type="submit"
|
|
disabled={loading}
|
|
className="
|
|
w-full text-white text-lg font-semibold py-3 rounded-xl
|
|
bg-gradient-to-r from-blue-600 to-pink-500
|
|
shadow-lg transition-all
|
|
hover:opacity-90 hover:scale-[1.02]
|
|
disabled:opacity-60
|
|
"
|
|
>
|
|
{loading ? 'Resetting...' : 'Reset Password'}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|