| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
 | | import * as Papa from 'papaparse'; |  | import { useCallback, useMemo, useRef, useState } from 'react'; |  |   |  | export function usePapaParse({ batchSize = 10, processBatch }) { |  |     const importIdRef = useRef(0); |  |   |  |     const [importer, setImporter] = useState({ |  |         state: 'idle', |  |     }); |  |   |  |     const reset = useCallback(() => { |  |         setImporter({ |  |             state: 'idle', |  |         }); |  |         importIdRef.current += 1; |  |     }, []); |  |   |  |     const parseCsv = useCallback((file) => { |  |         setImporter({ |  |             state: 'parsing', |  |         }); |  |   |  |         const importId = importIdRef.current; |  |         Papa.parse(file, { |  |             header: true, |  |             skipEmptyLines: true, |  |             async complete(results) { |  |                 if (importIdRef.current !== importId) { |  |                     return; |  |                 } |  |   |  |                 setImporter({ |  |                     state: 'running', |  |                     rowCount: results.data.length, |  |                     errorCount: results.errors.length, |  |                     importCount: 0, |  |                     remainingTime: null, |  |                 }); |  |   |  |                 let totalTime = 0; |  |                 for (let i = 0; i < results.data.length; i += batchSize) { |  |                     if (importIdRef.current !== importId) { |  |                         return; |  |                     } |  |   |  |                     const batch = results.data.slice(i, i + batchSize); |  |                     try { |  |                         const start = Date.now(); |  |                         await processBatch(batch); |  |                         totalTime += Date.now() - start; |  |   |  |                         const meanTime = totalTime / (i + batch.length); |  |                         setImporter(previous => { |  |                             if (previous.state === 'running') { |  |                                 const importCount = previous.importCount + batch.length; |  |                                 return { |  |                                     ...previous, |  |                                     importCount, |  |                                     remainingTime: meanTime * (results.data.length - importCount), |  |                                 }; |  |                             } |  |                             return previous; |  |                         }); |  |                     } catch (error) { |  |                         console.error('Failed to import batch', error); |  |                         setImporter(previous => |  |                             previous.state === 'running' |  |                                 ? { |  |                                     ...previous, |  |                                     errorCount: previous.errorCount + batch.length, |  |                                 } |  |                                 : previous |  |                         ); |  |                     } |  |                 } |  |   |  |                 setImporter(previous => |  |                     previous.state === 'running' |  |                         ? { |  |                             ...previous, |  |                             state: 'complete', |  |                             remainingTime: null, |  |                         } |  |                         : previous |  |                 ); |  |             }, |  |             error(error) { |  |                 setImporter({ |  |                     state: 'error', |  |                     error, |  |                 }); |  |             }, |  |             dynamicTyping: true, |  |         }); |  |     }, [batchSize, processBatch]); |  |   |  |     return useMemo(() => ({ importer, parseCsv, reset, }), [importer, parseCsv, reset]); |  | } | 
 |