import * as XLSX from 'xlsx';
|
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
export function useExcelParse({ batchSize = 10, processBatch, params }) {
|
const importIdRef = useRef(0);
|
const [importer, setImporter] = useState({ state: 'idle' });
|
|
const reset = useCallback(() => {
|
setImporter({ state: 'idle' });
|
importIdRef.current += 1;
|
}, []);
|
|
const parseExcel = useCallback(async (file) => {
|
if (!file) return;
|
setImporter({ state: 'parsing' });
|
|
const importId = importIdRef.current;
|
|
try {
|
const buf = await file.arrayBuffer();
|
const wb = XLSX.read(buf, { type: 'array' });
|
const sheet = wb.SheetNames[0];
|
const rows = XLSX.utils.sheet_to_json(wb.Sheets[sheet], { defval: '' });
|
|
setImporter({
|
state: 'running',
|
rowCount: rows.length,
|
importCount: 0,
|
errorCount: 0,
|
remainingTime: null,
|
});
|
|
let totalTime = 0;
|
for (let i = 0; i < rows.length; i += batchSize) {
|
if (importIdRef.current !== importId) return;
|
|
const batch = rows.slice(i, i + batchSize);
|
try {
|
const start = Date.now();
|
await processBatch(batch, params);
|
totalTime += Date.now() - start;
|
|
const mean = totalTime / (i + batch.length);
|
setImporter((prev) =>
|
prev.state === 'running'
|
? {
|
...prev,
|
importCount: prev.importCount + batch.length,
|
remainingTime: mean * (rows.length - (prev.importCount + batch.length)),
|
}
|
: prev
|
);
|
} catch (err) {
|
setImporter((prev) =>
|
prev.state === 'running'
|
? {
|
...prev,
|
errorCount: prev.errorCount + batch.length,
|
errorMsg: prev.errorMsg
|
? `${prev.errorMsg}\n${err?.message || String(err)}`
|
: (err?.message || String(err)),
|
}
|
: prev
|
);
|
}
|
}
|
|
setImporter((prev) =>
|
prev.state === 'running' ? { ...prev, state: 'complete', remainingTime: null } : prev
|
);
|
} catch (error) {
|
setImporter({ state: 'error', error });
|
}
|
}, [batchSize, processBatch, params]);
|
|
return useMemo(() => ({ importer, parseExcel, reset }), [importer, parseExcel, reset]);
|
}
|