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]); 
 |  } 
 |  
  |