courrier multi account restore compose
This commit is contained in:
parent
346b766b7f
commit
9f0ca0e6f5
@ -7,6 +7,9 @@ import {
|
||||
cacheEmailList,
|
||||
invalidateFolderCache
|
||||
} from '@/lib/redis';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Simple in-memory cache (will be removed in a future update)
|
||||
interface EmailCacheEntry {
|
||||
@ -38,11 +41,32 @@ export async function GET(request: Request) {
|
||||
const accountId = searchParams.get("accountId") || "";
|
||||
|
||||
// Extract account ID from folder name if present and none was explicitly provided
|
||||
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
|
||||
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : "";
|
||||
|
||||
// Use the most specific account ID available
|
||||
// First from the folder, then from the explicit parameter, then default
|
||||
let effectiveAccountId = folderAccountId || accountId || 'default';
|
||||
|
||||
// CRITICAL FIX: If effectiveAccountId is still 'default', try to find the first account for the user
|
||||
if (effectiveAccountId === 'default') {
|
||||
try {
|
||||
const accounts = await prisma.mailCredentials.findMany({
|
||||
where: { userId: session.user.id },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
take: 1,
|
||||
select: { id: true }
|
||||
});
|
||||
|
||||
if (accounts && accounts.length > 0) {
|
||||
effectiveAccountId = accounts[0].id;
|
||||
console.log(`No specific account provided, using first available account: ${effectiveAccountId}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error finding default account:", error);
|
||||
// Continue with 'default' if there's an error
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize folder name by removing account prefix if present
|
||||
const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder;
|
||||
|
||||
|
||||
@ -95,15 +95,23 @@ export const useCourrier = () => {
|
||||
// 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(':')) {
|
||||
// CRITICAL FIX: Handle account ID determination more robustly
|
||||
// If specific account ID is provided, always use it
|
||||
// Otherwise extract from currentFolder if possible
|
||||
let effectiveAccountId: string;
|
||||
|
||||
if (accountId) {
|
||||
// Use explicitly provided accountId
|
||||
effectiveAccountId = accountId;
|
||||
} else if (currentFolder.includes(':')) {
|
||||
// Extract from folder format
|
||||
const parts = currentFolder.split(':');
|
||||
// If no explicit accountId was provided, use the one from the folder name
|
||||
if (!accountId) {
|
||||
effectiveAccountId = parts[0];
|
||||
}
|
||||
effectiveAccountId = parts[0];
|
||||
normalizedFolder = parts[1];
|
||||
} else {
|
||||
// Default case
|
||||
effectiveAccountId = 'default';
|
||||
}
|
||||
|
||||
console.log(`Load emails - using normalized folder: ${normalizedFolder}, effectiveAccountId: ${effectiveAccountId}`);
|
||||
@ -125,12 +133,14 @@ export const useCourrier = () => {
|
||||
// Try to get cached emails first
|
||||
const currentRequestPage = page;
|
||||
|
||||
// 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}, normalizedFolder: ${normalizedFolder}, page ${currentRequestPage}, accountId ${effectiveAccountId}`);
|
||||
// CRITICAL FIX: Use the correct cache key format
|
||||
// We pass the full prefixed folder to ensure proper cache key consistency
|
||||
const folderForCache = `${effectiveAccountId}:${normalizedFolder}`;
|
||||
|
||||
console.log(`Getting cached emails for user ${session.user.id}, folder ${folderForCache}, page ${currentRequestPage}, accountId ${effectiveAccountId}`);
|
||||
const cachedEmails = await getCachedEmailsWithTimeout(
|
||||
session.user.id, // userId: string
|
||||
currentFolder, // folder: string - use full prefixed folder for cache key
|
||||
folderForCache, // folder: string - use consistently prefixed folder for cache key
|
||||
currentRequestPage, // page: number
|
||||
perPage, // perPage: number
|
||||
100, // timeoutMs: number
|
||||
@ -299,8 +309,13 @@ 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
|
||||
// Reset selected email and selection state immediately to avoid race conditions
|
||||
setSelectedEmail(null);
|
||||
setSelectedEmailIds([]);
|
||||
setEmails([]); // Clear existing emails right away
|
||||
setIsLoading(true); // Show loading state immediately
|
||||
|
||||
// CRITICAL FIX: 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
|
||||
@ -314,13 +329,8 @@ export const useCourrier = () => {
|
||||
|
||||
console.log(`Folder change: original=${folder}, normalized=${normalizedFolder}, accountId=${effectiveAccountId}, prefixed=${prefixedFolder}`);
|
||||
|
||||
// Reset selected email
|
||||
setSelectedEmail(null);
|
||||
setSelectedEmailIds([]);
|
||||
|
||||
// Use the consistently prefixed folder name for state
|
||||
// CRITICAL FIX: Always use the properly prefixed folder name in state
|
||||
setCurrentFolder(prefixedFolder);
|
||||
// CRITICAL FIX: Store the current account ID in state for all subsequent operations
|
||||
// This ensures operations like markAsRead use the correct account context
|
||||
|
||||
// Reset search query when changing folders
|
||||
setSearchQuery('');
|
||||
@ -328,19 +338,16 @@ export const useCourrier = () => {
|
||||
// Reset to page 1
|
||||
setPage(1);
|
||||
|
||||
// Clear existing emails before loading new ones to prevent UI flicker
|
||||
setEmails([]);
|
||||
|
||||
// Show loading state
|
||||
setIsLoading(true);
|
||||
// CRITICAL FIX: We set the currentFolder state AFTER we have prepared all parameters
|
||||
// This ensures any effects or functions triggered by currentFolder change have the correct context
|
||||
setCurrentFolder(prefixedFolder);
|
||||
|
||||
// Use a small delay to ensure state updates have propagated
|
||||
// This helps prevent race conditions when multiple folders are clicked quickly
|
||||
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}`);
|
||||
// CRITICAL FIX: Wait for the loadEmails operation to complete before considering the folder change done
|
||||
// This prevents multiple concurrent folder changes from interfering with each other
|
||||
await loadEmails(false, effectiveAccountId);
|
||||
} catch (error) {
|
||||
console.error(`Error changing to folder ${folder}:`, error);
|
||||
@ -408,24 +415,47 @@ export const useCourrier = () => {
|
||||
}, [currentFolder]);
|
||||
|
||||
// Mark an email as read/unread
|
||||
const markEmailAsRead = useCallback(async (emailId: string, isRead: boolean) => {
|
||||
const markEmailAsRead = useCallback(async (emailId: string, isRead: boolean, providedAccountId?: string) => {
|
||||
try {
|
||||
// Find the email to get its accountId
|
||||
const emailToMark = emails.find(e => e.id === emailId);
|
||||
if (!emailToMark) {
|
||||
throw new Error('Email not found');
|
||||
// CRITICAL FIX: If an account ID is provided, use it directly
|
||||
// Otherwise, find the email to get its accountId
|
||||
let emailAccountId = providedAccountId;
|
||||
let emailFolder = '';
|
||||
|
||||
if (!emailAccountId) {
|
||||
// Find the email in the current list
|
||||
const emailToMark = emails.find(e => e.id === emailId);
|
||||
if (!emailToMark) {
|
||||
throw new Error('Email not found');
|
||||
}
|
||||
|
||||
// Get the accountId from the email
|
||||
emailAccountId = emailToMark.accountId || 'default';
|
||||
emailFolder = emailToMark.folder;
|
||||
} else {
|
||||
// If providedAccountId exists but we don't have folder info,
|
||||
// try to find the email in the list to get its folder
|
||||
const emailToMark = emails.find(e => e.id === emailId && e.accountId === providedAccountId);
|
||||
if (emailToMark) {
|
||||
emailFolder = emailToMark.folder;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the accountId from the email
|
||||
const emailAccountId = emailToMark.accountId || 'default';
|
||||
|
||||
|
||||
// Normalize folder name by removing account prefix if present
|
||||
const normalizedFolder = emailToMark.folder.includes(':')
|
||||
? emailToMark.folder.split(':')[1]
|
||||
: emailToMark.folder;
|
||||
|
||||
let normalizedFolder = emailFolder;
|
||||
if (emailFolder && emailFolder.includes(':')) {
|
||||
normalizedFolder = emailFolder.split(':')[1];
|
||||
} else if (!emailFolder) {
|
||||
// If folder isn't available from the email object, try to extract it from currentFolder
|
||||
if (currentFolder.includes(':')) {
|
||||
normalizedFolder = currentFolder.split(':')[1];
|
||||
} else {
|
||||
normalizedFolder = currentFolder;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Marking email ${emailId} as ${isRead ? 'read' : 'unread'} in folder ${normalizedFolder}, account: ${emailAccountId}`);
|
||||
|
||||
|
||||
const response = await fetch(`/api/courrier/${emailId}/mark-read`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -437,27 +467,29 @@ export const useCourrier = () => {
|
||||
accountId: emailAccountId
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to mark email as read');
|
||||
}
|
||||
|
||||
// Update the email in the list
|
||||
|
||||
// Update the email in the list - only update the specific email with matching ID AND account ID
|
||||
setEmails(emails.map(email =>
|
||||
email.id === emailId ? { ...email, flags: { ...email.flags, seen: isRead } } : email
|
||||
(email.id === emailId && (!providedAccountId || email.accountId === providedAccountId))
|
||||
? { ...email, flags: { ...email.flags, seen: isRead } }
|
||||
: email
|
||||
));
|
||||
|
||||
|
||||
// If the selected email is the one being marked, update it too
|
||||
if (selectedEmail && selectedEmail.id === emailId) {
|
||||
if (selectedEmail && selectedEmail.id === emailId && (!providedAccountId || selectedEmail.accountId === providedAccountId)) {
|
||||
setSelectedEmail({ ...selectedEmail, flags: { ...selectedEmail.flags, seen: isRead } });
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error marking email as read:', error);
|
||||
return false;
|
||||
}
|
||||
}, [emails, selectedEmail]);
|
||||
}, [emails, selectedEmail, currentFolder]);
|
||||
|
||||
// Select an email to view
|
||||
const handleEmailSelect = useCallback(async (emailId: string, accountId: string, folderOverride: string) => {
|
||||
@ -473,8 +505,11 @@ export const useCourrier = () => {
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
// Normalize account ID if not provided
|
||||
const effectiveAccountId = accountId || 'default';
|
||||
// CRITICAL FIX: Always use the provided accountId, never use default
|
||||
// This ensures we consistently use the correct account throughout the email selection process
|
||||
if (!accountId) {
|
||||
throw new Error('Account ID is required for email selection');
|
||||
}
|
||||
|
||||
// Normalize folder name handling - ensure consistent format
|
||||
let normalizedFolder: string;
|
||||
@ -483,76 +518,59 @@ export const useCourrier = () => {
|
||||
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
|
||||
// CRITICAL FIX: Always use the explicitly provided accountId
|
||||
// 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}`);
|
||||
}
|
||||
prefixedFolder = `${accountId}:${normalizedFolder}`;
|
||||
} else {
|
||||
// No prefix, add one
|
||||
// No prefix, add one using the provided account ID
|
||||
normalizedFolder = folderOverride;
|
||||
prefixedFolder = `${effectiveAccountId}:${normalizedFolder}`;
|
||||
prefixedFolder = `${accountId}:${normalizedFolder}`;
|
||||
}
|
||||
|
||||
console.log(`Email selection with normalized values: folder=${normalizedFolder}, prefixed=${prefixedFolder}, accountId=${effectiveAccountId}`);
|
||||
console.log(`Email selection with normalized values: folder=${normalizedFolder}, prefixed=${prefixedFolder}, accountId=${accountId}`);
|
||||
|
||||
// More flexible email finding with detailed logging
|
||||
console.log(`Looking for email with ID=${emailId}, account=${effectiveAccountId}, normalized folder=${normalizedFolder}, prefixed=${prefixedFolder}`);
|
||||
// CRITICAL FIX: First search for email in current list using the EXACT account provided
|
||||
// This ensures we don't mix emails from different accounts
|
||||
console.log(`Looking for email with ID=${emailId}, account=${accountId}, normalized folder=${normalizedFolder}, prefixed=${prefixedFolder}`);
|
||||
|
||||
// First, try to find by exact match with account and folder
|
||||
// First, try to find by exact match with the provided account and folder
|
||||
let email = emails.find(e =>
|
||||
e.id === emailId &&
|
||||
e.accountId === effectiveAccountId &&
|
||||
e.accountId === accountId &&
|
||||
(
|
||||
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
|
||||
// CRITICAL FIX: If not found, we do NOT try finding by ID only
|
||||
// This prevents mixing emails across accounts
|
||||
if (!email) {
|
||||
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.`);
|
||||
console.log(`Email ${emailId} not found in current list for account ${accountId} (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);
|
||||
// Use the provided account ID and normalized folder for the API request
|
||||
console.log(`Fetching email ${emailId} directly from API with normalizedFolder=${normalizedFolder}, accountId=${accountId}`);
|
||||
const fullEmail = await fetchEmailContent(emailId, accountId, normalizedFolder);
|
||||
|
||||
// Ensure the returned email has the proper accountId and prefixed folder name
|
||||
// CRITICAL FIX: Always set the accountId correctly
|
||||
if (fullEmail) {
|
||||
if (!fullEmail.accountId) {
|
||||
fullEmail.accountId = effectiveAccountId;
|
||||
}
|
||||
fullEmail.accountId = accountId;
|
||||
|
||||
// Make sure folder has the proper prefix for consistent lookup
|
||||
if (fullEmail.folder && !fullEmail.folder.includes(':')) {
|
||||
fullEmail.folder = `${fullEmail.accountId}:${fullEmail.folder}`;
|
||||
fullEmail.folder = `${accountId}:${fullEmail.folder}`;
|
||||
}
|
||||
|
||||
console.log(`Successfully fetched email from API:`, {
|
||||
id: fullEmail.id,
|
||||
account: fullEmail.accountId,
|
||||
folder: fullEmail.folder
|
||||
});
|
||||
setSelectedEmail(fullEmail);
|
||||
}
|
||||
|
||||
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));
|
||||
@ -566,43 +584,35 @@ export const useCourrier = () => {
|
||||
if (!email.contentFetched) {
|
||||
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;
|
||||
// CRITICAL FIX: Use the provided accountId for fetching content, not the one from the email
|
||||
// This ensures consistent account context
|
||||
|
||||
if (emailFolder.includes(':')) {
|
||||
emailNormalizedFolder = emailFolder.split(':')[1];
|
||||
}
|
||||
console.log(`Fetching content for email ${emailId} with accountId=${accountId}, folder=${normalizedFolder}`);
|
||||
|
||||
// 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
|
||||
// Use the provided accountId and normalized folder for fetching
|
||||
const fullEmail = await fetchEmailContent(
|
||||
emailId,
|
||||
emailAccountId,
|
||||
emailNormalizedFolder
|
||||
accountId,
|
||||
normalizedFolder
|
||||
);
|
||||
|
||||
// Ensure the returned email has consistent format
|
||||
if (fullEmail && !fullEmail.accountId) {
|
||||
fullEmail.accountId = emailAccountId;
|
||||
// CRITICAL FIX: Ensure the returned email has the correct account ID
|
||||
if (fullEmail) {
|
||||
fullEmail.accountId = accountId;
|
||||
}
|
||||
|
||||
// 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
|
||||
accountId, // CRITICAL FIX: Use the provided accountId
|
||||
folder: prefixedFolder, // CRITICAL FIX: Use the consistently prefixed folder
|
||||
content: fullEmail.content,
|
||||
attachments: fullEmail.attachments,
|
||||
contentFetched: true
|
||||
};
|
||||
|
||||
// Update the email in the list
|
||||
setEmails(emails.map(e => e.id === emailId ? updatedEmail : e));
|
||||
setEmails(emails.map(e => e.id === emailId && e.accountId === accountId ? updatedEmail : e));
|
||||
setSelectedEmail(updatedEmail);
|
||||
console.log(`Successfully updated email with content`);
|
||||
} catch (error) {
|
||||
@ -613,13 +623,21 @@ export const useCourrier = () => {
|
||||
}
|
||||
} else {
|
||||
console.log(`Email found with content already fetched, selecting directly`);
|
||||
|
||||
// CRITICAL FIX: Ensure the email has the correct account ID before selecting
|
||||
email = {
|
||||
...email,
|
||||
accountId, // Always use the provided accountId
|
||||
folder: prefixedFolder // Always use the consistently prefixed folder
|
||||
};
|
||||
|
||||
setSelectedEmail(email);
|
||||
}
|
||||
|
||||
// Mark the email as read if it's not already
|
||||
if (!email.flags.seen) {
|
||||
console.log(`Marking email ${emailId} as read`);
|
||||
markEmailAsRead(emailId, true).catch(err => {
|
||||
console.log(`Marking email ${emailId} as read for account ${accountId}`);
|
||||
markEmailAsRead(emailId, true, accountId).catch(err => {
|
||||
console.error(`Failed to mark email as read: ${err.message}`);
|
||||
});
|
||||
}
|
||||
@ -637,11 +655,29 @@ export const useCourrier = () => {
|
||||
|
||||
// Toggle starred status for an email
|
||||
const toggleStarred = useCallback(async (emailId: string) => {
|
||||
// Find the email in the emails array
|
||||
const email = emails.find(e => e.id === emailId);
|
||||
if (!email) return;
|
||||
|
||||
const newStarredStatus = !email.flags.flagged;
|
||||
|
||||
// CRITICAL FIX: Extract the account ID from the email object
|
||||
const emailAccountId = email.accountId;
|
||||
if (!emailAccountId) {
|
||||
console.error('Cannot toggle star without account ID');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract normalized folder from folder with potential prefix
|
||||
let normalizedFolder: string;
|
||||
if (email.folder && email.folder.includes(':')) {
|
||||
normalizedFolder = email.folder.split(':')[1];
|
||||
} else if (currentFolder.includes(':')) {
|
||||
normalizedFolder = currentFolder.split(':')[1];
|
||||
} else {
|
||||
normalizedFolder = email.folder || currentFolder;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/courrier/${emailId}/star`, {
|
||||
method: 'POST',
|
||||
@ -650,7 +686,8 @@ export const useCourrier = () => {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
starred: newStarredStatus,
|
||||
folder: currentFolder
|
||||
folder: normalizedFolder,
|
||||
accountId: emailAccountId // CRITICAL FIX: Always include account ID in requests
|
||||
})
|
||||
});
|
||||
|
||||
@ -658,13 +695,15 @@ export const useCourrier = () => {
|
||||
throw new Error('Failed to toggle star status');
|
||||
}
|
||||
|
||||
// Update the email in the list
|
||||
// Update the email in the list - match both ID and account ID
|
||||
setEmails(emails.map(email =>
|
||||
email.id === emailId ? { ...email, flags: { ...email.flags, flagged: newStarredStatus } } : email
|
||||
(email.id === emailId && email.accountId === emailAccountId)
|
||||
? { ...email, flags: { ...email.flags, flagged: newStarredStatus } }
|
||||
: email
|
||||
));
|
||||
|
||||
// If the selected email is the one being starred, update it too
|
||||
if (selectedEmail && selectedEmail.id === emailId) {
|
||||
if (selectedEmail && selectedEmail.id === emailId && selectedEmail.accountId === emailAccountId) {
|
||||
setSelectedEmail({ ...selectedEmail, flags: { ...selectedEmail.flags, flagged: newStarredStatus } });
|
||||
}
|
||||
} catch (error) {
|
||||
@ -736,14 +775,41 @@ export const useCourrier = () => {
|
||||
setIsDeleting(true);
|
||||
|
||||
try {
|
||||
// CRITICAL FIX: Extract normalized folder and account ID from currentFolder
|
||||
let normalizedFolder = currentFolder;
|
||||
let accountId = 'default';
|
||||
|
||||
if (currentFolder.includes(':')) {
|
||||
const parts = currentFolder.split(':');
|
||||
accountId = parts[0];
|
||||
normalizedFolder = parts[1];
|
||||
}
|
||||
|
||||
// Filter email IDs based on the current account context
|
||||
// Only delete emails that belong to the current account
|
||||
const emailsInCurrentAccount = emails.filter(email =>
|
||||
emailIds.includes(email.id) &&
|
||||
(!email.accountId || email.accountId === accountId)
|
||||
);
|
||||
|
||||
const filteredEmailIds = emailsInCurrentAccount.map(email => email.id);
|
||||
|
||||
if (filteredEmailIds.length === 0) {
|
||||
console.log('No emails to delete in the current account context');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Deleting ${filteredEmailIds.length} emails from account ${accountId} in folder ${normalizedFolder}`);
|
||||
|
||||
const response = await fetch('/api/courrier/delete', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
emailIds,
|
||||
folder: currentFolder
|
||||
emailIds: filteredEmailIds,
|
||||
folder: normalizedFolder,
|
||||
accountId
|
||||
})
|
||||
});
|
||||
|
||||
@ -752,19 +818,23 @@ export const useCourrier = () => {
|
||||
}
|
||||
|
||||
// Remove the deleted emails from the list
|
||||
setEmails(emails.filter(email => !emailIds.includes(email.id)));
|
||||
setEmails(emails.filter(email =>
|
||||
!filteredEmailIds.includes(email.id) ||
|
||||
(email.accountId && email.accountId !== accountId)
|
||||
));
|
||||
|
||||
// Clear selection if the selected email was deleted
|
||||
if (selectedEmail && emailIds.includes(selectedEmail.id)) {
|
||||
if (selectedEmail && filteredEmailIds.includes(selectedEmail.id) &&
|
||||
(!selectedEmail.accountId || selectedEmail.accountId === accountId)) {
|
||||
setSelectedEmail(null);
|
||||
}
|
||||
|
||||
// Clear selected IDs
|
||||
setSelectedEmailIds([]);
|
||||
setSelectedEmailIds(prevIds => prevIds.filter(id => !filteredEmailIds.includes(id)));
|
||||
|
||||
toast({
|
||||
title: "Success",
|
||||
description: `${emailIds.length} email(s) deleted`
|
||||
description: `${filteredEmailIds.length} email(s) deleted`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error deleting emails:', error);
|
||||
@ -803,8 +873,17 @@ export const useCourrier = () => {
|
||||
const searchEmails = useCallback((query: string) => {
|
||||
setSearchQuery(query);
|
||||
setPage(1);
|
||||
loadEmails();
|
||||
}, [loadEmails]);
|
||||
|
||||
// CRITICAL FIX: Extract account ID from currentFolder when searching
|
||||
let accountId = 'default';
|
||||
if (currentFolder.includes(':')) {
|
||||
const parts = currentFolder.split(':');
|
||||
accountId = parts[0];
|
||||
}
|
||||
|
||||
// Call loadEmails with the correct account context
|
||||
loadEmails(false, accountId);
|
||||
}, [loadEmails, currentFolder]);
|
||||
|
||||
// Format an email for reply or forward
|
||||
const formatEmailForAction = useCallback((email: Email) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user