'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 { Mail, Lock, Eye, EyeOff, ArrowLeft, LogIn, CheckCircle, Loader2, Home, Shield, Phone, KeyRound, } from 'lucide-react'; import { loginWithEmail, loginWithPhone, sendEmailOTP, sendPhoneOTP, verifyEmail, verifyPhone, isEmail, isPhoneNumber, getOwnerByUserId, getCustomerByUserId, } 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 [showPassword, setShowPassword] = useState(false); const [isLoading, setIsLoading] = useState(false); const [isSuccess, setIsSuccess] = useState(false); const [formData, setFormData] = useState({ credential: '', password: '', rememberMe: false, }); 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 = 'رقم الهاتف غير صالح'; } if (!formData.password) { newErrors.password = 'كلمة المرور مطلوبة'; } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleLogin = async (e) => { e.preventDefault(); if (!validateForm()) return; setIsLoading(true); setErrors({}); try { 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); if (result.status === 200) { const token = typeof result.data === 'string' ? result.data : result.data?.token || result.data?.accessToken; AuthService.addToken(token); console.log('[Login] Token stored'); // Fetch user profile to get full name const authUser = AuthService.getUser(); if (authUser?.id) { try { const isOwner = AuthService.isOwner(); const fetchFn = isOwner ? getOwnerByUserId : getCustomerByUserId; const profile = await fetchFn(authUser.id); if (profile) { AuthService.cacheUser({ 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'); } } catch (err) { console.warn('[Login] Failed to fetch profile:', err); } } const userRole = AuthService.isAdmin() ? 'admin' : AuthService.isOwner() ? 'owner' : 'customer'; console.log('[Login] User role:', userRole); setIsSuccess(true); toast.success('تم تسجيل الدخول بنجاح!', { style: { background: '#dcfce7', color: '#166534' }, }); setTimeout(() => { if (userRole === 'admin') { router.push('/admin'); } else { 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; if (tempToken) { AuthService.addToken(tempToken); console.log('[Login] Temp token stored for OTP'); } toast('يرجى إدخال رمز التحقق', { icon: '🔐', style: { background: '#fef3c7', color: '#92400e' }, }); // Send OTP try { if (loginMethod === 'email') { await sendEmailOTP(); } else { await sendPhoneOTP(); } console.log('[Login] OTP sent successfully'); } catch (otpErr) { console.warn('[Login] OTP send failed, proceeding anyway:', otpErr); } 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' }, }); } } catch (err) { console.error('[Login] Error:', err); toast.error(err.message || 'حدث خطأ في الاتصال', { style: { background: '#fee2e2', color: '#991b1b' }, }); } finally { setIsLoading(false); } }; const handleVerifyOTP = async (e) => { e.preventDefault(); if (!otpCode || otpCode.length < 4) { setOtpError('يرجى إدخال رمز التحقق'); return; } setIsLoading(true); setOtpError(''); try { 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); if (result.ok) { 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'); } setIsSuccess(true); toast.success('تم التحقق بنجاح!', { style: { background: '#dcfce7', color: '#166534' }, }); setTimeout(() => { console.log('[OTP] Redirecting to home'); router.push('/'); }, 1500); } else { console.error('[OTP] Verification failed:', result.data); setOtpError(result.data?.message || 'رمز التحقق غير صحيح'); } } catch (err) { console.error('[OTP] Error:', err); setOtpError(err.message || 'حدث خطأ في التحقق'); } finally { setIsLoading(false); } }; const resendOTP = async () => { try { console.log('[OTP] Resending OTP via', loginMethod); if (loginMethod === 'email') { await sendEmailOTP(); } else { await sendPhoneOTP(); } toast.success('تم إرسال رمز التحقق مجدداً', { style: { background: '#dcfce7', color: '#166534' }, }); } catch (err) { console.error('[OTP] Resend failed:', err); toast.error('فشل إرسال الرمز'); } }; // Auto-detect login method from input const handleCredentialChange = (value) => { setFormData({ ...formData, credential: value }); if (errors.credential) setErrors({ ...errors, credential: null }); // Auto-switch method if (isEmail(value)) { setLoginMethod('email'); } else if (isPhoneNumber(value)) { setLoginMethod('phone'); } }; const particles = Array.from({ length: 20 }, (_, i) => ({ id: i, x: Math.random() * 100, y: Math.random() * 100, size: Math.random() * 3 + 1, duration: Math.random() * 15 + 10, delay: Math.random() * 5, })); const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.1, delayChildren: 0.2 }, }, }; const itemVariants = { hidden: { y: 20, opacity: 0 }, visible: { y: 0, opacity: 1, transition: { type: 'spring', stiffness: 100 }, }, }; return (
{step === 'otp' ? 'أدخل رمز التحقق' : 'مرحباً بعودتك!'}
تم إرسال رمز التحقق إلى{' '} {formData.credential}