@@ -246,10 +246,16 @@ export function useNotes() {
246246 }
247247 } , [ clerkUser ] ) ;
248248
249- const fetchAllNotes = useCallback ( async ( ) : Promise < Note [ ] > => {
249+ const fetchAllNotes = useCallback ( async ( folderId ?: string ) : Promise < Note [ ] > => {
250+ // Build params - optionally filter by folder
251+ const baseParams : { page : number ; limit : number ; folderId ?: string } = { page : 1 , limit : 50 } ;
252+ if ( folderId ) {
253+ baseParams . folderId = folderId ;
254+ }
255+
250256 // Fetch first page to determine total pages
251257 const firstPageResponse = await retryWithBackoff ( ( ) =>
252- api . getNotes ( { page : 1 , limit : 50 } )
258+ api . getNotes ( baseParams )
253259 ) ;
254260 const firstPageNotes = firstPageResponse . notes . map ( convertApiNote ) ;
255261
@@ -269,7 +275,7 @@ export function useNotes() {
269275 const batchPromises = [ ] ;
270276 for ( let page = i ; page < i + batchSize && page <= Math . min ( totalPages , 50 ) ; page ++ ) {
271277 batchPromises . push (
272- retryWithBackoff ( ( ) => api . getNotes ( { page, limit : 50 } ) )
278+ retryWithBackoff ( ( ) => api . getNotes ( { ... baseParams , page, limit : 50 } ) )
273279 . then ( response => response . notes . map ( convertApiNote ) )
274280 ) ;
275281 }
@@ -329,6 +335,54 @@ export function useNotes() {
329335 }
330336 } , [ fetchAllFolders , fetchAllNotes ] ) ;
331337
338+ // Refresh only notes in the current folder (and subfolders) for better performance
339+ const refreshCurrentFolder = useCallback ( async ( ) => {
340+ if ( ! selectedFolder ) {
341+ // No folder selected, do full refresh
342+ return loadData ( ) ;
343+ }
344+
345+ try {
346+ setLoading ( true ) ;
347+ setError ( null ) ;
348+
349+ // Get all folder IDs to fetch (selected + descendants)
350+ const folderIds = [ selectedFolder . id , ...getDescendantIds ( selectedFolder . id , folders ) ] ;
351+
352+ // Fetch notes for each folder in parallel
353+ const folderNotesPromises = folderIds . map ( folderId => fetchAllNotes ( folderId ) ) ;
354+ const folderNotesArrays = await Promise . all ( folderNotesPromises ) ;
355+ const fetchedNotes = folderNotesArrays . flat ( ) ;
356+
357+ // Create a folder map for quick lookup
358+ const folderMap = new Map ( folders . map ( ( f ) => [ f . id , f ] ) ) ;
359+
360+ // Process fetched notes
361+ const processedNotes = fetchedNotes . map ( ( note ) => {
362+ const folder = note . folderId ? folderMap . get ( note . folderId ) : undefined ;
363+ return {
364+ ...note ,
365+ attachments : [ ] ,
366+ attachmentCount : note . attachmentCount ?? 0 ,
367+ folder
368+ } ;
369+ } ) ;
370+
371+ // Merge with existing notes: replace notes in the fetched folders, keep others
372+ setNotes ( prev => {
373+ // Remove old notes from the fetched folders
374+ const notesOutsideFolders = prev . filter ( note => ! folderIds . includes ( note . folderId ?? '' ) ) ;
375+ // Add the freshly fetched notes
376+ return [ ...notesOutsideFolders , ...processedNotes ] ;
377+ } ) ;
378+ } catch ( error ) {
379+ secureLogger . error ( 'Folder refresh failed' , error ) ;
380+ setError ( 'Failed to refresh folder' ) ;
381+ } finally {
382+ setLoading ( false ) ;
383+ }
384+ } , [ selectedFolder , folders , fetchAllNotes , loadData ] ) ;
385+
332386 useEffect ( ( ) => {
333387 if ( ! isLoaded ) return ;
334388
@@ -426,19 +480,14 @@ export function useNotes() {
426480 // }
427481 // }, [selectedNote?.id, webSocket.isAuthenticated, webSocket]);
428482
429- // Refetch notes when switching folders to check for new notes from other devices/users
483+ // REMOVED: Auto-refetch on folder change was causing performance issues for users with many notes
484+ // Filtering now happens purely client-side. Use the refresh button to sync new notes from server.
485+ // The isInitialFolderChange ref is kept for potential future use.
430486 useEffect ( ( ) => {
431- // Skip the initial mount to avoid duplicate fetches
432487 if ( isInitialFolderChange . current ) {
433488 isInitialFolderChange . current = false ;
434- return ;
435- }
436-
437- // Only refetch if a folder is selected and encryption is ready
438- if ( selectedFolder ?. id && encryptionReady ) {
439- void loadData ( ) ;
440489 }
441- } , [ selectedFolder ?. id , encryptionReady , loadData ] ) ;
490+ } , [ selectedFolder ?. id ] ) ;
442491
443492 // Load attachments on-demand when a note is selected
444493 useEffect ( ( ) => {
@@ -828,7 +877,7 @@ export function useNotes() {
828877 setSearchQuery,
829878 setNotes,
830879 setFolders,
831- refetch : loadData ,
880+ refetch : refreshCurrentFolder , // Smart refresh: folder-only when in folder, full refresh otherwise
832881 reinitialize : async ( ) => {
833882 if ( clerkUser ) {
834883 await initializeUser ( ) ;
0 commit comments