Skip to content

Instantly share code, notes, and snippets.

@zach2825
Created August 2, 2021 14:29
Show Gist options
  • Save zach2825/faae1018c77721790c98ef805fed24dc to your computer and use it in GitHub Desktop.
Save zach2825/faae1018c77721790c98ef805fed24dc to your computer and use it in GitHub Desktop.
React hook for uploading files to an s3 presigned url. this required the useService hook
import { useState } from 'react';
import useService, { DELETE, PUT } from 'hooks/useService';
const useFileUploadHook = () => {
const [{}, fireApi] = useService();
const [filesUploaded, setFilesUploaded] = useState(1);
const [uploading, setUploading] = useState(false);
const [overallProgress, setOverallProgress] = useState(0);
const mashToS3 = async ({ file, goalPercentage, url }) => {
const form = new FormData();
form.append('file', file);
try {
return await fireApi({
baseURL: undefined,
url,
method: PUT,
headers: {
'Content-Type': file.type,
},
persist_changes: false,
onUploadProgress: data => onUploadProgress(data, goalPercentage),
params: file,
});
} catch (e) {
console.log({ e });
} finally {
setUploading(false);
}
};
const deleteFile = ({ module, module_id, file_id, image_type }) => {
let url = `${module}/${module_id}/images/${file_id}`;
return fireApi({
persist_changes: false,
method: DELETE,
url,
params: {
image_type,
},
});
};
const onUploadProgress = (data, _goalPercentage, { debug = false } = {}) => {
const { loaded, total } = data;
const currentPercentage = Math.floor((loaded / total) * 100);
const new_percentage_progress = (currentPercentage * filesUploaded) / _goalPercentage * 100;
if (new_percentage_progress > currentPercentage) {
setOverallProgress(new_percentage_progress);
}
debug && console.log({
filesUploaded,
new_percentage_progress,
newProgress: currentPercentage,
_goalPercentage,
loaded,
total,
data,
});
};
const uploadFile = async ({ record_id, file }) => {
setUploading(true);
setFilesUploaded(1);
setOverallProgress(0);
const { url } = await fireApi({
url: `file_url/${record_id}/create`,
persist_changes: false,
params: {
file_name: file.name,
file_type: file.type,
},
});
return mashToS3({
file,
url,
goalPercentage: 100,
});
};
const uploadImages = async ({ file_type = 'images', record_id, files = [] }) => {
const filesArray = Array.from(files);
setUploading(true);
setFilesUploaded(filesArray.length);
const apiUrl = `/${record_id}/${file_type}/create`;
const goalPercentage = 100 * filesArray.length;
const filePromises = Array.from(filesArray).map(async file => {
// get the presigned url
const { url } = await fireApi({
url: apiUrl,
params: {
file_name: file.name,
file_type: file.type,
},
persist_changes: false,
});
// mash the file into s3 using the presigned url
return mashToS3({
goalPercentage,
file,
url,
});
});
// await all uploads
try {
await Promise.all(filePromises);
return filePromises;
} catch (e) {
return [];
} finally {
setUploading(false);
}
};
return [
{ uploading, progress: overallProgress },
{ uploadFile, uploadImages, deleteFile },
];
};
export default useFileUploadHook;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment