courrier multi account restore compose

This commit is contained in:
alma 2025-04-30 13:03:40 +02:00
parent 21accd5224
commit d838cb9db9
2 changed files with 79 additions and 42 deletions

View File

@ -328,7 +328,6 @@ export const useCourrier = () => {
// CRITICAL FIX: Clear and precise parameter handling with detailed logging // CRITICAL FIX: Clear and precise parameter handling with detailed logging
let normalizedFolder: string; let normalizedFolder: string;
let effectiveAccountId: string; let effectiveAccountId: string;
let prefixedFolder: string;
// Parse input folder parameter // Parse input folder parameter
if (folder.includes(':')) { if (folder.includes(':')) {
@ -354,7 +353,7 @@ export const useCourrier = () => {
} }
// CRITICAL FIX: Always create a consistently formatted folder name with the EFFECTIVE account prefix // CRITICAL FIX: Always create a consistently formatted folder name with the EFFECTIVE account prefix
prefixedFolder = `${effectiveAccountId}:${normalizedFolder}`; const prefixedFolder = `${effectiveAccountId}:${normalizedFolder}`;
console.log(`[changeFolder] Normalized parameters: folder=${normalizedFolder}, accountId=${effectiveAccountId}, prefixedFolder=${prefixedFolder}`); console.log(`[changeFolder] Normalized parameters: folder=${normalizedFolder}, accountId=${effectiveAccountId}, prefixedFolder=${prefixedFolder}`);
@ -364,29 +363,29 @@ export const useCourrier = () => {
// Reset to page 1 // Reset to page 1
setPage(1); setPage(1);
// CRITICAL FIX: Set currentFolder state and verify it was set correctly // Set currentFolder state
console.log(`[changeFolder] Setting currentFolder to: ${prefixedFolder}`); console.log(`[changeFolder] Setting currentFolder to: ${prefixedFolder}`);
setCurrentFolder(prefixedFolder); setCurrentFolder(prefixedFolder);
// CRITICAL FIX: Use a small delay to ensure state updates have propagated // CRITICAL FIX: Wait for state updates to propagate
// This helps prevent race conditions during account switching setTimeout(async () => {
await new Promise(resolve => setTimeout(resolve, 200)); try {
// CRITICAL FIX: Always pass the effective account ID explicitly to loadEmails
// CRITICAL FIX: Double-check the folder after state update to ensure consistency // This ensures account context is maintained even if currentFolder hasn't updated yet
console.log(`[changeFolder] After state update, currentFolder=${currentFolder}, loading emails with explicit accountId=${effectiveAccountId}`); await loadEmails(false, effectiveAccountId);
console.log(`[changeFolder] Finished changing to folder=${prefixedFolder}`);
// CRITICAL FIX: Always pass the effective account ID explicitly to loadEmails } catch (error) {
// This ensures account context is maintained even if currentFolder hasn't updated yet console.error(`[changeFolder] Error in delayed loadEmails:`, error);
await loadEmails(false, effectiveAccountId); setError(error instanceof Error ? error.message : 'Error loading emails');
setIsLoading(false);
console.log(`[changeFolder] Finished changing to folder=${prefixedFolder}`); }
}, 50);
} catch (error) { } catch (error) {
console.error(`[changeFolder] Error changing to folder ${folder}:`, error); console.error(`[changeFolder] Error changing to folder ${folder}:`, error);
setError(error instanceof Error ? error.message : 'Unknown error'); setError(error instanceof Error ? error.message : 'Unknown error');
} finally {
setIsLoading(false); setIsLoading(false);
} }
}, [loadEmails, currentFolder]); }, [loadEmails, setSearchQuery, setPage, setCurrentFolder, setEmails, setSelectedEmail, setSelectedEmailIds, setIsLoading, setError]);
// Load emails when page changes for pagination only // Load emails when page changes for pagination only
useEffect(() => { useEffect(() => {

View File

@ -68,41 +68,57 @@ export async function getCachedEmailsWithTimeout(
return null; return null;
} }
// Extract account ID from folder name if present and none was explicitly provided // CRITICAL FIX: Proper folder and account ID normalization
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId; // This is critical for consistent cache keys
let effectiveAccountId: string;
// Use the most specific account ID available let normalizedFolder: string;
const effectiveAccountId = folderAccountId || accountId || 'default';
// Normalize folder name by removing account prefix if present // First, handle the folder format
// This ensures consistent cache key format regardless of how folder name is passed if (folder.includes(':')) {
const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder; // Extract parts if folder already has a prefix
const parts = folder.split(':');
const folderAccountId = parts[0];
normalizedFolder = parts[1];
// CRITICAL FIX: If explicit accountId is provided, it ALWAYS takes precedence
// This ensures account switching works correctly
if (accountId) {
console.log(`[getCachedEmailsWithTimeout] Using provided accountId (${accountId}) over folder prefix (${folderAccountId})`);
effectiveAccountId = accountId;
} else {
effectiveAccountId = folderAccountId;
}
} else {
// No folder prefix, use the folder name as is
normalizedFolder = folder;
effectiveAccountId = accountId || 'default';
}
// Log the normalization for debugging // Log the normalization for debugging
if (folder !== normalizedFolder) { console.log(`[getCachedEmailsWithTimeout] Normalized: folder=${normalizedFolder}, accountId=${effectiveAccountId} (from ${folder})`);
console.log(`Normalized folder name from ${folder} to ${normalizedFolder} for cache lookup with account ID ${effectiveAccountId}`);
}
return new Promise((resolve) => { return new Promise((resolve) => {
const timeoutId = setTimeout(() => { const timeoutId = setTimeout(() => {
console.log(`Cache access timeout for ${userId}:${normalizedFolder}:${page}:${perPage} for account ${effectiveAccountId}`); console.log(`Cache access timeout for ${userId}:${effectiveAccountId}:${normalizedFolder}:${page}:${perPage}`);
resolve(null); resolve(null);
}, timeoutMs); }, timeoutMs);
// CRITICAL FIX: Use the normalized parameters consistently
// This ensures we're looking up the right cache entries
getCachedEmailList(userId, effectiveAccountId, normalizedFolder, page, perPage) getCachedEmailList(userId, effectiveAccountId, normalizedFolder, page, perPage)
.then(result => { .then(result => {
clearTimeout(timeoutId); clearTimeout(timeoutId);
if (result) { if (result) {
console.log(`Using cached data for ${userId}:${normalizedFolder}:${page}:${perPage} for account ${effectiveAccountId}`); console.log(`[getCachedEmailsWithTimeout] Cache hit for ${userId}:${effectiveAccountId}:${normalizedFolder}:${page}:${perPage}`);
resolve(result); resolve(result);
} else { } else {
console.log(`Redis cache miss for ${userId}:${effectiveAccountId}:${normalizedFolder}:${page}:${perPage}, fetching emails from IMAP`); console.log(`[getCachedEmailsWithTimeout] Cache miss for ${userId}:${effectiveAccountId}:${normalizedFolder}:${page}:${perPage}`);
resolve(null); resolve(null);
} }
}) })
.catch(err => { .catch(err => {
clearTimeout(timeoutId); clearTimeout(timeoutId);
console.error('Error accessing cache:', err); console.error('[getCachedEmailsWithTimeout] Error accessing cache:', err);
resolve(null); resolve(null);
}); });
}); });
@ -119,16 +135,35 @@ export async function refreshEmailsInBackground(
perPage: number = 20, perPage: number = 20,
accountId?: string accountId?: string
): Promise<void> { ): Promise<void> {
// Extract account ID from folder name if present and none was explicitly provided // CRITICAL FIX: Apply consistent account ID and folder name normalization
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId; let effectiveAccountId: string;
let normalizedFolder: string;
// Use the most specific account ID available // First, handle the folder format
const effectiveAccountId = folderAccountId || accountId || 'default'; if (folder.includes(':')) {
// Extract parts if folder already has a prefix
const parts = folder.split(':');
const folderAccountId = parts[0];
normalizedFolder = parts[1];
// 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;
}
} else {
// No folder prefix
normalizedFolder = folder;
effectiveAccountId = accountId || 'default';
}
// Normalize folder name by removing account prefix if present console.log(`[refreshEmailsInBackground] Normalized: folder=${normalizedFolder}, accountId=${effectiveAccountId} (from ${folder})`);
const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder;
const prefetchKey = `refresh:${normalizedFolder}:${page}:${effectiveAccountId}`; // 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 // Skip if already in progress or in cooldown
if (!shouldPrefetch(userId, prefetchKey)) { if (!shouldPrefetch(userId, prefetchKey)) {
@ -138,11 +173,14 @@ export async function refreshEmailsInBackground(
// Use setTimeout to ensure this runs after current execution context // Use setTimeout to ensure this runs after current execution context
setTimeout(async () => { setTimeout(async () => {
try { try {
console.log(`Background refresh for ${userId}:${normalizedFolder}:${page}:${perPage} for account ${effectiveAccountId}`); 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); const freshData = await getEmails(userId, normalizedFolder, page, perPage, effectiveAccountId);
console.log(`Background refresh completed for ${userId}:${normalizedFolder} for account ${effectiveAccountId}`);
console.log(`[refreshEmailsInBackground] Completed for ${userId}, account=${effectiveAccountId}, folder=${normalizedFolder}`);
} catch (error) { } catch (error) {
console.error('Background refresh error:', error); console.error(`[refreshEmailsInBackground] Error: ${error instanceof Error ? error.message : String(error)}`);
} finally { } finally {
markPrefetchCompleted(userId, prefetchKey); markPrefetchCompleted(userId, prefetchKey);
} }