'use client'; import { useState, useEffect, Suspense } from 'react'; import { useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { useLanguage } from '@/context/LanguageContext'; import { useAuth } from '@/context/AuthContext'; import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; import Input from '@/components/ui/Input'; import GoogleSignInButton from '@/components/GoogleSignInButton'; import { authApi } from '@/lib/api'; import { safeInternalPath } from '@/lib/safeRedirect'; import { clearRedirectAttempt, didRedirectBounce, redirectAfterAuth, } from '@/lib/authRedirect'; import toast from 'react-hot-toast'; function LoginContent() { const searchParams = useSearchParams(); const { t, locale: language } = useLanguage(); const { login, user, isLoading: authLoading } = useAuth(); const [loading, setLoading] = useState(false); const [redirecting, setRedirecting] = useState(false); const [bounced, setBounced] = useState(false); const [loginMode, setLoginMode] = useState<'password' | 'magic-link'>('password'); const [magicLinkSent, setMagicLinkSent] = useState(false); const [formData, setFormData] = useState({ email: '', password: '', }); // Check for redirect after login (only same-origin relative paths are honoured) const redirectTo = safeInternalPath(searchParams.get('redirect'), '/dashboard'); // Send an already-signed-in visitor on to their destination — and detect the case // where that destination bounced them back here, which otherwise looks like the // login page silently ignoring a successful sign-in. useEffect(() => { if (authLoading || redirecting) return; if (!user) { // Signed out on the login page is a clean slate. clearRedirectAttempt(); return; } if (didRedirectBounce(redirectTo)) { setBounced(true); return; } setRedirecting(true); redirectAfterAuth(redirectTo); }, [authLoading, redirecting, user, redirectTo]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); try { await login(formData.email, formData.password); toast.success(language === 'es' ? '¡Bienvenido!' : 'Welcome back!'); // Deliberately leaves `loading` set: the button must stay disabled until the // browser replaces this page. setRedirecting(true); redirectAfterAuth(redirectTo); } catch (error: any) { toast.error(error.message || t('auth.errors.invalidCredentials')); setLoading(false); } }; const handleMagicLinkRequest = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.email) { toast.error(language === 'es' ? 'Ingresa tu email' : 'Please enter your email'); return; } setLoading(true); try { await authApi.requestMagicLink(formData.email); setMagicLinkSent(true); toast.success( language === 'es' ? 'Revisa tu correo para el enlace de acceso' : 'Check your email for the login link' ); } catch (error: any) { toast.error(error.message || (language === 'es' ? 'Error' : 'Failed')); } finally { setLoading(false); } }; // The destination sent us back here even though the session is valid. Say so, rather // than re-showing a form that appears to do nothing. The retry link is a plain so // it is a full page load, like every other navigation out of this page. if (bounced) { return (

{t('auth.login.redirectBlocked')}

{user &&

{user.email}

}

{redirectTo}

{t('nav.home')}
); } return (

{t('auth.login.title')}

{t('auth.login.subtitle')}

{/* Google Sign-In Button */} {/* Or Divider */}
{language === 'es' ? 'o continuar con' : 'or continue with'}
{/* Login Mode Tabs */}
{loginMode === 'password' ? (
setFormData({ ...formData, email: e.target.value })} required /> setFormData({ ...formData, password: e.target.value })} required />
{language === 'es' ? '¿Olvidaste tu contraseña?' : 'Forgot password?'}
{redirecting && (

{t('auth.login.redirecting')}

)}
) : magicLinkSent ? (

{language === 'es' ? 'Revisa tu Email' : 'Check Your Email'}

{language === 'es' ? `Enviamos un enlace de acceso a ${formData.email}` : `We sent a login link to ${formData.email}`}

) : (
setFormData({ ...formData, email: e.target.value })} required />

{language === 'es' ? 'Te enviaremos un enlace para iniciar sesión sin contraseña' : "We'll send you a link to sign in without a password"}

)}

{t('auth.login.noAccount')}{' '} {t('auth.login.register')}

); } function LoadingFallback() { return (
); } export default function LoginPage() { return ( }> ); }