'use client'; import { useState } from 'react'; import Button from '../ui/Button'; import DataWarning from './DataWarning'; import { Result } from '../../domain/entities/Result'; import { v4 as uuidv4 } from 'uuid'; interface ImportResultsFormProps { raceId: string; onSuccess: (results: Result[]) => void; onError: (error: string) => void; } interface CSVRow { driverId: string; position: number; fastestLap: number; incidents: number; startPosition: number; } export default function ImportResultsForm({ raceId, onSuccess, onError }: ImportResultsFormProps) { const [uploading, setUploading] = useState(false); const [error, setError] = useState(null); const parseCSV = (content: string): CSVRow[] => { const lines = content.trim().split('\n'); if (lines.length < 2) { throw new Error('CSV file is empty or invalid'); } // Parse header const header = lines[0].toLowerCase().split(',').map(h => h.trim()); const requiredFields = ['driverid', 'position', 'fastestlap', 'incidents', 'startposition']; for (const field of requiredFields) { if (!header.includes(field)) { throw new Error(`Missing required field: ${field}`); } } // Parse rows const rows: CSVRow[] = []; for (let i = 1; i < lines.length; i++) { const values = lines[i].split(',').map(v => v.trim()); if (values.length !== header.length) { throw new Error(`Invalid row ${i}: expected ${header.length} columns, got ${values.length}`); } const row: any = {}; header.forEach((field, index) => { row[field] = values[index]; }); // Validate and convert types const driverId = row.driverid; const position = parseInt(row.position, 10); const fastestLap = parseFloat(row.fastestlap); const incidents = parseInt(row.incidents, 10); const startPosition = parseInt(row.startposition, 10); if (!driverId || driverId.length === 0) { throw new Error(`Row ${i}: driverId is required`); } if (isNaN(position) || position < 1) { throw new Error(`Row ${i}: position must be a positive integer`); } if (isNaN(fastestLap) || fastestLap < 0) { throw new Error(`Row ${i}: fastestLap must be a non-negative number`); } if (isNaN(incidents) || incidents < 0) { throw new Error(`Row ${i}: incidents must be a non-negative integer`); } if (isNaN(startPosition) || startPosition < 1) { throw new Error(`Row ${i}: startPosition must be a positive integer`); } rows.push({ driverId, position, fastestLap, incidents, startPosition }); } // Validate no duplicate positions const positions = rows.map(r => r.position); const uniquePositions = new Set(positions); if (positions.length !== uniquePositions.size) { throw new Error('Duplicate positions found in CSV'); } // Validate no duplicate drivers const driverIds = rows.map(r => r.driverId); const uniqueDrivers = new Set(driverIds); if (driverIds.length !== uniqueDrivers.size) { throw new Error('Duplicate driver IDs found in CSV'); } return rows; }; const handleFileChange = async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; setUploading(true); setError(null); try { // Read file const content = await file.text(); // Parse CSV const rows = parseCSV(content); // Create Result entities const results = rows.map(row => Result.create({ id: uuidv4(), raceId, driverId: row.driverId, position: row.position, fastestLap: row.fastestLap, incidents: row.incidents, startPosition: row.startPosition, }) ); onSuccess(results); } catch (err) { const errorMessage = err instanceof Error ? err.message : 'Failed to parse CSV file'; setError(errorMessage); onError(errorMessage); } finally { setUploading(false); // Reset file input event.target.value = ''; } }; return ( <>

CSV format: driverId, position, fastestLap, incidents, startPosition

{error && (
Error: {error}
)} {uploading && (
Parsing CSV and importing results...
)}

CSV Example:

{`driverId,position,fastestLap,incidents,startPosition
550e8400-e29b-41d4-a716-446655440001,1,92.456,0,3
550e8400-e29b-41d4-a716-446655440002,2,92.789,1,1
550e8400-e29b-41d4-a716-446655440003,3,93.012,2,2`}
        
); }