/** * @ai-summary Import dialog component * @ai-context Multi-step dialog: upload -> preview -> confirm -> progress -> results */ import React, { useState, useEffect } from 'react'; import { useImportPreview, useImportUserData } from '../hooks/useImportUserData'; import { ImportPreview, ImportResult } from '../types/import.types'; interface ImportDialogProps { isOpen: boolean; onClose: () => void; file: File | null; } type ImportStep = 'upload' | 'preview' | 'confirm' | 'progress' | 'results'; export const ImportDialog: React.FC = ({ isOpen, onClose, file, }) => { const [step, setStep] = useState('upload'); const [preview, setPreview] = useState(null); const [mode, setMode] = useState<'merge' | 'replace'>('merge'); const [result, setResult] = useState(null); const previewMutation = useImportPreview(); const importMutation = useImportUserData(); const handleGeneratePreview = async () => { if (!file) return; setStep('preview'); try { const previewData = await previewMutation.mutateAsync(file); setPreview(previewData); setStep('confirm'); } catch { // Error handled by mutation hook setStep('upload'); } }; const handleConfirmImport = async () => { if (!file) return; setStep('progress'); try { const importResult = await importMutation.mutateAsync({ file, mode }); setResult(importResult); setStep('results'); } catch { // Error handled by mutation hook setStep('confirm'); } }; // Reset state when dialog opens useEffect(() => { if (isOpen && file) { setStep('upload'); setPreview(null); setMode('merge'); setResult(null); // Automatically start preview generation handleGeneratePreview(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpen, file]); const handleClose = () => { setStep('upload'); setPreview(null); setMode('merge'); setResult(null); onClose(); }; if (!isOpen) return null; const formatBytes = (bytes: number): string => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]; }; return (

Import Data

{/* Step 1: Upload */} {step === 'upload' && file && (

File selected: {file.name} ({formatBytes(file.size)})

)} {/* Step 2: Preview (Loading) */} {step === 'preview' && (

Analyzing import file...

)} {/* Step 3: Confirm */} {step === 'confirm' && preview && (

Import Summary

Vehicles: {preview.manifest.contents.vehicles.count}
Fuel Logs: {preview.manifest.contents.fuelLogs.count}
Maintenance Records: {preview.manifest.contents.maintenanceRecords.count}
Maintenance Schedules: {preview.manifest.contents.maintenanceSchedules.count}
Documents: {preview.manifest.contents.documents.count}
{preview.conflicts.vehicles > 0 && (

Conflicts detected: {preview.conflicts.vehicles}{' '} vehicle(s) with matching VINs already exist.

)} {preview.manifest.warnings.length > 0 && (

Warnings:

    {preview.manifest.warnings.map((warning, idx) => (
  • {warning}
  • ))}
)}

Import Mode

)} {/* Step 4: Progress */} {step === 'progress' && (

Importing data... This may take a few minutes.

)} {/* Step 5: Results */} {step === 'results' && result && (

{result.success ? 'Import completed successfully!' : 'Import completed with errors'}

Import Summary

Mode: {result.mode}
Imported: {result.summary.imported}
Updated: {result.summary.updated}
Skipped: {result.summary.skipped}
{result.summary.errors.length > 0 && (

Errors:

    {result.summary.errors.map((error, idx) => (
  • {error}
  • ))}
)} {result.warnings.length > 0 && (

Warnings:

    {result.warnings.map((warning, idx) => (
  • {warning}
  • ))}
)}
)}
); };