Skip to content

Instantly share code, notes, and snippets.

@fResult
Last active October 3, 2020 11:53
Show Gist options
  • Save fResult/5ea5bafaa3226b4ec4532efb1a362ab4 to your computer and use it in GitHub Desktop.
Save fResult/5ea5bafaa3226b4ec4532efb1a362ab4 to your computer and use it in GitHub Desktop.
FileUpload page
import React from 'react';
import { CancelToken } from 'axios'
const FileUpload = () => {
const [fileList, setFileList] = useState([]) // List of File instance
const [sizeAmount, setSizeAmount] = useState('') // sum files size (such as '444.44 MB' or '2.15 GB')
const [uploadedSize, setUploadedSize] = useState('') // sum uploaded (such as '444.44 MB' or '2.15 GB')
const [fileCount, setFileCount] = useState(0)
const [progress, setProgress] = useState(0) // sum uploaded (percent)
const [prevLoaded, setPrevLoaded] = useState(0) // previous progressEvent.loaded
const [allLoaded, setAllLoaded] = useState(0) // sum all files uploaded
const [allBytes, setAllBytes] = useState(0) // sum all files byte
const cancelUploadRef = useRef()
const { execute: uploadFiles, value, isLoading, error } = useAsync(
API.uploadFiles,
false
)
useEffect(() => {
if (fileList.length > 0) {
const calcFileBytes = (amount, file) => {
return amount + file.size
}
const bytes = Array.prototype.reduce.call(fileList, calcFileBytes, 0)
setAllBytes(bytes)
setSizeAmount(fileSize(bytes, { fixed: 2, spacer: ' ' }).human('jedec'))
setFileCount(fileList.length)
}
}, [fileList, progress, error, value, setAllBytes])
const handleBeforeUpload = (file) => {
fileList.push(file)
setFileList([...fileList])
return false
}
const handleRemoveFile = (selectedFile) => {
const idx = fileList.indexOf(selectedFile)
const newFileList = fileList.slice()
newFileList.splice(idx, 1)
setFileList(newFileList)
}
const asyncForEach = async (array, callback) => {
for (let idx = 0; idx < array.length; idx++) {
await callback(array[idx], idx, array)
}
}
const handleUploadFiles = async () => {
const formData = new FormData()
const axiosConfig = {
headers: { 'content-type': 'multipart/form-data' },
onUploadProgress: (progressEvent) => {
const percent = Math.round((allLoaded / allBytes) * 100)
setProgress(percent)
percent === 100 && setTimeout(() => setProgress(0), 1000)
if (progressEvent.loaded <= progressEvent.total) {
const growLoaded = progressEvent.loaded - prevLoaded
setPrevLoaded(progressEvent.loaded)
const newAllLoaded = allLoaded + growLoaded
setAllLoaded(newAllLoaded)
const uploadedSize = fileSize(newAllLoaded, { fixed: 2, spacer: ' ' }).human('jedec')
setUploadedSize(uploadedSize)
}
},
cancelToken: new CancelToken((cancel) => {
cancelUploadRef.current = cancel
})
}
await asyncForEach(
Array.prototype.map.call(fileList, (f) => f),
async (file, idx) => {
if (!formData.has('uuid')) {
formData.set('uuid', uuid())
} else {
const uuid = formData.get('uuid')
formData.set('uuid', uuid)
}
formData.set('import_file', file, file.name)
await uploadFiles(formData, axiosConfig)
}
)
}
return (
<div>
{/*Remove for abbrev */}
{progress > 0 ? (
fileList.length > 0 ? (
// AntDesign List - display fileList before start upload
<FileList
{...{
fileList,
sizeAmount,
fileCount,
onRemoveFile: handleRemoveFile
}}
/>
) : (
// AntDesign Upload Dragger - for select multiple files before upload
<UploadInput
{...{
fileList,
onBeforeUpload: handleBeforeUpload
}}
/>
)
) : (
// AntDesign Progress
<UploadProgress
{...{ progress, fileCount, uploadedSize, sizeAmount, willCancel }}
/>
)}
<ActionButtons>
{/** such as...
* Start Upload,
* Stop Upload,
* Confirm Stop
* Cancel Stop
* (dynamic in various above components)
**/}
</ActionButtons>
</div>
);
};
export default FileUpload;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment