200 lines
5.9 KiB
JavaScript
200 lines
5.9 KiB
JavaScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import { useRouter } from "next/navigation";
|
||
import { useDispatch } from "react-redux";
|
||
import { setProfile } from "@/redux/slices/profileSlice";
|
||
import { showToast } from "@/redux/slices/toastSlice";
|
||
import Link from "next/link";
|
||
|
||
export default function LoginPage() {
|
||
const router = useRouter();
|
||
const dispatch = useDispatch();
|
||
|
||
const [formData, setFormData] = useState({
|
||
email: "",
|
||
password: "",
|
||
});
|
||
|
||
const [errors, setErrors] = useState({});
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
|
||
const validateForm = () => {
|
||
const newErrors = {};
|
||
|
||
if (!formData.email.trim()) {
|
||
newErrors.email = "ایمیل الزامی است";
|
||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
|
||
newErrors.email = "ایمیل معتبر نیست";
|
||
}
|
||
|
||
if (!formData.password.trim()) {
|
||
newErrors.password = "رمز عبور الزامی است";
|
||
} else if (formData.password.length < 6) {
|
||
newErrors.password = "رمز عبور باید حداقل 6 کاراکتر باشد";
|
||
}
|
||
|
||
setErrors(newErrors);
|
||
return Object.keys(newErrors).length === 0;
|
||
};
|
||
|
||
const handleChange = (e) => {
|
||
const { name, value } = e.target;
|
||
setFormData((prev) => ({
|
||
...prev,
|
||
[name]: value,
|
||
}));
|
||
if (errors[name]) {
|
||
setErrors((prev) => ({
|
||
...prev,
|
||
[name]: "",
|
||
}));
|
||
}
|
||
};
|
||
|
||
const handleSubmit = async (e) => {
|
||
e.preventDefault();
|
||
|
||
if (!validateForm()) {
|
||
return;
|
||
}
|
||
|
||
setIsLoading(true);
|
||
|
||
try {
|
||
// فراخوانی API (توکن خودکار در HTTP-only cookie ذخیره میشود)
|
||
const response = await fetch("/api/auth/login", {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
},
|
||
body: JSON.stringify({
|
||
email: formData.email,
|
||
password: formData.password,
|
||
}),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
const error = await response.json();
|
||
throw new Error(error.message || "خطا در ورود");
|
||
}
|
||
|
||
const data = await response.json();
|
||
|
||
// ذخیره user info در Redux (فقط برای UI)
|
||
dispatch(
|
||
setProfile(
|
||
data.user || { email: formData.email }
|
||
)
|
||
);
|
||
|
||
dispatch(
|
||
showToast({
|
||
message: "خوش آمدید! شما با موفقیت وارد شدید",
|
||
type: "success",
|
||
})
|
||
);
|
||
|
||
// Redirect به صفحه اصلی
|
||
// (middleware خودکار بررسی توکن را انجام میدهد)
|
||
router.push("/");
|
||
} catch (error) {
|
||
dispatch(
|
||
showToast({
|
||
message: error.message || "خطایی در حین ورود رخ داد",
|
||
type: "error",
|
||
})
|
||
);
|
||
|
||
setErrors((prev) => ({
|
||
...prev,
|
||
submit: error.message,
|
||
}));
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="min-h-screen flex items-center justify-center bg-linear-to-br from-blue-50 to-indigo-100 px-4">
|
||
<div className="w-full max-w-md bg-white rounded-lg shadow-lg p-8">
|
||
<h1 className="text-3xl font-bold text-center text-gray-800 mb-2">
|
||
خوش آمدید
|
||
</h1>
|
||
<p className="text-center text-gray-600 mb-6">
|
||
لطفاً وارد حساب خود شوید
|
||
</p>
|
||
|
||
{errors.submit && (
|
||
<div className="mb-4 p-3 bg-red-50 border border-red-200 rounded-lg text-red-700 text-sm">
|
||
{errors.submit}
|
||
</div>
|
||
)}
|
||
|
||
<form onSubmit={handleSubmit} className="space-y-5">
|
||
{/* Email Field */}
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||
ایمیل
|
||
</label>
|
||
<input
|
||
type="email"
|
||
name="email"
|
||
value={formData.email}
|
||
onChange={handleChange}
|
||
placeholder="ایمیل خود را وارد کنید"
|
||
className={`w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 transition ${
|
||
errors.email ? "border-red-500" : "border-gray-300"
|
||
}`}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.email && (
|
||
<p className="mt-1 text-red-600 text-xs">{errors.email}</p>
|
||
)}
|
||
</div>
|
||
|
||
{/* Password Field */}
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||
رمز عبور
|
||
</label>
|
||
<input
|
||
type="password"
|
||
name="password"
|
||
value={formData.password}
|
||
onChange={handleChange}
|
||
placeholder="رمز عبور خود را وارد کنید"
|
||
className={`w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 transition ${
|
||
errors.password ? "border-red-500" : "border-gray-300"
|
||
}`}
|
||
disabled={isLoading}
|
||
/>
|
||
{errors.password && (
|
||
<p className="mt-1 text-red-600 text-xs">{errors.password}</p>
|
||
)}
|
||
</div>
|
||
|
||
{/* Submit Button */}
|
||
<button
|
||
type="submit"
|
||
disabled={isLoading}
|
||
className="w-full bg-indigo-600 text-white font-semibold py-2 rounded-lg hover:bg-indigo-700 transition disabled:bg-gray-400 disabled:cursor-not-allowed"
|
||
>
|
||
{isLoading ? "درحال ورود..." : "ورود"}
|
||
</button>
|
||
</form>
|
||
|
||
{/* Register Link */}
|
||
<div className="mt-6 text-center text-gray-600">
|
||
حساب کاربری ندارید؟{" "}
|
||
<Link
|
||
href="/register"
|
||
className="text-indigo-600 font-semibold hover:underline"
|
||
>
|
||
ثبتنام کنید
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
} |