diff --git a/app/login/page.js b/app/login/page.js index 305003a..94ab127 100644 --- a/app/login/page.js +++ b/app/login/page.js @@ -1,10 +1,10 @@ -'use client'; +"use client"; -import { useState } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import toast, { Toaster } from 'react-hot-toast'; -import Link from 'next/link'; -import { useRouter } from 'next/navigation'; +import { useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import toast, { Toaster } from "react-hot-toast"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; import { Mail, Lock, @@ -18,7 +18,7 @@ import { Shield, Phone, KeyRound, -} from 'lucide-react'; +} from "lucide-react"; import { loginWithEmail, loginWithPhone, @@ -30,44 +30,45 @@ import { isPhoneNumber, getOwnerByUserId, getCustomerByUserId, -} from '../utils/api'; -import AuthService from '../services/AuthService'; +} from "../utils/api"; +import AuthService from "../services/AuthService"; export default function LoginPage() { const router = useRouter(); // Step: 'login' | 'otp' - const [step, setStep] = useState('login'); - const [loginMethod, setLoginMethod] = useState('email'); // 'email' | 'phone' + const [step, setStep] = useState("login"); + const [loginMethod, setLoginMethod] = useState("email"); // 'email' | 'phone' const [showPassword, setShowPassword] = useState(false); const [isLoading, setIsLoading] = useState(false); const [isSuccess, setIsSuccess] = useState(false); const [formData, setFormData] = useState({ - credential: '', - password: '', + credential: "", + password: "", rememberMe: false, }); - const [otpCode, setOtpCode] = useState(''); - const [otpError, setOtpError] = useState(''); + const [otpCode, setOtpCode] = useState(""); + const [otpError, setOtpError] = useState(""); const [errors, setErrors] = useState({}); const validateForm = () => { const newErrors = {}; if (!formData.credential) { - newErrors.credential = loginMethod === 'email' - ? 'البريد الإلكتروني مطلوب' - : 'رقم الهاتف مطلوب'; - // } else if (loginMethod === 'email' && !isEmail(formData.credential)) { - // newErrors.credential = 'البريد الإلكتروني غير صالح'; - // } else if (loginMethod === 'phone' && !isPhoneNumber(formData.credential)) { - newErrors.credential = 'رقم الهاتف غير صالح'; + newErrors.credential = + loginMethod === "email" + ? "البريد الإلكتروني مطلوب" + : "رقم الهاتف مطلوب"; + // } else if (loginMethod === 'email' && !isEmail(formData.credential)) { + // newErrors.credential = 'البريد الإلكتروني غير صالح'; + // } else if (loginMethod === 'phone' && !isPhoneNumber(formData.credential)) { + newErrors.credential = "رقم الهاتف غير صالح"; } if (!formData.password) { - newErrors.password = 'كلمة المرور مطلوبة'; + newErrors.password = "كلمة المرور مطلوبة"; } setErrors(newErrors); @@ -82,17 +83,25 @@ export default function LoginPage() { setErrors({}); try { - const loginFn = loginMethod === 'email' ? loginWithEmail : loginWithPhone; - console.log('[Login] Attempting login via', loginMethod, ':', formData.credential); + const loginFn = loginMethod === "email" ? loginWithEmail : loginWithPhone; + console.log( + "[Login] Attempting login via", + loginMethod, + ":", + formData.credential, + ); const result = await loginFn(formData.credential, formData.password); - console.log('[Login] Response status:', result.status); + console.log("[Login] Response status:", result.status); if (result.status === 200) { - const token = typeof result.data === 'string' ? result.data : result.data?.token || result.data?.accessToken; + const token = + typeof result.data === "string" + ? result.data + : result.data?.token || result.data?.accessToken; AuthService.addToken(token); - console.log('[Login] Token stored'); + console.log("[Login] Token stored"); // Fetch user profile to get full name const authUser = AuthService.getUser(); @@ -103,71 +112,81 @@ export default function LoginPage() { const profile = await fetchFn(authUser.id); if (profile) { AuthService.cacheUser({ - name: profile.fullName || profile.name || `${profile.firstName || ''} ${profile.lastName || ''}`.trim(), + name: + profile.fullName || + profile.name || + `${profile.firstName || ""} ${profile.lastName || ""}`.trim(), email: profile.email || authUser.email, phone: profile.phone || profile.phoneNumber || authUser.phone, }); - console.log('[Login] User profile cached'); + console.log("[Login] User profile cached"); } } catch (err) { - console.warn('[Login] Failed to fetch profile:', err); + console.warn("[Login] Failed to fetch profile:", err); } } - const userRole = AuthService.isAdmin() ? 'admin' - : AuthService.isOwner() ? 'owner' - : 'customer'; - console.log('[Login] User role:', userRole); + const userRole = AuthService.isAdmin() + ? "admin" + : AuthService.isOwner() + ? "owner" + : "customer"; + console.log("[Login] User role:", userRole); setIsSuccess(true); - toast.success('تم تسجيل الدخول بنجاح!', { - style: { background: '#dcfce7', color: '#166534' }, + toast.success("تم تسجيل الدخول بنجاح!", { + style: { background: "#dcfce7", color: "#166534" }, }); setTimeout(() => { - if (userRole === 'admin') { - router.push('/admin'); + if (userRole === "admin") { + router.push("/admin"); } else { - router.push('/'); + router.push("/"); } }, 1500); - } else if (result.status === 206) { - console.log('[Login] 206 — OTP required'); - const tempToken = typeof result.data === 'string' ? result.data : result.data?.token || result.data?.accessToken; + console.log("[Login] 206 — OTP required"); + const tempToken = + typeof result.data === "string" + ? result.data + : result.data?.token || result.data?.accessToken; if (tempToken) { AuthService.addToken(tempToken); - console.log('[Login] Temp token stored for OTP'); + console.log("[Login] Temp token stored for OTP"); } - toast('يرجى إدخال رمز التحقق', { - icon: '🔐', - style: { background: '#fef3c7', color: '#92400e' }, + toast("يرجى إدخال رمز التحقق", { + icon: "🔐", + style: { background: "#fef3c7", color: "#92400e" }, }); // Send OTP try { - if (loginMethod === 'email') { + if (loginMethod === "email") { await sendEmailOTP(); } else { await sendPhoneOTP(); } - console.log('[Login] OTP sent successfully'); + console.log("[Login] OTP sent successfully"); } catch (otpErr) { - console.warn('[Login] OTP send failed, proceeding anyway:', otpErr); + console.warn("[Login] OTP send failed, proceeding anyway:", otpErr); } - setStep('otp'); + setStep("otp"); } else { // Other error - console.error('[Login] Unexpected status:', result.status, result.data); - toast.error(result.data?.message || result.data || 'بيانات الدخول غير صحيحة', { - style: { background: '#fee2e2', color: '#991b1b' }, - }); + console.error("[Login] Unexpected status:", result.status, result.data); + toast.error( + result.data?.message || result.data || "بيانات الدخول غير صحيحة", + { + style: { background: "#fee2e2", color: "#991b1b" }, + }, + ); } } catch (err) { - console.error('[Login] Error:', err); - toast.error(err.message || 'حدث خطأ في الاتصال', { - style: { background: '#fee2e2', color: '#991b1b' }, + console.error("[Login] Error:", err); + toast.error(err.message || "حدث خطأ في الاتصال", { + style: { background: "#fee2e2", color: "#991b1b" }, }); } finally { setIsLoading(false); @@ -177,43 +196,46 @@ export default function LoginPage() { const handleVerifyOTP = async (e) => { e.preventDefault(); if (!otpCode || otpCode.length < 4) { - setOtpError('يرجى إدخال رمز التحقق'); + setOtpError("يرجى إدخال رمز التحقق"); return; } setIsLoading(true); - setOtpError(''); + setOtpError(""); try { - const verifyFn = loginMethod === 'email' ? verifyEmail : verifyPhone; - console.log('[OTP] Verifying code:', otpCode); + const verifyFn = loginMethod === "email" ? verifyEmail : verifyPhone; + console.log("[OTP] Verifying code:", otpCode); const result = await verifyFn(otpCode); - console.log('[OTP] Verify response status:', result.status); + console.log("[OTP] Verify response status:", result.status); if (result.ok) { - const finalToken = typeof result.data === 'string' ? result.data : result.data?.token || result.data?.accessToken; - if (finalToken && typeof finalToken === 'string') { + const finalToken = + typeof result.data === "string" + ? result.data + : result.data?.token || result.data?.accessToken; + if (finalToken && typeof finalToken === "string") { AuthService.addToken(finalToken); - console.log('[OTP] Final token stored'); + console.log("[OTP] Final token stored"); } setIsSuccess(true); - toast.success('تم التحقق بنجاح!', { - style: { background: '#dcfce7', color: '#166534' }, + toast.success("تم التحقق بنجاح!", { + style: { background: "#dcfce7", color: "#166534" }, }); setTimeout(() => { - console.log('[OTP] Redirecting to home'); - router.push('/'); + console.log("[OTP] Redirecting to home"); + router.push("/"); }, 1500); } else { - console.error('[OTP] Verification failed:', result.data); - setOtpError(result.data?.message || 'رمز التحقق غير صحيح'); + console.error("[OTP] Verification failed:", result.data); + setOtpError(result.data?.message || "رمز التحقق غير صحيح"); } } catch (err) { - console.error('[OTP] Error:', err); - setOtpError(err.message || 'حدث خطأ في التحقق'); + console.error("[OTP] Error:", err); + setOtpError(err.message || "حدث خطأ في التحقق"); } finally { setIsLoading(false); } @@ -221,18 +243,18 @@ export default function LoginPage() { const resendOTP = async () => { try { - console.log('[OTP] Resending OTP via', loginMethod); - if (loginMethod === 'email') { + console.log("[OTP] Resending OTP via", loginMethod); + if (loginMethod === "email") { await sendEmailOTP(); } else { await sendPhoneOTP(); } - toast.success('تم إرسال رمز التحقق مجدداً', { - style: { background: '#dcfce7', color: '#166534' }, + toast.success("تم إرسال رمز التحقق مجدداً", { + style: { background: "#dcfce7", color: "#166534" }, }); } catch (err) { - console.error('[OTP] Resend failed:', err); - toast.error('فشل إرسال الرمز'); + console.error("[OTP] Resend failed:", err); + toast.error("فشل إرسال الرمز"); } }; @@ -271,7 +293,7 @@ export default function LoginPage() { visible: { y: 0, opacity: 1, - transition: { type: 'spring', stiffness: 100 }, + transition: { type: "spring", stiffness: 100 }, }, }; @@ -285,9 +307,23 @@ export default function LoginPage() { ))} @@ -312,8 +348,14 @@ export default function LoginPage() { > {/* Back link */} - - + + العودة للرئيسية @@ -329,23 +371,28 @@ export default function LoginPage() { - + - {step === 'otp' ? ( + {step === "otp" ? ( ) : ( @@ -353,14 +400,14 @@ export default function LoginPage() {

SweetHome

- {step === 'otp' ? 'أدخل رمز التحقق' : 'مرحباً بعودتك!'} + {step === "otp" ? "أدخل رمز التحقق" : "مرحباً بعودتك!"}

- {step === 'login' ? ( + {step === "login" ? ( { - setLoginMethod('email'); - setFormData({ ...formData, credential: '' }); + setLoginMethod("email"); + setFormData({ ...formData, credential: "" }); }} className={`flex-1 py-2.5 rounded-lg text-sm font-medium transition-all flex items-center justify-center gap-2 ${ - loginMethod === 'email' - ? 'bg-amber-500 text-white shadow-lg' - : 'text-gray-400 hover:text-white' + loginMethod === "email" + ? "bg-amber-500 text-white shadow-lg" + : "text-gray-400 hover:text-white" }`} > @@ -389,13 +436,13 @@ export default function LoginPage() {
{errors.password && ( - + {errors.password} )} @@ -474,12 +554,22 @@ export default function LoginPage() { setFormData({ ...formData, rememberMe: e.target.checked })} + 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" /> - تذكرني + + تذكرني + - + نسيت كلمة المرور؟ @@ -525,7 +615,7 @@ export default function LoginPage() {

- تم إرسال رمز التحقق إلى{' '} + تم إرسال رمز التحقق إلى{" "} {formData.credential} @@ -533,23 +623,29 @@ export default function LoginPage() {

- + { setOtpCode(e.target.value); - if (otpError) setOtpError(''); + if (otpError) setOtpError(""); }} className={`w-full px-4 py-4 bg-white/5 border rounded-xl focus:outline-none focus:ring-2 focus:ring-amber-500 focus:border-transparent text-white text-center text-2xl tracking-[0.5em] placeholder-gray-500 transition-all ${ - otpError ? 'border-red-500' : 'border-gray-700' + otpError ? "border-red-500" : "border-gray-700" }`} placeholder="______" maxLength={6} dir="ltr" /> {otpError && ( - + {otpError} )} @@ -586,10 +682,10 @@ export default function LoginPage() {
- - بتسجيل الدخول، أنت توافق على{' '} - شروط الاستخدام - {' '}و{' '} - سياسة الخصوصية + + بتسجيل الدخول، أنت توافق على{" "} + + شروط الاستخدام + {" "} + و{" "} + + سياسة الخصوصية +