125 lines
5.5 KiB
JavaScript
125 lines
5.5 KiB
JavaScript
import { EyeOff, Mail, Phone, Eye, LogIn, Lock, Loader2, CheckCircle } from "lucide-react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { motion } from "framer-motion";
|
|
import Link from "next/link";
|
|
import { useState } from "react";
|
|
|
|
export default function LoginForm({ loginMethod, errors, formData, isLoading, isSuccess, setFormData, handleCredentialChange }) {
|
|
const { t } = useTranslation();
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
return (
|
|
<>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-300 mb-2">{loginMethod === "email" ? t("emailLabel") : t("phoneLabel")}</label>
|
|
<div className="relative group">
|
|
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
|
|
{loginMethod === "email" ? (
|
|
<Mail className={`w-5 h-5 transition-colors ${errors.credential ? "text-red-500" : "text-gray-400 group-focus-within:text-amber-500"}`} />
|
|
) : (
|
|
<Phone className={`w-5 h-5 transition-colors ${errors.credential ? "text-red-500" : "text-gray-400 group-focus-within:text-amber-500"}`} />
|
|
)}
|
|
</div>
|
|
<input
|
|
type="text"
|
|
// type={loginMethod === 'email' ? 'email' : 'tel'}
|
|
value={formData.credential}
|
|
onChange={(e) => handleCredentialChange(e.target.value)}
|
|
className={`w-full pr-12 pl-4 py-4 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent text-amber-50 placeholder-gray-500 transition-all ${
|
|
errors.credential ? "border-red-500" : "border-gray-700"
|
|
}`}
|
|
placeholder={loginMethod === "email" ? t("emailPlaceholder") : t("phonePlaceholder")}
|
|
dir="ltr"
|
|
/>
|
|
</div>
|
|
{errors.credential && (
|
|
<motion.p initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }} className="text-red-500 text-sm mt-1">
|
|
{errors.credential}
|
|
</motion.p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Password */}
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-300 mb-2">{t("password")}</label>
|
|
<div className="relative group">
|
|
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
|
|
<Lock className={`w-5 h-5 transition-colors ${errors.password ? "text-red-500" : "text-gray-400 group-focus-within:text-amber-500"}`} />
|
|
</div>
|
|
<input
|
|
type={showPassword ? "text" : "password"}
|
|
value={formData.password}
|
|
onChange={(e) => {
|
|
setFormData({
|
|
...formData,
|
|
password: e.target.value,
|
|
});
|
|
if (errors.password) setErrors({ ...errors, password: null });
|
|
}}
|
|
className={`w-full pr-12 pl-12 py-4 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent text-amber-50 placeholder-gray-500 transition-all ${
|
|
errors.password ? "border-red-500" : "border-gray-700"
|
|
}`}
|
|
placeholder={t("passwordPlaceholder")}
|
|
/>
|
|
<button type="button" onClick={() => setShowPassword(!showPassword)} className="absolute inset-y-0 left-0 pl-3 flex items-center">
|
|
{showPassword ? <EyeOff className="w-5 h-5 text-gray-400 hover:text-gray-300 transition-colors" /> : <Eye className="w-5 h-5 text-gray-400 hover:text-gray-300 transition-colors" />}
|
|
</button>
|
|
</div>
|
|
{errors.password && (
|
|
<motion.p initial={{ opacity: 0, y: -10 }} animate={{ opacity: 1, y: 0 }} className="text-red-500 text-sm mt-1">
|
|
{errors.password}
|
|
</motion.p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Remember + Forgot */}
|
|
<div className="flex items-center justify-between">
|
|
<label className="flex items-center gap-2 cursor-pointer group">
|
|
<input
|
|
type="checkbox"
|
|
checked={formData.rememberMe}
|
|
onChange={(e) =>
|
|
setFormData({
|
|
...formData,
|
|
rememberMe: e.target.checked,
|
|
})
|
|
}
|
|
className="w-4 h-4 rounded border-gray-600 bg-white/5 text-amber-500 focus:ring-amber-500 focus:ring-offset-0"
|
|
/>
|
|
<span className="text-sm text-gray-400 group-hover:text-white transition-colors">{t("rememberMe")}</span>
|
|
</label>
|
|
<Link href="/forgot-password" className="text-sm text-amber-400 hover:text-amber-300 transition-colors">
|
|
{t("forgotPassword")}
|
|
</Link>
|
|
</div>
|
|
|
|
{/* Submit */}
|
|
<motion.button
|
|
type="submit"
|
|
disabled={isLoading || isSuccess}
|
|
className="relative w-full bg-gradient-to-r from-amber-500 to-amber-600 text-white py-4 rounded-xl font-bold text-lg overflow-hidden group disabled:opacity-50 disabled:cursor-not-allowed"
|
|
whileHover={{ scale: 1.02 }}
|
|
whileTap={{ scale: 0.98 }}
|
|
>
|
|
<span className="relative z-10 flex items-center justify-center gap-2">
|
|
{isLoading ? (
|
|
<>
|
|
<Loader2 className="w-5 h-5 animate-spin" />
|
|
{t("loggingIn")}{" "}
|
|
</>
|
|
) : isSuccess ? (
|
|
<>
|
|
<CheckCircle className="w-5 h-5" /> {t("success")}{" "}
|
|
</>
|
|
) : (
|
|
<>
|
|
{" "}
|
|
<LogIn className="w-5 h-5" />
|
|
{t("login")}
|
|
</>
|
|
)}
|
|
</span>
|
|
</motion.button>
|
|
</>
|
|
);
|
|
}
|