courrier multi account restore compose
This commit is contained in:
parent
7c9535cb25
commit
a9012dec69
@ -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",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user