'use client'; import { useState, Suspense } from 'react'; import { Link } from '@/i18n/navigation'; import Image from 'next/image'; import { useSearchParams } from 'next/navigation'; import { useTranslations } from 'next-intl'; import { useAuth } from '@/lib/context/auth-context'; interface FieldErrors { email?: string; password?: string; } type ErrorField = 'email' | 'password' | 'general'; function mapLoginError( error: any, t: (key: string) => string ): { message: string; field: ErrorField } { const errorMessage = error?.message || error?.response?.message || ''; if (error?.name === 'TypeError' || errorMessage.includes('fetch')) { return { message: t('errors.network'), field: 'general' }; } if (errorMessage.includes('Invalid credentials') || errorMessage.includes('Identifiants')) { return { message: t('errors.invalidCredentials'), field: 'general' }; } if (errorMessage.includes('inactive') || errorMessage.includes('désactivé')) { return { message: t('errors.inactive'), field: 'general' }; } if (errorMessage.includes('not found') || errorMessage.includes('introuvable')) { return { message: t('errors.notFound'), field: 'email' }; } if (errorMessage.includes('password') || errorMessage.includes('mot de passe')) { return { message: t('errors.incorrectPassword'), field: 'password' }; } if (errorMessage.includes('Too many') || errorMessage.includes('rate limit')) { return { message: t('errors.rateLimit'), field: 'general' }; } return { message: errorMessage || t('errors.generic'), field: 'general' }; } function LoginPageContent() { const { login } = useAuth(); const searchParams = useSearchParams(); const redirectTo = searchParams.get('redirect') || '/dashboard'; const tLogin = useTranslations('auth.login'); const tPanel = useTranslations('auth.sidePanel'); const tFooter = useTranslations('auth.footerLinks'); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [rememberMe, setRememberMe] = useState(false); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); const [fieldErrors, setFieldErrors] = useState({}); const validateForm = (): boolean => { const errors: FieldErrors = {}; if (!email.trim()) { errors.email = tLogin('fieldErrors.emailRequired'); } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { errors.email = tLogin('fieldErrors.emailInvalid'); } if (!password) { errors.password = tLogin('fieldErrors.passwordRequired'); } else if (password.length < 6) { errors.password = tLogin('fieldErrors.passwordMin'); } setFieldErrors(errors); return Object.keys(errors).length === 0; }; const handleEmailChange = (e: React.ChangeEvent) => { setEmail(e.target.value); }; const handlePasswordChange = (e: React.ChangeEvent) => { setPassword(e.target.value); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(''); setFieldErrors({}); if (!validateForm()) { return; } setIsLoading(true); try { await login(email, password, redirectTo, rememberMe); } catch (err: any) { const { message, field } = mapLoginError(err, tLogin); if (field === 'email') { setFieldErrors({ email: message }); } else if (field === 'password') { setFieldErrors({ password: message }); } else { setError(message); } } finally { setIsLoading(false); } }; return (
Xpeditis

{tLogin('title')}

{tLogin('subtitle')}

{error && (

{error}

)}
{fieldErrors.email && (

{fieldErrors.email}

)}
{fieldErrors.password && (

{fieldErrors.password}

)}
{tLogin('forgotPassword')}

{tLogin('noAccount')}{' '} {tLogin('createAccount')}

{tFooter('contact')} {tFooter('privacy')} {tFooter('terms')}

{tPanel('title')}

{tPanel('description')}

{tPanel('features.instantRates.title')}

{tPanel('features.instantRates.description')}

{tPanel('features.booking.title')}

{tPanel('features.booking.description')}

{tPanel('features.tracking.title')}

{tPanel('features.tracking.description')}

50+
{tPanel('stats.carriers')}
10k+
{tPanel('stats.shipments')}
99.5%
{tPanel('stats.satisfaction')}
); } export default function LoginPage() { return ( ); }