import React, { useEffect, useState } from 'react'; import Papa from 'papaparse'; import { BaseControl, DropZone, FormFileUpload } from '@wordpress/components'; import { toast } from 'react-toastify'; import DownloadIcon from '@mui/icons-material/Download'; import UploadIcon from '@mui/icons-material/Upload'; import { Button, FormControl, FormHelperText, FormLabel, Stack, Typography, } from '@mui/material'; import { Spinner } from '../../../../resources/js/Shared/Spinner'; interface Props { handleUpload: (file: File) => void; isBusy: boolean; isDisabled: boolean; templateHeaders?: string[]; templateURL?: string; } export const BatchUploader = ({ handleUpload, isBusy, isDisabled, templateHeaders, templateURL, }: Props) => { const figureStyle = { padding: 0, margin: '0 0 1rem 0', }; const tableStyle = { border: 0, }; const headerStyle = { position: 'sticky', top: 0, background: 'white', }; const wrapStyle = { maxHeight: '65vh', overflow: 'auto', border: '1px solid #c3c4c7', }; const [data, setData] = useState(); const [error, setError] = useState(); const [file, setFile] = useState(); const [hasParsed, setHasParsed] = useState(false); const [limit, setLimit] = useState(10); const [headers, setHeaders] = useState | null>(); const [results, setResults] = useState(); const canBeParsed = (name: string) => { return name.endsWith('csv') || name.endsWith('txt'); }; const checkHeaders = (fields: string[]) => { if (hasEmptyHeaders(fields)) { setError( `Your spreadsheet is missing headers. Please edit your file or upload another one.` ); } else if (hasBadCharacters(fields)) { setError( `Your spreadsheet headers contain uppercase characters and/or spaces. Please edit your file or upload another one.` ); } else { setHeaders(fields.filter((field) => field)); } }; const handleChange = (e) => { setError(null); setFile(e.target.files[0]); setData(null); setHeaders(null); }; const handleCSVDownload = () => { const csv = Papa.unparse({ fields: templateHeaders }); const csvData = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const csvURL = window.URL.createObjectURL(csvData); const tempLink = document.createElement('a'); tempLink.href = csvURL; tempLink.setAttribute('download', 'template.csv'); tempLink.click(); }; const handleDrop = (files) => { setError(null); setFile(files[0]); setData(null); setHeaders(null); }; const handleShowAll = () => { setLimit(limit + 10); }; const hasBadCharacters = (arr: string[]): boolean => { return arr.some((value) => value.match(/[A-Z|\s]/g)); }; const hasEmptyHeaders = (arr: string[]) => { /* Flag headers containing empty strings vs. empty strings on end. */ if (arr.some(isEmpty)) { return arr.slice(arr.findIndex(isEmpty)).join('').length ? true : false; } }; const isEmpty = (value: string) => value === ''; const parseFile = () => { setHasParsed(false); Papa.parse(file, { dynamicTyping: true, header: true, skipEmptyLines: true, complete: (parsedResults) => { setResults(parsedResults); setHasParsed(true); }, }); }; useEffect(() => { if (file && canBeParsed(file.name)) { parseFile(); } }, [file]); useEffect(() => { if (results) { setData(results.data); checkHeaders(results.meta.fields); } }, [results]); useEffect(() => { toast.error(error, { autoClose: false, }); }, [error]); return ( <> Please upload or drop a spreadsheet file in .csv, .ods, .txt, .xls, or .xlsx format. Only text and comma delimited value (CSV) files can be previewed.
( <> {file && ( {`${ file.name } (${ Math.round( (file.size / 1000) * 100 ) / 100 } KB)`} )} {file && ( )} {templateHeaders?.length && ( )} {templateURL && ( )} )} /> { handleDrop(files); }} />
{file && canBeParsed(file.name) && !hasParsed && } {hasParsed && data && headers && ( <>

Showing{' '} {data.length > limit ? limit.toLocaleString() : data.length.toLocaleString()}{' '} {data.length > limit ? ` of ${data.length.toLocaleString()} ` : ''} items parsed from {file.name}

{headers.map((header: string) => ( ))} {data.map((row, index: number) => ( <> {index <= limit && ( {headers.map( ( header: string, i: number ) => ( ) )} )} ))}
{header}
{row[header]}
{data.length > limit && ( )} )} ); };