import { useRef, ChangeEvent } from 'react'; import { Camera, Upload, Loader2, Sparkles, Palette, Check, User } from 'lucide-react'; import Button from '@/components/ui/Button'; import Heading from '@/components/ui/Heading'; export type RacingSuitColor = | 'red' | 'blue' | 'green' | 'yellow' | 'orange' | 'purple' | 'black' | 'white' | 'pink' | 'cyan'; export interface AvatarInfo { facePhoto: string | null; suitColor: RacingSuitColor; generatedAvatars: string[]; selectedAvatarIndex: number | null; isGenerating: boolean; isValidating: boolean; } interface FormErrors { [key: string]: string | undefined; } interface AvatarStepProps { avatarInfo: AvatarInfo; setAvatarInfo: (info: AvatarInfo) => void; errors: FormErrors; setErrors: (errors: FormErrors) => void; onGenerateAvatars: () => void; } const SUIT_COLORS: { value: RacingSuitColor; label: string; hex: string }[] = [ { value: 'red', label: 'Racing Red', hex: '#EF4444' }, { value: 'blue', label: 'Motorsport Blue', hex: '#3B82F6' }, { value: 'green', label: 'Racing Green', hex: '#22C55E' }, { value: 'yellow', label: 'Championship Yellow', hex: '#EAB308' }, { value: 'orange', label: 'Papaya Orange', hex: '#F97316' }, { value: 'purple', label: 'Royal Purple', hex: '#A855F7' }, { value: 'black', label: 'Stealth Black', hex: '#1F2937' }, { value: 'white', label: 'Clean White', hex: '#F9FAFB' }, { value: 'pink', label: 'Hot Pink', hex: '#EC4899' }, { value: 'cyan', label: 'Electric Cyan', hex: '#06B6D4' }, ]; export function AvatarStep({ avatarInfo, setAvatarInfo, errors, setErrors, onGenerateAvatars }: AvatarStepProps) { const fileInputRef = useRef(null); const handleFileSelect = async (e: ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; // Validate file type if (!file.type.startsWith('image/')) { setErrors({ ...errors, facePhoto: 'Please upload an image file' }); return; } // Validate file size (max 5MB) if (file.size > 5 * 1024 * 1024) { setErrors({ ...errors, facePhoto: 'Image must be less than 5MB' }); return; } // Convert to base64 const reader = new FileReader(); reader.onload = async (event) => { const base64 = event.target?.result as string; setAvatarInfo({ ...avatarInfo, facePhoto: base64, generatedAvatars: [], selectedAvatarIndex: null, }); const newErrors = { ...errors }; delete newErrors.facePhoto; setErrors(newErrors); }; reader.readAsDataURL(file); }; return ( // eslint-disable-next-line gridpilot-rules/no-raw-html-in-app
{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
Create Your Racing Avatar {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}

Upload a photo and we will generate a unique racing avatar for you

{/* Photo Upload */} {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */} {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
{/* Upload Area */} {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
fileInputRef.current?.click()} className={`relative flex-1 flex flex-col items-center justify-center p-6 rounded-xl border-2 border-dashed cursor-pointer transition-all ${ avatarInfo.facePhoto ? 'border-performance-green bg-performance-green/5' : errors.facePhoto ? 'border-red-500 bg-red-500/5' : 'border-charcoal-outline hover:border-primary-blue hover:bg-primary-blue/5' }`} > {avatarInfo.isValidating ? ( <> {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}

Validating photo...

) : avatarInfo.facePhoto ? ( <> {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
{/* eslint-disable-next-line @next/next/no-img-element */} Your photo
{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}

Photo uploaded

{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}

Click to change

) : ( <> {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}

Drop your photo here or click to upload

{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}

JPEG or PNG, max 5MB

)}
{/* Preview area */} {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
{(() => { const selectedAvatarUrl = avatarInfo.selectedAvatarIndex !== null ? avatarInfo.generatedAvatars[avatarInfo.selectedAvatarIndex] : undefined; if (!selectedAvatarUrl) { return ; } return ( <> {/* eslint-disable-next-line @next/next/no-img-element */} Selected avatar ); })()}
{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}

Your avatar

{errors.facePhoto && (

{errors.facePhoto}

)}
{/* Suit Color Selection */} {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */} {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
{SUIT_COLORS.map((color) => ( ))}
{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}

Selected: {SUIT_COLORS.find(c => c.value === avatarInfo.suitColor)?.label}

{/* Generate Button */} {avatarInfo.facePhoto && !errors.facePhoto && (
)} {/* Generated Avatars */} {avatarInfo.generatedAvatars.length > 0 && (
{/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */} {/* eslint-disable-next-line gridpilot-rules/no-raw-html-in-app */}
{avatarInfo.generatedAvatars.map((url, index) => ( ))}
{errors.avatar && (

{errors.avatar}

)}
)}
); }