'use client'; import { useState, useEffect } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { motion, AnimatePresence } from 'framer-motion'; import { Mail, Lock, Eye, EyeOff, LogIn, AlertCircle, Flag, Shield, } from 'lucide-react'; import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; import Input from '@/components/ui/Input'; import Heading from '@/components/ui/Heading'; import { useAuth } from '@/lib/auth/AuthContext'; import AuthWorkflowMockup from '@/components/auth/AuthWorkflowMockup'; import UserRolesPreview from '@/components/auth/UserRolesPreview'; import { EnhancedFormError, FormErrorSummary } from '@/components/errors/EnhancedFormError'; import { useEnhancedForm } from '@/lib/hooks/useEnhancedForm'; import { validateLoginForm, type LoginFormValues } from '@/lib/utils/validation'; import { logErrorWithContext } from '@/lib/utils/errorUtils'; export default function LoginPage() { const router = useRouter(); const searchParams = useSearchParams(); const { refreshSession, session } = useAuth(); const returnTo = searchParams.get('returnTo') ?? '/dashboard'; const [showPassword, setShowPassword] = useState(false); const [showErrorDetails, setShowErrorDetails] = useState(false); const [hasInsufficientPermissions, setHasInsufficientPermissions] = useState(false); // Check if user is already authenticated useEffect(() => { if (session) { // If there's a returnTo parameter (user was redirected here from a protected route), // they might not have permission. Don't auto-redirect them back. const returnToParam = searchParams.get('returnTo'); console.log('[LOGIN] returnToParam:', returnToParam); console.log('[LOGIN] returnTo:', returnTo); const hasReturnTo = returnToParam !== null; if (hasReturnTo) { console.log('[LOGIN] Has returnTo, setting insufficient permissions'); setHasInsufficientPermissions(true); } else { // No returnTo means they navigated here directly while authenticated console.log('[LOGIN] No returnTo, redirecting to dashboard'); router.replace('/dashboard'); } } }, [session, router, returnTo, searchParams]); // Use enhanced form hook const { formState, setFormState, handleChange, handleSubmit, setFormError, } = useEnhancedForm({ initialValues: { email: '', password: '', rememberMe: false, }, validate: validateLoginForm, component: 'LoginPage', onSubmit: async (values) => { const { ServiceFactory } = await import('@/lib/services/ServiceFactory'); const serviceFactory = new ServiceFactory(process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001'); const authService = serviceFactory.createAuthService(); // Log the attempt for debugging logErrorWithContext( { message: 'Login attempt', values: { ...values, password: '[REDACTED]' } }, { component: 'LoginPage', action: 'login-submit', formData: { ...values, password: '[REDACTED]' }, } ); await authService.login({ email: values.email, password: values.password, rememberMe: values.rememberMe, }); // Refresh session in context so header updates immediately await refreshSession(); router.push(returnTo); }, onError: (error, values) => { // Show error details toggle in development if (process.env.NODE_ENV === 'development') { setShowErrorDetails(true); } }, onSuccess: () => { // Reset error details on success setShowErrorDetails(false); }, }); return (
{/* Background Pattern */}
{/* Left Side - Info Panel (Hidden on mobile) */}
{/* Logo */}
GridPilot
Your Sim Racing Infrastructure

Manage leagues, track performance, join teams, and compete with drivers worldwide. One account, multiple roles.

{/* Role Cards */} {/* Workflow Mockup */} {/* Trust Indicators */}
Secure login
iRacing verified
{/* Right Side - Login Form */}
{/* Mobile Logo/Header */}
Welcome Back

Sign in to continue to GridPilot

{/* Desktop Header */}
Welcome Back

Sign in to access your racing dashboard

{/* Background accent */}
{/* Email */}
{/* Password */}
Forgot password?
{/* Remember Me */}
{/* Insufficient Permissions Message */} {hasInsufficientPermissions && (
Insufficient Permissions

You don't have permission to access that page. Please log in with an account that has the required role.

)}
{/* Enhanced Error Display */} {formState.submitError && ( { // Clear the error by setting submitError to undefined setFormState(prev => ({ ...prev, submitError: undefined })); }} showDeveloperDetails={showErrorDetails} /> )} {/* Submit Button */}
{/* Divider */}
or continue with
{/* Sign Up Link */}

Don't have an account?{' '} Create one

{/* Name Immutability Notice */}
Note: Your display name cannot be changed after signup. Please ensure it's correct when creating your account.
{/* Footer */}

By signing in, you agree to our{' '} Terms of Service {' '}and{' '} Privacy Policy

{/* Mobile Role Info */}
); }