/** * Signup Template * * Pure presentation component that accepts ViewData only. * No business logic, no state management. */ 'use client'; import Link from 'next/link'; import { motion } from 'framer-motion'; import { Mail, Lock, Eye, EyeOff, UserPlus, AlertCircle, Flag, User, Check, X, Car, Users, Trophy, Shield, Sparkles, } 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 { SignupViewData } from '@/lib/builders/view-data/types/SignupViewData'; import { checkPasswordStrength } from '@/lib/utils/validation'; interface SignupTemplateProps { viewData: SignupViewData; formActions: { setFormData: React.Dispatch>; handleSubmit: (e: React.FormEvent) => Promise; setShowPassword: (show: boolean) => void; setShowConfirmPassword: (show: boolean) => void; }; uiState: { showPassword: boolean; showConfirmPassword: boolean; }; mutationState: { isPending: boolean; error: string | null; }; } const USER_ROLES = [ { icon: Car, title: 'Driver', description: 'Race, track stats, join teams', color: 'primary-blue', }, { icon: Trophy, title: 'League Admin', description: 'Organize leagues and events', color: 'performance-green', }, { icon: Users, title: 'Team Manager', description: 'Manage team and drivers', color: 'purple-400', }, ]; const FEATURES = [ 'Track your racing statistics and progress', 'Join or create competitive leagues', 'Build or join racing teams', 'Connect your iRacing account', 'Compete in organized events', 'Access detailed performance analytics', ]; export function SignupTemplate({ viewData, formActions, uiState, mutationState }: SignupTemplateProps) { const passwordStrength = checkPasswordStrength(viewData.formState.fields.password.value); const passwordRequirements = [ { met: viewData.formState.fields.password.value.length >= 8, label: 'At least 8 characters' }, { met: /[a-z]/.test(viewData.formState.fields.password.value) && /[A-Z]/.test(viewData.formState.fields.password.value), label: 'Upper and lowercase letters' }, { met: /\d/.test(viewData.formState.fields.password.value), label: 'At least one number' }, { met: /[^a-zA-Z\d]/.test(viewData.formState.fields.password.value), label: 'At least one special character' }, ]; return (
{/* Background Pattern */}
{/* Left Side - Info Panel (Hidden on mobile) */}
{/* Logo */}
GridPilot
Start Your Racing Journey

Join thousands of sim racers. One account gives you access to all roles - race as a driver, organize leagues, or manage teams.

{/* Role Cards */}
{USER_ROLES.map((role, index) => (

{role.title}

{role.description}

))}
{/* Features List */}
What you'll get
    {FEATURES.map((feature, index) => (
  • {feature}
  • ))}
{/* Trust Indicators */}
Secure signup
iRacing integration
{/* Right Side - Signup Form */}
{/* Mobile Logo/Header */}
Join GridPilot

Create your account and start racing

{/* Desktop Header */}
Create Account

Get started with your free account

{/* Background accent */}
{/* First Name */}
formActions.setFormData(prev => ({ ...prev, firstName: e.target.value }))} error={!!viewData.formState.fields.firstName.error} errorMessage={viewData.formState.fields.firstName.error} placeholder="John" disabled={mutationState.isPending} className="pl-10" autoComplete="given-name" />
{/* Last Name */}
formActions.setFormData(prev => ({ ...prev, lastName: e.target.value }))} error={!!viewData.formState.fields.lastName.error} errorMessage={viewData.formState.fields.lastName.error} placeholder="Smith" disabled={mutationState.isPending} className="pl-10" autoComplete="family-name" />

Your name will be used as-is and cannot be changed later

{/* Name Immutability Warning */}
Important: Your name cannot be changed after signup. Please ensure it's correct.
{/* Email */}
formActions.setFormData(prev => ({ ...prev, email: e.target.value }))} error={!!viewData.formState.fields.email.error} errorMessage={viewData.formState.fields.email.error} placeholder="you@example.com" disabled={mutationState.isPending} className="pl-10" autoComplete="email" />
{/* Password */}
formActions.setFormData(prev => ({ ...prev, password: e.target.value }))} error={!!viewData.formState.fields.password.error} errorMessage={viewData.formState.fields.password.error} placeholder="••••••••" disabled={mutationState.isPending} className="pl-10 pr-10" autoComplete="new-password" />
{/* Password Strength */} {viewData.formState.fields.password.value && (
{passwordStrength.label}
{passwordRequirements.map((req, index) => (
{req.met ? ( ) : ( )} {req.label}
))}
)}
{/* Confirm Password */}
formActions.setFormData(prev => ({ ...prev, confirmPassword: e.target.value }))} error={!!viewData.formState.fields.confirmPassword.error} errorMessage={viewData.formState.fields.confirmPassword.error} placeholder="••••••••" disabled={mutationState.isPending} className="pl-10 pr-10" autoComplete="new-password" />
{viewData.formState.fields.confirmPassword.value && viewData.formState.fields.password.value === viewData.formState.fields.confirmPassword.value && (

Passwords match

)}
{/* Submit Button */}
{/* Divider */}
or continue with
{/* Login Link */}

Already have an account?{' '} Sign in

{/* Footer */}

By creating an account, you agree to our{' '} Terms of Service {' '}and{' '} Privacy Policy

{/* Mobile Role Info */}

One account for all roles

{USER_ROLES.map((role) => (
{role.title}
))}
); }