@@ -9,8 +9,8 @@ import React, { useEffect, useRef, useState } from 'react';
99import appService from '@internxt-mobile/services/AppService' ;
1010import errorService from '@internxt-mobile/services/ErrorService' ;
1111import notificationsService from '@internxt-mobile/services/NotificationsService' ;
12- import { AppStateStatus , NativeEventSubscription } from 'react-native' ;
1312import { NotificationType } from '@internxt-mobile/types/index' ;
13+ import { AppStateStatus , NativeEventSubscription } from 'react-native' ;
1414
1515import { driveFolderService } from '@internxt-mobile/services/drive/folder' ;
1616import { mapFileWithIsFolder , mapFolderWithIsFolder } from 'src/helpers/driveItemMappers' ;
@@ -85,6 +85,8 @@ export const DriveContextProvider: React.FC<DriveContextProviderProps> = ({ chil
8585 const [ currentFolder , setCurrentFolder ] = useState < DriveFoldersTreeNode | null > ( null ) ;
8686 const currentFolderId = useRef < string | null > ( null ) ;
8787 const onAppStateChangeListener = useRef < NativeEventSubscription | null > ( null ) ;
88+ const folderAbortControllers = useRef < Map < string , AbortController > > ( new Map ( ) ) ;
89+ const driveFoldersTreeRef = useRef < DriveFoldersTree > ( { [ rootFolderId ] : ROOT_FOLDER_NODE } ) ;
8890
8991 const handleAppStateChange = ( state : AppStateStatus ) => {
9092 if ( state === 'active' && currentFolderId . current ) {
@@ -110,6 +112,10 @@ export const DriveContextProvider: React.FC<DriveContextProviderProps> = ({ chil
110112 } ;
111113 } , [ ] ) ;
112114
115+ useEffect ( ( ) => {
116+ driveFoldersTreeRef . current = driveFoldersTree ;
117+ } , [ driveFoldersTree ] ) ;
118+
113119 useEffect ( ( ) => {
114120 asyncStorageService . getItem ( AsyncStorageKey . PreferredDriveViewMode ) . then ( ( preferredDriveViewMode ) => {
115121 if ( preferredDriveViewMode && preferredDriveViewMode !== viewMode ) {
@@ -245,43 +251,71 @@ export const DriveContextProvider: React.FC<DriveContextProviderProps> = ({ chil
245251 } ;
246252 } ;
247253
248- const loadFolderContent = async ( folderId : string , options ?: LoadFolderContentOptions ) => {
249- const shouldResetPagination = options ?. resetPagination ;
250- const driveFolderTreeNode : DriveFoldersTreeNode = driveFoldersTree [ folderId ] ?? ROOT_FOLDER_NODE ;
251- if ( ! driveFolderTreeNode ) throw new Error ( 'Cannot load this folder' ) ;
252-
253- if ( options ?. focusFolder && driveFolderTreeNode ) {
254- setCurrentFolder ( driveFolderTreeNode ) ;
255- }
254+ const registerFolderLoad = ( folderId : string ) : AbortController => {
255+ folderAbortControllers . current . get ( folderId ) ?. abort ( ) ;
256+ const controller = new AbortController ( ) ;
257+ folderAbortControllers . current . set ( folderId , controller ) ;
258+ return controller ;
259+ } ;
256260
257- let files : DriveFileForTree [ ] = [ ] ;
258- let folders : DriveFolderForTree [ ] = [ ] ;
261+ const updateFolderNode = ( folderId : string , updates : Partial < DriveFoldersTreeNode > ) => {
262+ setDriveFoldersTree ( ( prevTree ) => {
263+ const node = prevTree [ folderId ] ;
264+ if ( ! node ) return prevTree ;
265+ return { ...prevTree , [ folderId ] : { ...node , ...updates } } ;
266+ } ) ;
267+ } ;
259268
269+ const fetchFolderData = async (
270+ folderId : string ,
271+ options : LoadFolderContentOptions | undefined ,
272+ controller : AbortController ,
273+ ) : Promise < { files : DriveFileForTree [ ] ; folders : DriveFolderForTree [ ] } | null > => {
260274 if ( options ?. loadAllContent ) {
261275 const allContent = await fetchAllFolderContent ( folderId ) ;
262- files = allContent . files ;
263- folders = allContent . folders ;
264- } else {
265- const nextFilesPage = options ?. resetPagination
266- ? 1
267- : Math . ceil ( driveFolderTreeNode . files . length / FILES_LIMIT_PER_PAGE ) + 1 ;
268- const nextFoldersPage = options ?. resetPagination
269- ? 1
270- : Math . ceil ( driveFolderTreeNode . folders . length / FOLDERS_LIMIT_PER_PAGE ) + 1 ;
271-
272- const paginatedContent = await fetchFolderContent ( folderId , nextFilesPage , nextFoldersPage ) ;
273- files = paginatedContent . files ;
274- folders = paginatedContent . folders ;
276+ return controller . signal . aborted ? null : allContent ;
275277 }
276278
277- updateDriveFoldersTree ( {
278- folderId,
279- parentId : driveFolderTreeNode . parentId ,
280- newFiles : files ,
281- newFolders : folders ,
282- error : undefined ,
283- resetPagination : shouldResetPagination ?? false ,
284- } ) ;
279+ const currentDriveFoldersTree = driveFoldersTreeRef . current [ folderId ] ?? ROOT_FOLDER_NODE ;
280+ const nextFilesPage = options ?. resetPagination
281+ ? 1
282+ : Math . ceil ( currentDriveFoldersTree . files . length / FILES_LIMIT_PER_PAGE ) + 1 ;
283+ const nextFoldersPage = options ?. resetPagination
284+ ? 1
285+ : Math . ceil ( currentDriveFoldersTree . folders . length / FOLDERS_LIMIT_PER_PAGE ) + 1 ;
286+
287+ const folderContentResult = await fetchFolderContent ( folderId , nextFilesPage , nextFoldersPage ) ;
288+ return controller . signal . aborted ? null : folderContentResult ;
289+ } ;
290+
291+ const loadFolderContent = async ( folderId : string , options ?: LoadFolderContentOptions ) => {
292+ const driveFolderNode = driveFoldersTreeRef . current [ folderId ] ?? ROOT_FOLDER_NODE ;
293+ if ( options ?. focusFolder ) setCurrentFolder ( driveFolderNode ) ;
294+
295+ const controller = registerFolderLoad ( folderId ) ;
296+ updateFolderNode ( folderId , { loading : true , error : undefined } ) ;
297+
298+ try {
299+ const driveFolderNodeContent = await fetchFolderData ( folderId , options , controller ) ;
300+ if ( ! driveFolderNodeContent ) return ;
301+
302+ updateDriveFoldersTree ( {
303+ folderId,
304+ parentId : driveFolderNode . parentId ,
305+ newFiles : driveFolderNodeContent . files ,
306+ newFolders : driveFolderNodeContent . folders ,
307+ error : undefined ,
308+ resetPagination : options ?. resetPagination ?? false ,
309+ } ) ;
310+ } catch ( error ) {
311+ if ( controller . signal . aborted ) return ;
312+ updateFolderNode ( folderId , { loading : false , error : error as Error } ) ;
313+ throw error ;
314+ } finally {
315+ if ( folderAbortControllers . current . get ( folderId ) === controller ) {
316+ folderAbortControllers . current . delete ( folderId ) ;
317+ }
318+ }
285319 } ;
286320
287321 const updateDriveFoldersTree = ( {
@@ -299,47 +333,46 @@ export const DriveContextProvider: React.FC<DriveContextProviderProps> = ({ chil
299333 newFolders : DriveFolderForTree [ ] ;
300334 error ?: Error ;
301335 } ) => {
302- const driveFolderTreeNode = driveFoldersTree [ folderId ] ;
303-
304- const allFiles = resetPagination ? newFiles : [ ...( driveFolderTreeNode ?. files ?? [ ] ) , ...newFiles ] ;
305-
306- const allFolders = resetPagination ? newFolders : [ ...( driveFolderTreeNode ?. folders ?? [ ] ) , ...newFolders ] ;
307-
308- const newTreeNodes = {
309- [ folderId ] : {
310- name : driveFolderTreeNode ?. name || 'Drive' ,
311- parentId : parentId ,
312- uuid : folderId ,
313- files : allFiles ,
314- folders : allFolders ,
315- loading : false ,
316- error,
317- } as DriveFoldersTreeNode ,
318- } ;
336+ setDriveFoldersTree ( ( prevDriveFoldersTree ) => {
337+ const driveFolderTreeNode = prevDriveFoldersTree [ folderId ] ;
319338
320- allFolders . forEach ( ( folder ) => {
321- const existingNode = driveFoldersTree [ folder . uuid ] ;
322- if ( ! existingNode ) {
323- newTreeNodes [ folder . uuid ] = {
324- uuid : folder . uuid ,
325- name : folder . plainName ?? '' ,
326- parentId : folder . parentUuid ,
327- id : folder . id ,
328- updatedAt : folder . updatedAt ,
329- createdAt : folder . createdAt ,
330- loading : true ,
331- files : [ ] ,
332- folders : [ ] ,
333- // @ts -expect-error - leave old implementation in order to not break anything
334- currentFoldersPage : 2 ,
335- error : undefined ,
336- } ;
337- }
338- } ) ;
339+ const allFiles = resetPagination ? newFiles : [ ...( driveFolderTreeNode ?. files ?? [ ] ) , ...newFiles ] ;
340+
341+ const allFolders = resetPagination ? newFolders : [ ...( driveFolderTreeNode ?. folders ?? [ ] ) , ...newFolders ] ;
342+
343+ const newTreeNodes = {
344+ [ folderId ] : {
345+ name : driveFolderTreeNode ?. name || 'Drive' ,
346+ parentId : parentId ,
347+ uuid : folderId ,
348+ files : allFiles ,
349+ folders : allFolders ,
350+ loading : false ,
351+ error,
352+ } as DriveFoldersTreeNode ,
353+ } ;
354+
355+ allFolders . forEach ( ( folder ) => {
356+ const existingNode = prevDriveFoldersTree [ folder . uuid ] ;
357+ if ( ! existingNode ) {
358+ newTreeNodes [ folder . uuid ] = {
359+ uuid : folder . uuid ,
360+ name : folder . plainName ?? '' ,
361+ parentId : folder . parentUuid ,
362+ id : folder . id ,
363+ updatedAt : folder . updatedAt ,
364+ createdAt : folder . createdAt ,
365+ loading : true ,
366+ files : [ ] ,
367+ folders : [ ] ,
368+ // @ts -expect-error - leave old implementation in order to not break anything
369+ currentFoldersPage : 2 ,
370+ error : undefined ,
371+ } ;
372+ }
373+ } ) ;
339374
340- setDriveFoldersTree ( {
341- ...driveFoldersTree ,
342- ...newTreeNodes ,
375+ return { ...prevDriveFoldersTree , ...newTreeNodes } ;
343376 } ) ;
344377 } ;
345378
0 commit comments