From 92043b065fd4c29a526774bdfc4a90a6a644a5f4 Mon Sep 17 00:00:00 2001 From: arunjaindev Date: Fri, 26 Jul 2024 12:34:08 +0530 Subject: [PATCH] feat: add support for progressing in download --- src/Shared/Hooks/UseDownload/UseDownload.tsx | 35 +++++++++++++++++--- src/Shared/Hooks/UseDownload/types.tsx | 1 + 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/Shared/Hooks/UseDownload/UseDownload.tsx b/src/Shared/Hooks/UseDownload/UseDownload.tsx index 2cd6e61fc..e321f87e8 100644 --- a/src/Shared/Hooks/UseDownload/UseDownload.tsx +++ b/src/Shared/Hooks/UseDownload/UseDownload.tsx @@ -10,13 +10,36 @@ import { HandleDownloadProps } from './types' const useDownload = () => { const [isDownloading, setIsDownloading] = useState(false) + const [progress, setProgress] = useState(null) + + const getChunksDataFromResponse = async (response: Response) => { + const contentLength = +response.headers.get('Content-Length') + if (!contentLength) { + throw new Error('Invalid content length') + } + const reader = response.body.getReader() + const chunks = [] + let receivedLength = 0 + + // eslint-disable-next-line no-constant-condition + while (true) { + // eslint-disable-next-line no-await-in-loop + const { done, value } = await reader.read() + if (done) break + + chunks.push(value) + receivedLength += value.length + setProgress(receivedLength / contentLength) + } + } /** * @param downloadUrl - API url for downloading file - * @param filterType - Show toast 'Preparing file for download' + * @param showFilePreparingToast - Show toast 'Preparing file for download' * @param fileName - fileName of the downloaded file * @param showSuccessfulToast - show toast on successful download * @param downloadSuccessToastContent - Content to show in toast on successful download + * @param showProgress - show download progress, default false, returns null if false, else returns percentage downloaded */ const handleDownload = async ({ downloadUrl, @@ -24,6 +47,7 @@ const useDownload = () => { fileName, showSuccessfulToast = true, downloadSuccessToastContent = 'Downloaded Successfully', + showProgress = false, }: HandleDownloadProps): Promise => { setIsDownloading(true) if (showFilePreparingToast) { @@ -37,10 +61,12 @@ const useDownload = () => { try { const response = await getDownloadResponse(downloadUrl) if (response.status === API_STATUS_CODES.OK) { - const data = await (response as any).blob() + const data = showProgress ? getChunksDataFromResponse(response) : await (response as any).blob() + + const blob = showProgress ? new Blob(data) : data // Create a new URL object - const blobUrl = URL.createObjectURL(data) + const blobUrl = URL.createObjectURL(blob) // Create a link element const a = document.createElement('a') @@ -78,7 +104,8 @@ const useDownload = () => { return null } - return { handleDownload, isDownloading } + // progress will be null if showProgress is false + return { handleDownload, isDownloading, progress } } export default useDownload diff --git a/src/Shared/Hooks/UseDownload/types.tsx b/src/Shared/Hooks/UseDownload/types.tsx index b4271a252..ead0f8db0 100644 --- a/src/Shared/Hooks/UseDownload/types.tsx +++ b/src/Shared/Hooks/UseDownload/types.tsx @@ -4,4 +4,5 @@ export interface HandleDownloadProps { fileName?: string showSuccessfulToast?: boolean downloadSuccessToastContent?: string + showProgress?: boolean }