@@ -45,18 +45,33 @@ export const useFileUpload = ({ onUploadComplete }: UseFileUploadOptions = {}):
4545 const [ error , setError ] = useState < string | null > ( null ) ;
4646 // Use a ref to track if upload should be canceled
4747 const cancelRef = useRef < boolean > ( false ) ;
48+ // Use a ref to hold the AbortController
49+ const abortControllerRef = useRef < AbortController | null > ( null ) ;
4850
4951 const reset = useCallback ( ( ) => {
5052 setFile ( null ) ;
5153 setStatus ( UploadStatus . IDLE ) ;
5254 setProgress ( 0 ) ;
5355 setError ( null ) ;
5456 cancelRef . current = false ;
57+
58+ // Abort any pending requests from previous uploads
59+ if ( abortControllerRef . current ) {
60+ abortControllerRef . current . abort ( ) ;
61+ abortControllerRef . current = null ;
62+ }
5563 } , [ ] ) ;
5664
5765 const cancelUpload = useCallback ( ( ) => {
66+ cancelRef . current = true ;
67+
68+ // Abort the ongoing request if there's one
69+ if ( abortControllerRef . current ) {
70+ abortControllerRef . current . abort ( ) ;
71+ abortControllerRef . current = null ;
72+ }
73+
5874 if ( status === UploadStatus . UPLOADING || status === UploadStatus . REQUESTING_PERMISSION ) {
59- cancelRef . current = true ;
6075 setStatus ( UploadStatus . IDLE ) ;
6176 setProgress ( 0 ) ;
6277 } else {
@@ -89,6 +104,20 @@ export const useFileUpload = ({ onUploadComplete }: UseFileUploadOptions = {}):
89104 setError ( null ) ;
90105 } , [ t ] ) ;
91106
107+ // Extract the progress callback outside of uploadFile to reduce complexity
108+ const createProgressCallback = useCallback ( ( signal : AbortSignal ) : UploadProgressCallback => {
109+ return ( progress : number ) => {
110+ if ( ! cancelRef . current && ! signal . aborted ) {
111+ setProgress ( progress ) ;
112+ }
113+ } ;
114+ } , [ ] ) ;
115+
116+ // Helper to check if the upload has been canceled
117+ const isUploadCanceled = useCallback ( ( signal : AbortSignal ) : boolean => {
118+ return cancelRef . current || signal . aborted ;
119+ } , [ ] ) ;
120+
92121 const uploadFile = useCallback ( async ( ) => {
93122 if ( ! file ) {
94123 setError ( t ( 'upload.error.noFile' ) ) ;
@@ -97,70 +126,88 @@ export const useFileUpload = ({ onUploadComplete }: UseFileUploadOptions = {}):
97126
98127 // Reset cancel flag
99128 cancelRef . current = false ;
129+
130+ // Create a new AbortController for this upload request
131+ abortControllerRef . current = new AbortController ( ) ;
132+ const { signal } = abortControllerRef . current ;
100133
101134 try {
102135 setStatus ( UploadStatus . REQUESTING_PERMISSION ) ;
103136
104- // Check for permissions
105- let hasPermission = await checkFilePermissions ( ) ;
137+ // Check and request permissions if needed
138+ const hasPermission = await checkPermissions ( ) ;
106139
107140 if ( ! hasPermission ) {
108- // Request permissions
109- hasPermission = await requestFilePermissions ( ) ;
110-
111- if ( ! hasPermission ) {
112- setStatus ( UploadStatus . ERROR ) ;
113- setError ( t ( 'upload.error.permissionDenied' ) ) ;
114- return ;
115- }
141+ setStatus ( UploadStatus . ERROR ) ;
142+ setError ( t ( 'upload.error.permissionDenied' ) ) ;
143+ return ;
116144 }
117145
118146 // Check if canceled during permission check
119- if ( cancelRef . current ) {
147+ if ( isUploadCanceled ( signal ) ) {
120148 setStatus ( UploadStatus . IDLE ) ;
121149 return ;
122150 }
123151
124152 setStatus ( UploadStatus . UPLOADING ) ;
125153 setProgress ( 0 ) ;
126154
127- // Create a progress callback for the upload
128- const updateProgress : UploadProgressCallback = ( progress ) => {
129- // Only update progress if not canceled
130- if ( ! cancelRef . current ) {
131- setProgress ( progress ) ;
132- }
133- } ;
155+ // Get a progress callback
156+ const updateProgress = createProgressCallback ( signal ) ;
134157
135- // Upload the file using the API service
136- const result = await uploadReport ( file , updateProgress ) ;
158+ // Upload the file
159+ const result = await uploadReport ( file , updateProgress , signal ) ;
137160
138161 // Check if canceled during upload
139- if ( cancelRef . current ) {
162+ if ( isUploadCanceled ( signal ) ) {
140163 setStatus ( UploadStatus . IDLE ) ;
141164 return ;
142165 }
143166
144- // Set progress to 100% to indicate completion
167+ // Success
145168 setProgress ( 1 ) ;
146169 setStatus ( UploadStatus . SUCCESS ) ;
147170
148- // Notify parent component if callback provided
149171 if ( onUploadComplete ) {
150172 onUploadComplete ( result ) ;
151173 }
152174 } catch ( error ) {
153- // Don't show error if canceled
154- if ( ! cancelRef . current ) {
155- setStatus ( UploadStatus . ERROR ) ;
156- setError (
157- error instanceof Error
158- ? error . message
159- : t ( 'upload.error.unknown' )
160- ) ;
161- }
175+ handleUploadError ( error as Error , signal ) ;
176+ } finally {
177+ cleanupAbortController ( signal ) ;
178+ }
179+ } , [ file , onUploadComplete , t , createProgressCallback , isUploadCanceled ] ) ;
180+
181+ // Helper to handle file permissions
182+ const checkPermissions = useCallback ( async ( ) : Promise < boolean > => {
183+ let hasPermission = await checkFilePermissions ( ) ;
184+
185+ if ( ! hasPermission ) {
186+ hasPermission = await requestFilePermissions ( ) ;
162187 }
163- } , [ file , onUploadComplete , t ] ) ;
188+
189+ return hasPermission ;
190+ } , [ ] ) ;
191+
192+ // Helper to handle upload errors
193+ const handleUploadError = useCallback ( ( error : Error , signal : AbortSignal ) => {
194+ // Don't show error for aborted requests
195+ if ( error instanceof DOMException && error . name === 'AbortError' ) {
196+ return ;
197+ }
198+
199+ if ( ! isUploadCanceled ( signal ) ) {
200+ setStatus ( UploadStatus . ERROR ) ;
201+ setError ( error instanceof Error ? error . message : t ( 'upload.error.unknown' ) ) ;
202+ }
203+ } , [ t , isUploadCanceled ] ) ;
204+
205+ // Helper to clean up the AbortController
206+ const cleanupAbortController = useCallback ( ( signal : AbortSignal ) => {
207+ if ( abortControllerRef . current ?. signal === signal ) {
208+ abortControllerRef . current = null ;
209+ }
210+ } , [ ] ) ;
164211
165212 return {
166213 file,
@@ -173,4 +220,4 @@ export const useFileUpload = ({ onUploadComplete }: UseFileUploadOptions = {}):
173220 formatFileSize,
174221 cancelUpload
175222 } ;
176- } ;
223+ } ;
0 commit comments