import { motion } from "framer-motion"; import { FileSpreadsheet, Loader2, X } from "lucide-react"; import { humanDateTime } from "../lib/metrics"; import { MODAL_TRANSITION } from "../lib/motion"; import { MiniMetric } from "./MetricTiles"; import { Modal } from "./Modal"; import type { ImportPreview, ImportPreviewRow, ImportProgress } from "../types"; type ImportPreviewModalProps = { busy: boolean; preview: ImportPreview | null; importProgress: ImportProgress | null; onClose: () => void; onConfirm: () => void; }; export function ImportPreviewModal({ busy, preview, importProgress, onClose, onConfirm, }: ImportPreviewModalProps) { const validRows = preview?.rows.filter((row) => row.entry && !row.errors.length && !row.duplicate) ?? []; const invalidRows = preview?.rows.filter((row) => row.errors.length) ?? []; const duplicateRows = preview?.rows.filter((row) => row.duplicate) ?? []; return ( {preview && (

{preview.fileName.toLowerCase().endsWith(".json") ? "JSON import" : "Excel import"}

Preview rows

{preview.fileName}

{preview.rows.map((row) => ( ))}
Row Status Date Flavour Size Cans Message
{row.rowNumber} 0} duplicate={row.duplicate} /> {row.entry ? humanDateTime(row.entry.dateTime) : "-"} {row.entry?.flavour ?? "-"} {row.entry ? `${row.entry.sizeMl}ml` : "-"} {row.entry?.cans ?? "-"} {rowMessage(row)}
{preview.rows.map((row) => (
Row {row.rowNumber} 0} duplicate={row.duplicate} />

{row.entry?.flavour ?? "No entry parsed"}

{row.entry ? (

{humanDateTime(row.entry.dateTime)} · {row.entry.sizeMl}ml · {row.entry.cans} can{row.entry.cans === 1 ? "" : "s"}

) : null}

{rowMessage(row)}

))}
{busy && importProgress ? (

Importing {importProgress.done} of {importProgress.total}…

) : null}
)}
); } function ImportStatusBadge({ invalid, duplicate }: { invalid: boolean; duplicate: boolean }) { return ( {invalid ? "Invalid" : duplicate ? "Duplicate" : "Ready"} ); } function rowMessage(row: ImportPreviewRow) { return row.errors.join(" ") || row.duplicateReason || "Looks good."; }