From f21f9728259336ee59c662cb8f7089a6e9e74724 Mon Sep 17 00:00:00 2001 From: Daniel Luiz Alves Date: Tue, 9 Sep 2025 09:40:08 -0300 Subject: [PATCH] feat: implement dynamic upload timeout based on file size across components - Added a calculateUploadTimeout function to determine upload timeout based on file size in FileUploadSection, GlobalDropZone, and UploadFileModal components. - Updated axios upload requests to use the calculated timeout, improving upload handling for larger files. --- .../components/file-upload-section.tsx | 16 ++++++++++++++++ .../components/general/global-drop-zone.tsx | 19 ++++++++++++++++++- .../components/modals/upload-file-modal.tsx | 15 ++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/(shares)/r/[alias]/components/file-upload-section.tsx b/apps/web/src/app/(shares)/r/[alias]/components/file-upload-section.tsx index 31622a6..c44998f 100644 --- a/apps/web/src/app/(shares)/r/[alias]/components/file-upload-section.tsx +++ b/apps/web/src/app/(shares)/r/[alias]/components/file-upload-section.tsx @@ -150,6 +150,18 @@ export function FileUploadSection({ reverseShare, password, alias, onUploadSucce return fileName.split(".").pop() || ""; }; + const calculateUploadTimeout = (fileSize: number): number => { + const baseTimeout = 300000; + const fileSizeMB = fileSize / (1024 * 1024); + if (fileSizeMB > 500) { + const extraMB = fileSizeMB - 500; + const extraMinutes = Math.ceil(extraMB / 100); + return baseTimeout + extraMinutes * 60000; + } + + return baseTimeout; + }; + const uploadFileToStorage = async ( file: File, presignedUrl: string, @@ -172,10 +184,14 @@ export function FileUploadSection({ reverseShare, password, alias, onUploadSucce throw new Error(result.error || "Chunked upload failed"); } } else { + const uploadTimeout = calculateUploadTimeout(file.size); await axios.put(presignedUrl, file, { headers: { "Content-Type": file.type, }, + timeout: uploadTimeout, + maxContentLength: Infinity, + maxBodyLength: Infinity, onUploadProgress: (progressEvent) => { if (onProgress && progressEvent.total) { const progress = (progressEvent.loaded / progressEvent.total) * 100; diff --git a/apps/web/src/components/general/global-drop-zone.tsx b/apps/web/src/components/general/global-drop-zone.tsx index 3b40712..7c5008a 100644 --- a/apps/web/src/components/general/global-drop-zone.tsx +++ b/apps/web/src/components/general/global-drop-zone.tsx @@ -64,6 +64,18 @@ export function GlobalDropZone({ onSuccess, children, currentFolderId }: GlobalD [generateFileId] ); + const calculateUploadTimeout = useCallback((fileSize: number): number => { + const baseTimeout = 300000; + const fileSizeMB = fileSize / (1024 * 1024); + if (fileSizeMB > 500) { + const extraMB = fileSizeMB - 500; + const extraMinutes = Math.ceil(extraMB / 100); + return baseTimeout + extraMinutes * 60000; + } + + return baseTimeout; + }, []); + const handleDragOver = useCallback((event: DragEvent) => { event.preventDefault(); event.stopPropagation(); @@ -158,11 +170,16 @@ export function GlobalDropZone({ onSuccess, children, currentFolderId }: GlobalD folderId: currentFolderId, }); } else { + const uploadTimeout = calculateUploadTimeout(file.size); + await axios.put(url, file, { headers: { "Content-Type": file.type, }, signal: abortController.signal, + timeout: uploadTimeout, // Dynamic timeout based on file size + maxContentLength: Infinity, + maxBodyLength: Infinity, onUploadProgress: (progressEvent: any) => { const progress = (progressEvent.loaded / (progressEvent.total || file.size)) * 100; setFileUploads((prev) => prev.map((u) => (u.id === id ? { ...u, progress: Math.round(progress) } : u))); @@ -203,7 +220,7 @@ export function GlobalDropZone({ onSuccess, children, currentFolderId }: GlobalD ); } }, - [t, isS3Enabled, currentFolderId] + [t, isS3Enabled, currentFolderId, calculateUploadTimeout] ); const handleDrop = useCallback( diff --git a/apps/web/src/components/modals/upload-file-modal.tsx b/apps/web/src/components/modals/upload-file-modal.tsx index dde26e4..74eb843 100644 --- a/apps/web/src/components/modals/upload-file-modal.tsx +++ b/apps/web/src/components/modals/upload-file-modal.tsx @@ -231,6 +231,18 @@ export function UploadFileModal({ isOpen, onClose, onSuccess, currentFolderId }: ); }; + const calculateUploadTimeout = (fileSize: number): number => { + const baseTimeout = 300000; + const fileSizeMB = fileSize / (1024 * 1024); + if (fileSizeMB > 500) { + const extraMB = fileSizeMB - 500; + const extraMinutes = Math.ceil(extraMB / 100); + return baseTimeout + extraMinutes * 60000; + } + + return baseTimeout; + }; + const uploadFile = async (fileUpload: FileUpload) => { const { file, id } = fileUpload; @@ -312,12 +324,13 @@ export function UploadFileModal({ isOpen, onClose, onSuccess, currentFolderId }: folderId: currentFolderId, }); } else { + const uploadTimeout = calculateUploadTimeout(file.size); await axios.put(url, file, { headers: { "Content-Type": file.type, }, signal: abortController.signal, - timeout: 300000, // 5 minutes timeout for direct uploads + timeout: uploadTimeout, maxContentLength: Infinity, maxBodyLength: Infinity, onUploadProgress: (progressEvent) => {