fix: frontend race condition — folder sync callback was reloading wrong folder

- When user switches folders quickly, syncFolder(A) callback fires after user already selected B
- loadMails() was called with stale selectedFolderId, loading wrong mails
- Add useRef to track current folder ID, only reload if still on same folder
- Also fix backend: message_id dedup now only within same folder (not cross-folder)
This commit is contained in:
Agent Zero
2026-07-20 14:07:26 +02:00
parent 4acebe55e5
commit 9946c6c4bd
+12 -3
View File
@@ -4,7 +4,7 @@
* Account selection is integrated into the folder tree (left pane). * Account selection is integrated into the folder tree (left pane).
*/ */
import React, { useState, useEffect, useCallback } from 'react'; import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Card } from '@/components/ui/Card'; import { Card } from '@/components/ui/Card';
@@ -82,6 +82,12 @@ export function MailPage() {
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc'); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
const [isSyncing, setIsSyncing] = useState(false); const [isSyncing, setIsSyncing] = useState(false);
// Ref to track the current folder ID for async callbacks (prevents race conditions)
const selectedFolderIdRef = useRef<string | null>(null);
useEffect(() => {
selectedFolderIdRef.current = selectedFolderId;
}, [selectedFolderId]);
// Load accounts // Load accounts
const loadAccounts = useCallback(async () => { const loadAccounts = useCallback(async () => {
setLoadingAccounts(true); setLoadingAccounts(true);
@@ -183,9 +189,12 @@ export function MailPage() {
setSelectedMailIds(new Set()); setSelectedMailIds(new Set());
setActiveView('list'); setActiveView('list');
// Live sync: fetch new mails from IMAP in background, reload after // Live sync: fetch new mails from IMAP in background, reload after
// Only reload if the user hasn't switched to another folder in the meantime
syncFolder(folderId).then(() => { syncFolder(folderId).then(() => {
loadMails(); if (selectedFolderIdRef.current === folderId) {
loadAllFolders(); loadMails();
loadAllFolders();
}
}).catch(() => {}); }).catch(() => {});
}, },
[folders, loadMails, loadAllFolders], [folders, loadMails, loadAllFolders],