'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 { useLogin } from "@/lib/hooks/auth/useLogin"; import AuthWorkflowMockup from '@/components/auth/AuthWorkflowMockup'; import UserRolesPreview from '@/components/auth/UserRolesPreview'; import { EnhancedFormError } from '@/components/errors/EnhancedFormError'; import { useEnhancedForm } from '@/lib/hooks/useEnhancedForm'; import { validateLoginForm, type LoginFormValues } from '@/lib/utils/validation'; import { logErrorWithContext } from '@/lib/utils/errorUtils'; import { StatefulPageWrapper } from '@/components/shared/state/StatefulPageWrapper'; // Template component for login UI function LoginTemplate({ data }: { data: { returnTo: string; hasInsufficientPermissions: boolean; showPassword: boolean; showErrorDetails: boolean; formState: any; handleChange: any; handleSubmit: any; setFormState: any; setShowPassword: any; setShowErrorDetails: any; } }) { const { returnTo, hasInsufficientPermissions, showPassword, showErrorDetails, formState, handleChange, handleSubmit, setFormState, setShowPassword, setShowErrorDetails, } = data; 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: typeof formState) => ({ ...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 */}
); } 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); // Use login mutation hook const loginMutation = useLogin({ onSuccess: async () => { // Refresh session in context so header updates immediately await refreshSession(); router.push(returnTo); }, onError: (error) => { // Show error details toggle in development if (process.env.NODE_ENV === 'development') { setShowErrorDetails(true); } }, }); // Check if user is already authenticated useEffect(() => { console.log('[LoginPage] useEffect running', { session: session ? 'exists' : 'null', returnTo: searchParams.get('returnTo'), pathname: window.location.pathname, search: window.location.search, }); if (session) { // Check if this is a returnTo redirect (user lacks permissions) const isPermissionRedirect = searchParams.get('returnTo') !== null; console.log('[LoginPage] Authenticated user check', { isPermissionRedirect, returnTo: searchParams.get('returnTo'), }); if (isPermissionRedirect) { // User was redirected here due to insufficient permissions // Show permission error instead of redirecting console.log('[LoginPage] Showing permission error'); setHasInsufficientPermissions(true); } else { // User navigated here directly while authenticated, redirect to dashboard console.log('[LoginPage] Redirecting to dashboard'); router.replace('/dashboard'); } } }, [session, router, searchParams]); // Use enhanced form hook const { formState, setFormState, handleChange, handleSubmit, } = useEnhancedForm({ initialValues: { email: '', password: '', rememberMe: false, }, validate: validateLoginForm, component: 'LoginPage', onSubmit: async (values) => { // Log the attempt for debugging logErrorWithContext( { message: 'Login attempt', values: { ...values, password: '[REDACTED]' } }, { component: 'LoginPage', action: 'login-submit', formData: { ...values, password: '[REDACTED]' }, } ); await loginMutation.mutateAsync({ email: values.email, password: values.password, rememberMe: values.rememberMe, }); }, onError: (error, values) => { // Error handling is done in the mutation's onError callback }, onSuccess: () => { // Reset error details on success setShowErrorDetails(false); }, }); // Prepare template data const templateData = { returnTo, hasInsufficientPermissions, showPassword, showErrorDetails, formState, handleChange, handleSubmit, setFormState, setShowPassword, setShowErrorDetails, }; // Mutation state for wrapper const isLoading = loginMutation.isPending; const error = loginMutation.error; return ( loginMutation.mutate({ email: '', password: '', rememberMe: false })} Template={LoginTemplate} loading={{ variant: 'full-screen', message: 'Loading login...' }} errorConfig={{ variant: 'full-screen' }} /> ); }