courrier multi account restore compose

This commit is contained in:
alma 2025-04-29 12:00:36 +02:00
parent 7c9535cb25
commit a9012dec69

View File

@ -91,9 +91,26 @@ export const useCourrier = () => {
setError(null);
try {
// CRITICAL FIX: Extract normalized folder name for API requests
// The currentFolder should already have the account prefix in format "accountId:folder"
// We need to extract the base folder name for the API request
let normalizedFolder = currentFolder;
let effectiveAccountId = accountId || 'default';
if (currentFolder.includes(':')) {
const parts = currentFolder.split(':');
// If no explicit accountId was provided, use the one from the folder name
if (!accountId) {
effectiveAccountId = parts[0];
}
normalizedFolder = parts[1];
}
console.log(`Load emails - using normalized folder: ${normalizedFolder}, effectiveAccountId: ${effectiveAccountId}`);
// Construct query parameters
const queryParams = new URLSearchParams({
folder: currentFolder,
folder: normalizedFolder, // Use normalized folder without account prefix for API
page: page.toString(),
perPage: perPage.toString()
});
@ -102,24 +119,22 @@ export const useCourrier = () => {
queryParams.set('search', searchQuery);
}
// Add accountId to query params if provided
if (accountId) {
queryParams.set('accountId', accountId);
}
// Always add accountId to query params
queryParams.set('accountId', effectiveAccountId);
// Try to get cached emails first
const currentRequestPage = page;
// FIXED: Use the correct parameter order for getCachedEmailsWithTimeout
// FIXED: Use the correct parameter order and normalized values
// Function signature: (userId: string, folder: string, page: number, perPage: number, timeoutMs: number = 100, accountId?: string)
console.log(`Getting cached emails for user ${session.user.id}, folder ${currentFolder}, page ${currentRequestPage}, accountId ${accountId || 'default'}`);
console.log(`Getting cached emails for user ${session.user.id}, folder ${currentFolder}, normalizedFolder: ${normalizedFolder}, page ${currentRequestPage}, accountId ${effectiveAccountId}`);
const cachedEmails = await getCachedEmailsWithTimeout(
session.user.id, // userId: string
currentFolder, // folder: string
currentFolder, // folder: string - use full prefixed folder for cache key
currentRequestPage, // page: number
perPage, // perPage: number
100, // timeoutMs: number
accountId // accountId?: string
effectiveAccountId // accountId?: string - always pass the effective account ID
);
if (cachedEmails) {
@ -184,12 +199,14 @@ export const useCourrier = () => {
setIsLoading(false);
// Still refresh in background for fresh data
// CRITICAL FIX: Use the same effective account ID for background refresh
console.log(`Starting background refresh with folder ${currentFolder}, account ${effectiveAccountId}`);
refreshEmailsInBackground(
session.user.id,
currentFolder,
currentRequestPage,
perPage,
accountId // Make sure accountId is passed
effectiveAccountId // Always use the effective account ID
).catch(err => {
console.error('Background refresh error:', err);
});
@ -197,6 +214,7 @@ export const useCourrier = () => {
}
// Fetch emails from API
console.log(`Fetching emails from API with params: ${queryParams.toString()}`);
const response = await fetch(`/api/courrier?${queryParams.toString()}`);
if (!response.ok) {
@ -206,6 +224,21 @@ export const useCourrier = () => {
const data: EmailListResult = await response.json();
// CRITICAL FIX: Ensure all emails have the proper account ID and folder format for consistent lookup
if (Array.isArray(data.emails)) {
data.emails.forEach(email => {
// If email doesn't have an accountId, set it to the effective one
if (!email.accountId) {
email.accountId = effectiveAccountId;
}
// Ensure folder has the proper prefix format
if (email.folder && !email.folder.includes(':')) {
email.folder = `${email.accountId}:${email.folder}`;
}
});
}
// Update state with the fetched data
if (isLoadMore) {
setEmails(prev => {
@ -266,6 +299,7 @@ export const useCourrier = () => {
const changeFolder = useCallback(async (folder: string, accountId?: string) => {
console.log(`Changing folder to ${folder} for account ${accountId || 'default'}`);
try {
// CRITICAL FIX: Better folder and account ID handling
// Extract account ID from folder name if present and none was explicitly provided
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
@ -275,14 +309,18 @@ export const useCourrier = () => {
// Normalize folder name by removing account prefix if present
const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder;
console.log(`Folder change normalized: ${normalizedFolder}, account: ${effectiveAccountId}`);
// Always create a consistently formatted folder name with account prefix
const prefixedFolder = `${effectiveAccountId}:${normalizedFolder}`;
console.log(`Folder change: original=${folder}, normalized=${normalizedFolder}, accountId=${effectiveAccountId}, prefixed=${prefixedFolder}`);
// Reset selected email
setSelectedEmail(null);
setSelectedEmailIds([]);
// Record the new folder (preserving account prefix if present)
setCurrentFolder(folder);
// Use the consistently prefixed folder name for state
// CRITICAL FIX: Always use the properly prefixed folder name in state
setCurrentFolder(prefixedFolder);
// Reset search query when changing folders
setSearchQuery('');
@ -301,6 +339,8 @@ export const useCourrier = () => {
await new Promise(resolve => setTimeout(resolve, 100));
// Call loadEmails with correct boolean parameter type and account ID
// CRITICAL FIX: Pass the properly formatted folder name to the cache lookup functions
console.log(`Loading emails for prefixed folder: ${prefixedFolder} with accountId: ${effectiveAccountId}`);
await loadEmails(false, effectiveAccountId);
} catch (error) {
console.error(`Error changing to folder ${folder}:`, error);
@ -421,56 +461,170 @@ export const useCourrier = () => {
// Select an email to view
const handleEmailSelect = useCallback(async (emailId: string, accountId: string, folderOverride: string) => {
console.log(`Selecting email ${emailId} from account ${accountId} in folder ${folderOverride}`);
// Enhanced logging for better debugging
console.log(`Selecting email ${emailId} from account [${accountId}] in folder [${folderOverride}]`);
// Skip processing if emailId is empty (used when deselecting emails)
if (!emailId) {
console.log('No email ID provided, clearing selection');
setSelectedEmail(null);
return;
}
setIsLoading(true);
try {
// Normalize account ID if not provided
const effectiveAccountId = accountId || 'default';
// Normalize folder name by removing account prefix if present
const normalizedFolder = folderOverride.includes(':') ? folderOverride.split(':')[1] : folderOverride;
// Normalize folder name handling - ensure consistent format
let normalizedFolder: string;
let prefixedFolder: string;
// Find the email in the current list
const email = emails.find(e =>
if (folderOverride.includes(':')) {
// Extract parts if folder already has a prefix
const parts = folderOverride.split(':');
const folderAccountId = parts[0];
normalizedFolder = parts[1];
// CRITICAL FIX: Always use the provided accountId instead of the one in the folder
// This ensures we're looking in the right account when an email is clicked
prefixedFolder = `${effectiveAccountId}:${normalizedFolder}`;
if (folderAccountId !== effectiveAccountId) {
console.log(`WARNING: Folder account prefix mismatch. Folder has ${folderAccountId}, but using ${effectiveAccountId}`);
}
} else {
// No prefix, add one
normalizedFolder = folderOverride;
prefixedFolder = `${effectiveAccountId}:${normalizedFolder}`;
}
console.log(`Email selection with normalized values: folder=${normalizedFolder}, prefixed=${prefixedFolder}, accountId=${effectiveAccountId}`);
// More flexible email finding with detailed logging
console.log(`Looking for email with ID=${emailId}, account=${effectiveAccountId}, normalized folder=${normalizedFolder}, prefixed=${prefixedFolder}`);
// First, try to find by exact match with account and folder
let email = emails.find(e =>
e.id === emailId &&
(e.accountId === effectiveAccountId) &&
(e.folder === normalizedFolder || e.folder === folderOverride)
e.accountId === effectiveAccountId &&
(
e.folder === prefixedFolder ||
e.folder === normalizedFolder ||
e.folder === folderOverride ||
// Also check for case where email folder has its own prefix but with the same normalized folder
(e.folder?.includes(':') && e.folder.split(':')[1] === normalizedFolder)
)
);
// If not found, try to find just by ID as fallback
if (!email) {
console.log(`Email ${emailId} not found in current list. Fetching from API.`);
const fullEmail = await fetchEmailContent(emailId, effectiveAccountId, normalizedFolder);
setSelectedEmail(fullEmail);
console.log(`No exact match found. Looking for email just by ID=${emailId}`);
email = emails.find(e => e.id === emailId);
if (email) {
console.log(`Found email by ID only. Account=${email.accountId}, folder=${email.folder}`);
}
}
if (!email) {
console.log(`Email ${emailId} not found in current list (searched ${emails.length} emails). Fetching from API.`);
try {
// CRITICAL FIX: Pass both normalized folder and account ID to fetch
// Using normalized folder (without prefix) for API compatibility
console.log(`Fetching email ${emailId} directly from API with normalizedFolder=${normalizedFolder}, accountId=${effectiveAccountId}`);
const fullEmail = await fetchEmailContent(emailId, effectiveAccountId, normalizedFolder);
// Ensure the returned email has the proper accountId and prefixed folder name
if (fullEmail) {
if (!fullEmail.accountId) {
fullEmail.accountId = effectiveAccountId;
}
// Make sure folder has the proper prefix for consistent lookup
if (fullEmail.folder && !fullEmail.folder.includes(':')) {
fullEmail.folder = `${fullEmail.accountId}:${fullEmail.folder}`;
}
}
console.log(`Successfully fetched email from API:`, {
id: fullEmail.id,
account: fullEmail.accountId,
folder: fullEmail.folder
});
setSelectedEmail(fullEmail);
} catch (error) {
// Type the error properly
const fetchError = error instanceof Error ? error : new Error(String(error));
console.error(`Error fetching email from API: ${fetchError.message}`);
throw fetchError;
}
return;
}
// If content is not fetched, get the full content
if (!email.contentFetched) {
console.log(`Fetching content for email ${emailId}`);
const fullEmail = await fetchEmailContent(emailId, effectiveAccountId, normalizedFolder);
// Merge the full content with the email
const updatedEmail = {
...email,
content: fullEmail.content,
attachments: fullEmail.attachments,
contentFetched: true
};
// Update the email in the list
setEmails(emails.map(e => e.id === emailId ? updatedEmail : e));
setSelectedEmail(updatedEmail);
console.log(`Email found but content not fetched. Getting full content for ${emailId}`);
try {
// CRITICAL FIX: Extract normalized folder from email's folder if it has a prefix
const emailFolder = email.folder || normalizedFolder;
let emailNormalizedFolder = emailFolder;
if (emailFolder.includes(':')) {
emailNormalizedFolder = emailFolder.split(':')[1];
}
// Always use the email's own accountId if available
const emailAccountId = email.accountId || effectiveAccountId;
console.log(`Fetching content for email ${emailId} with accountId=${emailAccountId}, folder=${emailNormalizedFolder}`);
// Use the email's own accountId and normalized folder for fetching
const fullEmail = await fetchEmailContent(
emailId,
emailAccountId,
emailNormalizedFolder
);
// Ensure the returned email has consistent format
if (fullEmail && !fullEmail.accountId) {
fullEmail.accountId = emailAccountId;
}
// Merge the full content with the email
const updatedEmail = {
...email,
accountId: emailAccountId, // Ensure account ID is preserved
folder: email.folder, // Preserve original folder name with prefix
content: fullEmail.content,
attachments: fullEmail.attachments,
contentFetched: true
};
// Update the email in the list
setEmails(emails.map(e => e.id === emailId ? updatedEmail : e));
setSelectedEmail(updatedEmail);
console.log(`Successfully updated email with content`);
} catch (error) {
// Type the error properly
const contentError = error instanceof Error ? error : new Error(String(error));
console.error(`Error fetching email content: ${contentError.message}`);
throw contentError;
}
} else {
console.log(`Email found with content already fetched, selecting directly`);
setSelectedEmail(email);
}
// Mark the email as read if it's not already
if (!email.flags.seen) {
markEmailAsRead(emailId, true);
console.log(`Marking email ${emailId} as read`);
markEmailAsRead(emailId, true).catch(err => {
console.error(`Failed to mark email as read: ${err.message}`);
});
}
} catch (err) {
console.error('Error selecting email:', err);
console.error(`Error selecting email: ${err instanceof Error ? err.message : String(err)}`);
toast({
variant: "destructive",
title: "Error",