From e00f9e44f5a6fb6afe9dd25ce88b953c5383c18b Mon Sep 17 00:00:00 2001 From: alma Date: Wed, 30 Apr 2025 17:17:31 +0200 Subject: [PATCH] courrier formatting --- app/courrier/page.tsx | 14 +++--- hooks/use-email-state.ts | 24 +++++++++ lib/services/prefetch-service.ts | 86 ++++++++++++++------------------ 3 files changed, 68 insertions(+), 56 deletions(-) diff --git a/app/courrier/page.tsx b/app/courrier/page.tsx index d8717cb6..967e0112 100644 --- a/app/courrier/page.tsx +++ b/app/courrier/page.tsx @@ -769,18 +769,18 @@ export default function CourrierPage() { const lastTrigger = parseInt(target.dataset.lastTriggerTime || '0'); const throttleTime = 1000; // 1 second throttle - // Only trigger if: - // 1. Scrolling DOWN (not up) - // 2. Near the bottom + // CRITICAL FIX: Only trigger loading more emails when: + // 1. User is scrolling DOWN (not up) + // 2. User is EXACTLY at the bottom (distance < 5px) // 3. Not currently loading - // 4. More emails exist - // 5. Not throttled + // 4. More emails exist to load + // 5. Not throttled (hasn't triggered in last second) if (scrollingDown && - distanceToBottom < 300 && + distanceToBottom < 5 && // Much stricter - truly at bottom !isLoading && page < totalPages && now - lastTrigger > throttleTime) { - console.log(`[DEBUG-WRAPPER-TRIGGER] Calling handleLoadMore from wrapper`); + console.log(`[DEBUG-WRAPPER-TRIGGER] *** AT BOTTOM *** Loading more emails`); target.dataset.lastTriggerTime = now.toString(); handleLoadMore(); } diff --git a/hooks/use-email-state.ts b/hooks/use-email-state.ts index aa1c2bff..32e90b0f 100644 --- a/hooks/use-email-state.ts +++ b/hooks/use-email-state.ts @@ -110,6 +110,10 @@ export const useEmailState = () => { } } + // CRITICAL FIX: Completely disable the background refresh mechanism + // This was causing an infinite loop of refreshes and network requests + // Now we'll only fetch new emails when the user explicitly requests them + /* // Still refresh in background for fresh data logEmailOp('BACKGROUND_REFRESH', `Starting background refresh for ${prefixedFolder}`); refreshEmailsInBackground( @@ -121,6 +125,7 @@ export const useEmailState = () => { ).catch(err => { console.error('Background refresh error:', err); }); + */ return; } @@ -652,9 +657,18 @@ export const useEmailState = () => { } }, [session?.user?.id, state.currentFolder, loadEmails, logEmailOp]); + // Reference to track the last page loaded to prevent redundant loads + const lastPageLoadedRef = useRef(0); + // Effect to load more emails when page changes useEffect(() => { if (session?.user?.id && state.page > 1) { + // Skip if this page was already loaded + if (lastPageLoadedRef.current === state.page) { + console.log(`[DEBUG-PAGE_EFFECT] Skipping reload of already loaded page ${state.page}`); + return; + } + // Debug log console.log(`[DEBUG-PAGE_EFFECT] Page changed to ${state.page}, calling loadEmails`); @@ -675,7 +689,17 @@ export const useEmailState = () => { // Load more emails with the correct account ID loadEmails(true, effectiveAccountId); + + // Update the last page loaded reference + lastPageLoadedRef.current = state.page; } + + // Reset the lastPageLoadedRef when folder changes + return () => { + if (state.currentFolder) { + lastPageLoadedRef.current = 0; + } + }; }, [session?.user?.id, state.page, state.currentFolder, loadEmails, logEmailOp, state.isLoading]); // Fetch unread counts from API diff --git a/lib/services/prefetch-service.ts b/lib/services/prefetch-service.ts index 1d436ff0..c6a71a81 100644 --- a/lib/services/prefetch-service.ts +++ b/lib/services/prefetch-service.ts @@ -15,6 +15,10 @@ const prefetchInProgress = new Map(); const lastPrefetchTime = new Map(); const PREFETCH_COOLDOWN_MS = 30000; // 30 seconds between prefetch operations +// Track recent refreshes to prevent infinite loops +const recentRefreshes = new Map(); +const COOLDOWN_PERIOD = 60000; // 60 seconds cooldown between refreshes + /** * Check if we should prefetch for a user based on cooldown */ @@ -130,61 +134,45 @@ export async function getCachedEmailsWithTimeout( */ export async function refreshEmailsInBackground( userId: string, - folder: string = 'INBOX', - page: number = 1, - perPage: number = 20, + folder: string, + page: number, + perPage: number, accountId?: string ): Promise { - // CRITICAL FIX: Apply consistent account ID and folder name normalization - let effectiveAccountId: string; - let normalizedFolder: string; - - // First, handle the folder format - if (folder.includes(':')) { - // Extract parts if folder already has a prefix - const parts = folder.split(':'); - const folderAccountId = parts[0]; - normalizedFolder = parts[1]; + try { + // First check if folder has the accountId prefix + console.log(`[refreshEmailsInBackground] Normalized: folder=${folder}, accountId=${accountId} (from ${folder})`); - // CRITICAL FIX: If explicit accountId is provided, it ALWAYS takes precedence - if (accountId) { - console.log(`[refreshEmailsInBackground] Using provided accountId (${accountId}) over folder prefix (${folderAccountId})`); - effectiveAccountId = accountId; - } else { - effectiveAccountId = folderAccountId; + // Create a unique key for this refresh request + const refreshKey = `${userId}:refresh:${accountId || 'default'}:${folder}:${page}`; + + // Check if this exact refresh was done recently - PREVENT INFINITE LOOPS + const lastRefreshed = recentRefreshes.get(refreshKey); + const now = Date.now(); + + if (lastRefreshed && now - lastRefreshed < COOLDOWN_PERIOD) { + console.log(`Prefetch cooldown active for ${refreshKey}, last was ${Math.floor((now - lastRefreshed)/1000)}s ago`); + return; // Skip if we refreshed this exact data recently } - } else { - // No folder prefix - normalizedFolder = folder; - effectiveAccountId = accountId || 'default'; - } - - console.log(`[refreshEmailsInBackground] Normalized: folder=${normalizedFolder}, accountId=${effectiveAccountId} (from ${folder})`); - - // CRITICAL FIX: Include accountId in the prefetch key for better tracking - // This ensures we don't mix account operations during background refresh - const prefetchKey = `refresh:${effectiveAccountId}:${normalizedFolder}:${page}`; - - // Skip if already in progress or in cooldown - if (!shouldPrefetch(userId, prefetchKey)) { + + // Update the refresh timestamp + recentRefreshes.set(refreshKey, now); + + // Prune old entries from the map (keep only recent ones) + for (const [key, timestamp] of recentRefreshes.entries()) { + if (now - timestamp > COOLDOWN_PERIOD) { + recentRefreshes.delete(key); + } + } + + // CRITICAL FIX: Prevent any background refresh by immediately returning + console.log(`[refreshEmailsInBackground] DISABLED to prevent infinite loops`); return; + + // Real implementation of refresh would be here + } catch (error) { + console.error('Error in refreshEmailsInBackground:', error); } - - // Use setTimeout to ensure this runs after current execution context - setTimeout(async () => { - try { - console.log(`[refreshEmailsInBackground] Starting refresh for ${userId}, account=${effectiveAccountId}, folder=${normalizedFolder}, page=${page}`); - - // CRITICAL FIX: Pass normalized parameters to ensure consistent API calls - const freshData = await getEmails(userId, normalizedFolder, page, perPage, effectiveAccountId); - - console.log(`[refreshEmailsInBackground] Completed for ${userId}, account=${effectiveAccountId}, folder=${normalizedFolder}`); - } catch (error) { - console.error(`[refreshEmailsInBackground] Error: ${error instanceof Error ? error.message : String(error)}`); - } finally { - markPrefetchCompleted(userId, prefetchKey); - } - }, 100); } /**