-
Notifications
You must be signed in to change notification settings - Fork 75
/
Copy pathuseMultiFileUpload.js
110 lines (90 loc) · 2.83 KB
/
useMultiFileUpload.js
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
99
100
101
102
103
104
105
106
107
108
109
110
import { useState, useCallback } from 'react';
// interface FileUploadItem {
// data: File;
// id: string;
// status: | 'queued' | 'uploading' | 'success' | 'error';
// message?: string
// }
// interface UseMultiFileUploadOptions {
// maxFileSizeMB?: number;
// onUpload: (file: File) => Promise<any>;
// }
const MEGABYTE_LIMIT = 100;
const mbToBytes = (mb) => mb * 1024 * 1024;
export const useMultiFileUpload = ({ onUpload, maxFileSizeMB = MEGABYTE_LIMIT }) => {
const [isUploading, setIsUploading] = useState('pending');
const [files, setFiles] = useState([]);
// eslint-disable-next-line sonarjs/pseudo-random
const generateFileId = () => Math.random().toString(36).substring(2, 15);
const addFiles = useCallback((newFiles) => {
const fileItems = Array.from(newFiles).map((data) => {
const byteLimit = mbToBytes(maxFileSizeMB);
if (data.size > byteLimit) {
return {
data,
id: generateFileId(),
status: 'error',
message: `Exceeds the ${maxFileSizeMB}MB limit.`,
};
}
return {
data,
id: generateFileId(),
status: 'queued',
message: null,
};
});
setFiles((prevFiles) => [...prevFiles, ...fileItems]);
}, []);
const clearFiles = useCallback(() => setFiles(() => []));
const uploadFile = useCallback(
async (fileItem) => {
try {
// Update the uploading status of the files
setFiles((prevFiles) =>
prevFiles.map((f) =>
f.id === fileItem.id ? { ...f, status: 'uploading' } : f,
),
);
// Perform the upload
await onUpload(fileItem.data);
// Update state on success
// Remove successful upload
setFiles((prevFiles) =>
prevFiles.map((f) =>
f.id === fileItem.id ? { ...f, status: 'success', message: 'Success.' } : f,
),
);
} catch (error) {
// Update state on error
const message = error?.message || `Unable to upload ${fileItem.data.name}`;
setFiles((prevFiles) =>
prevFiles.map((f) =>
f.id === fileItem.id ? { ...f, status: 'error', message } : f,
),
);
}
},
[onUpload],
);
const startUploads = useCallback(async () => {
setIsUploading(() => 'uploading');
const pendingFiles = files.filter((f) => f.status === 'queued');
if (pendingFiles.length === 0) {
return setIsUploading(() => 'complete');
}
await Promise.allSettled(pendingFiles.map((fileItem) => uploadFile(fileItem)));
setIsUploading(() => 'complete');
}, [files]);
const removeFile = useCallback((fileId) => {
setFiles((prevFiles) => prevFiles.filter((f) => f.id !== fileId));
}, []);
return {
files,
addFiles,
clearFiles,
isUploading,
removeFile,
startUploads,
};
};