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

View File

@ -68,41 +68,57 @@ export async function getCachedEmailsWithTimeout(
return null;
}
// Extract account ID from folder name if present and none was explicitly provided
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
// Use the most specific account ID available
const effectiveAccountId = folderAccountId || accountId || 'default';
// CRITICAL FIX: Proper folder and account ID normalization
// This is critical for consistent cache keys
let effectiveAccountId: string;
let normalizedFolder: string;
// Normalize folder name by removing account prefix if present
// This ensures consistent cache key format regardless of how folder name is passed
const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder;
// 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];
// 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
if (folder !== normalizedFolder) {
console.log(`Normalized folder name from ${folder} to ${normalizedFolder} for cache lookup with account ID ${effectiveAccountId}`);
}
console.log(`[getCachedEmailsWithTimeout] Normalized: folder=${normalizedFolder}, accountId=${effectiveAccountId} (from ${folder})`);
return new Promise((resolve) => {
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);
}, timeoutMs);
// CRITICAL FIX: Use the normalized parameters consistently
// This ensures we're looking up the right cache entries
getCachedEmailList(userId, effectiveAccountId, normalizedFolder, page, perPage)
.then(result => {
clearTimeout(timeoutId);
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);
} 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);
}
})
.catch(err => {
clearTimeout(timeoutId);
console.error('Error accessing cache:', err);
console.error('[getCachedEmailsWithTimeout] Error accessing cache:', err);
resolve(null);
});
});
@ -119,16 +135,35 @@ export async function refreshEmailsInBackground(
perPage: number = 20,
accountId?: string
): Promise<void> {
// Extract account ID from folder name if present and none was explicitly provided
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
// CRITICAL FIX: Apply consistent account ID and folder name normalization
let effectiveAccountId: string;
let normalizedFolder: string;
// Use the most specific account ID available
const effectiveAccountId = folderAccountId || accountId || 'default';
// 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];
// 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
const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder;
console.log(`[refreshEmailsInBackground] Normalized: folder=${normalizedFolder}, accountId=${effectiveAccountId} (from ${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
if (!shouldPrefetch(userId, prefetchKey)) {
@ -138,11 +173,14 @@ export async function refreshEmailsInBackground(
// Use setTimeout to ensure this runs after current execution context
setTimeout(async () => {
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);
console.log(`Background refresh completed for ${userId}:${normalizedFolder} for account ${effectiveAccountId}`);
console.log(`[refreshEmailsInBackground] Completed for ${userId}, account=${effectiveAccountId}, folder=${normalizedFolder}`);
} catch (error) {
console.error('Background refresh error:', error);
console.error(`[refreshEmailsInBackground] Error: ${error instanceof Error ? error.message : String(error)}`);
} finally {
markPrefetchCompleted(userId, prefetchKey);
}