2026-08-05 23:27:34 +03:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import { useState } from "react";
|
|
|
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
|
import { motion, AnimatePresence } from "framer-motion";
|
|
|
|
|
import toast, { Toaster } from "react-hot-toast";
|
|
|
|
|
import { useRouter } from "next/navigation";
|
|
|
|
|
import AuthService from "../../services/AuthService";
|
|
|
|
|
import InteractiveBackground from "../Animation/Background"
|
|
|
|
|
import { BackLink, HeaderForm } from "./HeaderLogin";
|
|
|
|
|
import HeaderAnimation, { containerVariants, itemVariants } from "../Animation/HeaderLoginAnimation";
|
|
|
|
|
import TabsLogin from "./Tabs";
|
|
|
|
|
import LoginForm from "./LoginForm";
|
|
|
|
|
import CreateNewAccount from "./CreateNewAccount";
|
|
|
|
|
import PolicyAndPrivecy from "./PolicyAndPrivecy";
|
|
|
|
|
import OtpComponent from "./OtpComponent";
|
|
|
|
|
|
|
|
|
|
export default function Login() {
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
const [step, setStep] = useState("login");
|
|
|
|
|
const [loginMethod, setLoginMethod] = useState("email");
|
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
|
|
|
const [formData, setFormData] = useState({
|
|
|
|
|
credential: "", //email or phoneNumber
|
|
|
|
|
password: "",
|
|
|
|
|
rememberMe: false,
|
|
|
|
|
});
|
|
|
|
|
const [errors, setErrors] = useState({});
|
|
|
|
|
const validateForm = () => {
|
|
|
|
|
const newErrors = {};
|
|
|
|
|
if (!formData.credential) {
|
|
|
|
|
newErrors.credential = loginMethod === "email" ? t("emailRequired") : t("phoneRequired");
|
|
|
|
|
}
|
|
|
|
|
if (!formData.password) {
|
|
|
|
|
newErrors.password = t("passwordRequired");
|
|
|
|
|
}
|
|
|
|
|
setErrors(newErrors);
|
|
|
|
|
return Object.keys(newErrors).length === 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleLogin = async (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
if (!validateForm()) return;
|
|
|
|
|
setIsLoading(true);
|
|
|
|
|
setErrors({});
|
|
|
|
|
try {
|
|
|
|
|
const response = await AuthService.login({
|
|
|
|
|
loginMethod,
|
|
|
|
|
credential: formData.credential,
|
|
|
|
|
password: formData.password,
|
|
|
|
|
});
|
|
|
|
|
switch (response.type) {
|
|
|
|
|
case "SUCCESS":
|
|
|
|
|
toast.success(t("loginSuccess"));
|
|
|
|
|
router.push("/");
|
|
|
|
|
break;
|
|
|
|
|
case "OTP_REQUIRED":
|
|
|
|
|
toast(t("otpRequired"));
|
|
|
|
|
setStep("otp");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2026-08-11 16:04:09 +03:00
|
|
|
toast.error("Login failed the email or password is wrong");
|
2026-08-05 23:27:34 +03:00
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("[Login] Error:", err);
|
|
|
|
|
toast.error(err.message || t("connectionError"), {
|
|
|
|
|
style: { background: "#fee2e2", color: "#991b1b" },
|
|
|
|
|
});
|
|
|
|
|
} finally {
|
|
|
|
|
setIsLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Auto-detect login method from input
|
|
|
|
|
const handleCredentialChange = (value) => {
|
|
|
|
|
setFormData({ ...formData, credential: value });
|
|
|
|
|
if (errors.credential) setErrors({ ...errors, credential: null });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handelTabs = (type) => {
|
|
|
|
|
setLoginMethod(type);
|
|
|
|
|
setFormData({ ...formData, credential: "" });
|
|
|
|
|
};
|
|
|
|
|
return (
|
|
|
|
|
<div className="min-h-screen flex items-center justify-center p-4 relative overflow-hidden">
|
|
|
|
|
<Toaster position="top-center" reverseOrder={false} />
|
|
|
|
|
<InteractiveBackground />
|
|
|
|
|
{/* Particles */}
|
|
|
|
|
<HeaderAnimation />
|
|
|
|
|
<motion.div variants={containerVariants} initial="hidden" animate="visible" className="relative w-full max-w-md z-10">
|
|
|
|
|
{/* Back link */}
|
|
|
|
|
<BackLink />
|
|
|
|
|
<motion.div variants={itemVariants} className="bg-white/10 backdrop-blur-2xl rounded-3xl shadow-2xl border border-white/10 overflow-hidden">
|
|
|
|
|
{/* Header */}
|
|
|
|
|
<HeaderForm step={step} />
|
|
|
|
|
<div className="p-8">
|
|
|
|
|
<AnimatePresence mode="wait">
|
|
|
|
|
{step === "login" ? (
|
|
|
|
|
<motion.form key="login" initial={{ opacity: 0, x: -20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: 20 }} onSubmit={handleLogin} className="space-y-6">
|
|
|
|
|
{/* Login method tabs */}
|
|
|
|
|
<TabsLogin loginMethod={loginMethod} handelTabs={handelTabs} />
|
|
|
|
|
{/* Form Login */}
|
|
|
|
|
<LoginForm
|
|
|
|
|
loginMethod={loginMethod}
|
|
|
|
|
errors={errors}
|
|
|
|
|
formData={formData}
|
|
|
|
|
isLoading={isLoading}
|
|
|
|
|
isSuccess={isSuccess}
|
|
|
|
|
setFormData={setFormData}
|
|
|
|
|
handleCredentialChange={handleCredentialChange}
|
|
|
|
|
/>
|
|
|
|
|
</motion.form>
|
|
|
|
|
) : (
|
|
|
|
|
// /* OTP Verification Step */
|
|
|
|
|
<OtpComponent isLoading={isLoading} setIsLoading={setIsLoading} isSuccess={isSuccess} setIsSuccess={setIsSuccess} loginMethod={loginMethod} formData={formData} setStep={setStep} />
|
|
|
|
|
)}
|
|
|
|
|
</AnimatePresence>
|
|
|
|
|
<CreateNewAccount />
|
|
|
|
|
</div>
|
|
|
|
|
</motion.div>
|
|
|
|
|
<PolicyAndPrivecy />
|
|
|
|
|
</motion.div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|