'use client' import { useState, useCallback } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Upload, FileText, Check } from 'lucide-react' interface CsvImportWizardProps { targetFields: { key: string; label: string; required?: boolean }[] defaultMappings?: Record onImport: (rows: Record[]) => Promise className?: string } function parseCsv(text: string): { headers: string[]; rows: string[][] } { const lines = text.split(/\r?\n/).filter(line => line.trim()) if (lines.length === 0) return { headers: [], rows: [] } const separator = lines[0].includes(';') ? ';' : ',' const headers = lines[0].split(separator).map(h => h.trim().replace(/^"(.*)"$/, '$1')) const rows = lines.slice(1).map(line => line.split(separator).map(cell => cell.trim().replace(/^"(.*)"$/, '$1')) ) return { headers, rows } } export default function CsvImportWizard({ targetFields, defaultMappings, onImport, className, }: CsvImportWizardProps) { const [step, setStep] = useState<1 | 2 | 3>(1) const [headers, setHeaders] = useState([]) const [rows, setRows] = useState([]) const [mappings, setMappings] = useState>({}) const [isImporting, setIsImporting] = useState(false) const [importCount, setImportCount] = useState(0) const [fileName, setFileName] = useState('') const handleFileSelect = useCallback((e: React.ChangeEvent) => { const file = e.target.files?.[0] if (!file) return setFileName(file.name) const reader = new FileReader() reader.onload = (ev) => { const text = ev.target?.result as string const parsed = parseCsv(text) setHeaders(parsed.headers) setRows(parsed.rows) // Auto-map using defaults const autoMappings: Record = {} for (const field of targetFields) { const defaultCsv = defaultMappings?.[field.key] if (defaultCsv && parsed.headers.includes(defaultCsv)) { autoMappings[field.key] = defaultCsv } else { const match = parsed.headers.find( h => h.toLowerCase() === field.key.toLowerCase() || h.toLowerCase() === field.label.toLowerCase() ) if (match) autoMappings[field.key] = match } } setMappings(autoMappings) setStep(2) } reader.readAsText(file) }, [targetFields, defaultMappings]) const handleImport = async () => { setIsImporting(true) try { const mappedRows = rows.map(row => { const obj: Record = {} for (const [fieldKey, csvCol] of Object.entries(mappings)) { const colIdx = headers.indexOf(csvCol) if (colIdx >= 0 && row[colIdx]) { obj[fieldKey] = row[colIdx] } } return obj }).filter(row => Object.keys(row).length > 0) await onImport(mappedRows) setImportCount(mappedRows.length) setStep(3) } finally { setIsImporting(false) } } const reset = () => { setStep(1) setHeaders([]) setRows([]) setMappings({}) setFileName('') setImportCount(0) } const requiredFieldsMapped = targetFields .filter(f => f.required) .every(f => mappings[f.key]) return ( {step === 1 && <> Steg 1: Valj fil} {step === 2 && <> Steg 2: Kolumnmappning} {step === 3 && <> Import klar} {step === 1 && (

Valj en CSV-fil att importera

)} {step === 2 && (

{fileName} - {rows.length} rader hittades. Mappa kolumner:

{targetFields.map(field => (
))}
{rows.length > 0 && (
{headers.map(h => ( {h} ))} {rows.slice(0, 5).map((row, i) => ( {row.map((cell, j) => ( {cell} ))} ))}
)}
)} {step === 3 && (

{importCount} rader importerades

Fran {fileName}

)}
) }