courrier multi account restore compose
This commit is contained in:
parent
6939ad5e35
commit
eb557d16dd
@ -614,141 +614,6 @@ export const useEmailState = () => {
|
|||||||
}
|
}
|
||||||
}, [session?.user?.id, state.page, state.currentFolder, loadEmails, logEmailOp]);
|
}, [session?.user?.id, state.page, state.currentFolder, loadEmails, logEmailOp]);
|
||||||
|
|
||||||
// Calculate and update unread counts from emails
|
|
||||||
const updateUnreadCounts = useCallback(() => {
|
|
||||||
// This function will count unread emails in each folder and update the unreadCountMap
|
|
||||||
if (state.emails.length === 0) return;
|
|
||||||
|
|
||||||
// Create a temporary count map
|
|
||||||
const tempUnreadMap: Record<string, Record<string, number>> = {};
|
|
||||||
|
|
||||||
// Initialize with existing accounts and folders to avoid losing counts
|
|
||||||
// when switching folders
|
|
||||||
state.accounts.forEach(account => {
|
|
||||||
tempUnreadMap[account.id] = { ...state.unreadCountMap[account.id] || {} };
|
|
||||||
|
|
||||||
// Initialize each folder with 0 if it doesn't exist
|
|
||||||
account.folders.forEach(folder => {
|
|
||||||
// Extract base folder name if it has a prefix
|
|
||||||
const baseFolderName = folder.includes(':') ? folder.split(':')[1] : folder;
|
|
||||||
const prefixedFolder = folder.includes(':') ? folder : `${account.id}:${baseFolderName}`;
|
|
||||||
|
|
||||||
// Initialize both prefixed and unprefixed versions
|
|
||||||
if (tempUnreadMap[account.id][baseFolderName] === undefined) {
|
|
||||||
tempUnreadMap[account.id][baseFolderName] = 0;
|
|
||||||
}
|
|
||||||
if (tempUnreadMap[account.id][prefixedFolder] === undefined) {
|
|
||||||
tempUnreadMap[account.id][prefixedFolder] = 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Count unread emails from current folder
|
|
||||||
state.emails.forEach(email => {
|
|
||||||
// Check if email is unread
|
|
||||||
const isUnread = email.flags && !email.flags.seen;
|
|
||||||
|
|
||||||
// Only count if it's unread
|
|
||||||
if (isUnread && email.accountId) {
|
|
||||||
// Get folder information
|
|
||||||
let folder = email.folder;
|
|
||||||
let accountId = email.accountId;
|
|
||||||
|
|
||||||
// Make sure the account exists in our map
|
|
||||||
if (!tempUnreadMap[accountId]) {
|
|
||||||
tempUnreadMap[accountId] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract folder name if it has a prefix
|
|
||||||
let baseFolderName = folder;
|
|
||||||
if (folder.includes(':')) {
|
|
||||||
const parts = folder.split(':');
|
|
||||||
// Don't override accountId from the folder prefix
|
|
||||||
baseFolderName = parts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure we have entries for both formats
|
|
||||||
if (!tempUnreadMap[accountId][baseFolderName]) {
|
|
||||||
tempUnreadMap[accountId][baseFolderName] = 0;
|
|
||||||
}
|
|
||||||
if (!tempUnreadMap[accountId][folder]) {
|
|
||||||
tempUnreadMap[accountId][folder] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment both formats to ensure they're both available
|
|
||||||
tempUnreadMap[accountId][baseFolderName]++;
|
|
||||||
tempUnreadMap[accountId][folder]++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Store the current update for comparison
|
|
||||||
if (!(window as any).__lastUnreadUpdate) {
|
|
||||||
(window as any).__lastUnreadUpdate = {
|
|
||||||
timestamp: 0,
|
|
||||||
map: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the unread counts have actually changed before updating state
|
|
||||||
let hasChanged = false;
|
|
||||||
|
|
||||||
// Compare with current unread count map
|
|
||||||
Object.entries(tempUnreadMap).forEach(([accountId, folderCounts]) => {
|
|
||||||
Object.entries(folderCounts).forEach(([folder, count]) => {
|
|
||||||
if (state.unreadCountMap[accountId]?.[folder] !== count) {
|
|
||||||
hasChanged = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if we've updated recently
|
|
||||||
const now = Date.now();
|
|
||||||
const lastUpdate = (window as any).__lastUnreadUpdate;
|
|
||||||
const timeSinceLastUpdate = now - lastUpdate.timestamp;
|
|
||||||
|
|
||||||
// If changes found and not updated too recently, update state
|
|
||||||
if (hasChanged && timeSinceLastUpdate > 500) {
|
|
||||||
// Log only on actual change
|
|
||||||
logEmailOp('UNREAD_COUNTS', 'Updated unread counts:', tempUnreadMap);
|
|
||||||
|
|
||||||
// Create a single dispatch to update all counts at once
|
|
||||||
dispatch({
|
|
||||||
type: 'SET_UNREAD_COUNTS',
|
|
||||||
payload: tempUnreadMap
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update timestamp of last update
|
|
||||||
lastUpdate.timestamp = now;
|
|
||||||
lastUpdate.map = tempUnreadMap;
|
|
||||||
}
|
|
||||||
}, [state.emails, state.accounts, state.unreadCountMap, dispatch, logEmailOp]);
|
|
||||||
|
|
||||||
// Call updateUnreadCounts when relevant state changes
|
|
||||||
useEffect(() => {
|
|
||||||
if (!state.emails || state.emails.length === 0) return;
|
|
||||||
|
|
||||||
// Debounce unread count updates to prevent rapid multiple updates
|
|
||||||
let updateTimeoutId: ReturnType<typeof setTimeout>;
|
|
||||||
|
|
||||||
const debounceMs = 500; // 500ms debounce
|
|
||||||
|
|
||||||
// Function to call after debounce period
|
|
||||||
const debouncedUpdate = () => {
|
|
||||||
updateTimeoutId = setTimeout(() => {
|
|
||||||
updateUnreadCounts();
|
|
||||||
}, debounceMs);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clear any existing timeout and start a new one
|
|
||||||
debouncedUpdate();
|
|
||||||
|
|
||||||
// Cleanup timeout on unmount or state change
|
|
||||||
return () => {
|
|
||||||
clearTimeout(updateTimeoutId);
|
|
||||||
};
|
|
||||||
// Deliberately exclude unreadCountMap to prevent infinite loops
|
|
||||||
}, [state.emails, updateUnreadCounts]);
|
|
||||||
|
|
||||||
// Fetch unread counts from API
|
// Fetch unread counts from API
|
||||||
const fetchUnreadCounts = useCallback(async () => {
|
const fetchUnreadCounts = useCallback(async () => {
|
||||||
// Don't fetch if user is not logged in
|
// Don't fetch if user is not logged in
|
||||||
@ -827,7 +692,59 @@ export const useEmailState = () => {
|
|||||||
dispatch({ type: 'SET_LOADING_UNREAD_COUNTS', payload: false });
|
dispatch({ type: 'SET_LOADING_UNREAD_COUNTS', payload: false });
|
||||||
}
|
}
|
||||||
}, [dispatch, session?.user, state.isLoadingUnreadCounts, logEmailOp]);
|
}, [dispatch, session?.user, state.isLoadingUnreadCounts, logEmailOp]);
|
||||||
|
|
||||||
|
// Calculate and update unread counts
|
||||||
|
const updateUnreadCounts = useCallback(() => {
|
||||||
|
// Skip if no emails or accounts
|
||||||
|
if (state.emails.length === 0 || state.accounts.length === 0) return;
|
||||||
|
|
||||||
|
// To avoid running this too frequently, check the timestamp of last update
|
||||||
|
if (!(window as any).__lastUnreadUpdate) {
|
||||||
|
(window as any).__lastUnreadUpdate = { timestamp: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const lastUpdate = (window as any).__lastUnreadUpdate;
|
||||||
|
const MIN_UPDATE_INTERVAL = 2000; // 2 seconds minimum between updates
|
||||||
|
|
||||||
|
if (now - lastUpdate.timestamp < MIN_UPDATE_INTERVAL) {
|
||||||
|
return; // Skip if updated too recently
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rather than calculating locally, let's fetch from the API
|
||||||
|
// This ensures we get accurate server-side counts
|
||||||
|
fetchUnreadCounts();
|
||||||
|
|
||||||
|
// Update timestamp of last update
|
||||||
|
lastUpdate.timestamp = now;
|
||||||
|
}, [state.emails.length, state.accounts.length, fetchUnreadCounts]);
|
||||||
|
|
||||||
|
// Call updateUnreadCounts when relevant state changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (!state.emails || state.emails.length === 0) return;
|
||||||
|
|
||||||
|
// Debounce unread count updates to prevent rapid multiple updates
|
||||||
|
let updateTimeoutId: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
|
const debounceMs = 2000; // Increase debounce to 2 seconds
|
||||||
|
|
||||||
|
// Function to call after debounce period
|
||||||
|
const debouncedUpdate = () => {
|
||||||
|
updateTimeoutId = setTimeout(() => {
|
||||||
|
updateUnreadCounts();
|
||||||
|
}, debounceMs);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Clear any existing timeout and start a new one
|
||||||
|
debouncedUpdate();
|
||||||
|
|
||||||
|
// Cleanup timeout on unmount or state change
|
||||||
|
return () => {
|
||||||
|
clearTimeout(updateTimeoutId);
|
||||||
|
};
|
||||||
|
// Deliberately exclude unreadCountMap to prevent infinite loops
|
||||||
|
}, [state.emails, updateUnreadCounts]);
|
||||||
|
|
||||||
// Tracking when an email is viewed to optimize unread count refreshes
|
// Tracking when an email is viewed to optimize unread count refreshes
|
||||||
const lastViewedEmailRef = useRef<number | null>(null);
|
const lastViewedEmailRef = useRef<number | null>(null);
|
||||||
const fetchFailuresRef = useRef<number>(0);
|
const fetchFailuresRef = useRef<number>(0);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user