import { Box } from "@chakra-ui/react"; import { useRef } from "react"; import { useAppStore } from "../appstore"; import { parseCSVOrTSV } from "../utils/parsing"; import { api } from "../api"; import { toast, updateToast } from "../components/ui/toaster"; import {PrimaryButton} from "../components/primaryButton"; import {Tooltip} from "../components/tooltip"; import {LuImport} from "react-icons/lu"; export function FileUpload() { const fileInputRef = useRef(null); const { orderList, addAllToOrderList, setUnresolvedSkus, parseMode, setOrderName } = useAppStore(); const handleFileSelect = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; // Validate file type if (!file.name.endsWith('.csv') && !file.name.endsWith('.tsv')) { toast({ type: "error", title: "Invalid file type", description: "Please upload a CSV or TSV file", }); // Reset file input to allow re-selecting a valid file if (fileInputRef.current) { fileInputRef.current.value = ''; } return; } // Track if this is a fresh order (for naming purposes) const isNewOrder = orderList.length === 0; if (orderList.length > 0) { toast({ type: "warning", title: "Clear order list first", }); // Reset file input to allow re-selecting the same file if (fileInputRef.current) { fileInputRef.current.value = ''; } return; } const readToastId = toast({ title: "Reading file...", type: "loading", }); try { const content = await file.text(); const parsedSkuQtyPairs = parseCSVOrTSV(content, parseMode); if (parsedSkuQtyPairs.length === 0) { updateToast(readToastId, { type: "error", title: "Could not parse file", description: "File must contain 2 columns: SKU and Quantity", }); return; } // Check row limit and truncate if needed let rowsToProcess = parsedSkuQtyPairs; updateToast(readToastId, { type: "loading", title: `Resolving ${rowsToProcess.length} SKUs...`, }); const parsedSkus = rowsToProcess.map(p => p.sku); const b2BQOMItems = await api.resolveSkus(parsedSkus); const resolvedItems = b2BQOMItems.map(item => ({ ...item, quantity: rowsToProcess.find(i => i.sku === item.sku)?.qty as number, })); if (resolvedItems.length === 0) { updateToast(readToastId, { type: "warning", title: `None of the SKUs were resolved`, }); return; } if (resolvedItems.length === rowsToProcess.length) { setUnresolvedSkus([]); updateToast(readToastId, { type: "success", title: `All ${resolvedItems.length} SKU(s) resolved successfully`, }); } else { const resolvedSkus = new Set(resolvedItems.map(i => i.sku)); const unresolvedSkus = parsedSkus.filter(key => !resolvedSkus.has(key)); setUnresolvedSkus(unresolvedSkus); updateToast(readToastId, { type: "warning", title: "Some SKUs could not be resolved", description: `${resolvedSkus.size} resolved, ${unresolvedSkus.length} not found`, }); } addAllToOrderList(resolvedItems); // Set order name from filename if this is a new order if (isNewOrder && resolvedItems.length > 0) { const fileNameWithoutExtension = file.name.replace(/\.(csv|tsv)$/i, ''); setOrderName(fileNameWithoutExtension); } } catch (err) { console.error(err); updateToast(readToastId, { type: "error", title: "Failed to process file", description: err instanceof Error ? err.message : "Please try again", }); } finally { // Reset file input if (fileInputRef.current) { fileInputRef.current.value = ''; } } }; const handleButtonClick = () => { fileInputRef.current?.click(); }; return ( Import ); }