/** * Manages per-account state snapshots for fast switching. * When user switches from Account A → B, we snapshot A's store state * into memory, clear stores, then restore B's cached state. */ import { useEmailStore } from '@/stores/email-store'; import { useContactStore } from '@/stores/contact-store'; import { useCalendarStore } from '@/stores/calendar-store'; import { useFilterStore } from '@/stores/filter-store'; import { DEFAULT_SEARCH_FILTERS } from '@/lib/jmap/search-utils'; import { useIdentityStore } from '@/stores/identity-store'; import { useVacationStore } from '@/stores/vacation-store'; import { useMessageListTabsStore } from '@/stores/message-list-tabs-store'; import { useTaskStore } from '@/stores/task-store'; export interface StoreSnapshot { snapshot: () => Partial; clear: () => Partial; } // eslint-disable-next-line @typescript-eslint/no-explicit-any type StoreData = Record; interface AccountSnapshot { email: StoreData; contact: StoreData; calendar: StoreData; filter: StoreData; identity: StoreData; vacation: StoreData; messageListTabs: StoreData; tasks: StoreData; } const cache = new Map(); /** Capture current store states for the given account */ export function snapshotAccount(accountId: string): void { const emailState = useEmailStore.getState(); const contactState = useContactStore.getState(); const calendarState = useCalendarStore.getState(); const filterState = useFilterStore.getState(); const identityState = useIdentityStore.getState(); const vacationState = useVacationStore.getState(); const messageListTabsState = useMessageListTabsStore.getState(); const taskState = useTaskStore.getState(); cache.set(accountId, { email: { emails: [...emailState.emails], mailboxes: [...emailState.mailboxes], selectedEmail: emailState.selectedEmail, selectedMailbox: emailState.selectedMailbox, searchQuery: emailState.searchQuery, quota: emailState.quota ? { ...emailState.quota } : emailState.quota, }, contact: { contacts: [...contactState.contacts], addressBooks: [...contactState.addressBooks], supportsSync: contactState.supportsSync, }, calendar: { calendars: [...calendarState.calendars], events: [...calendarState.events], selectedCalendarIds: [...calendarState.selectedCalendarIds], viewMode: calendarState.viewMode, supportsCalendar: calendarState.supportsCalendar, }, filter: { rules: [...filterState.rules], isSupported: filterState.isSupported, }, identity: { identities: [...identityState.identities], preferredPrimaryId: identityState.preferredPrimaryId, }, vacation: { isEnabled: vacationState.isEnabled, isSupported: vacationState.isSupported, }, messageListTabs: { registrations: { ...messageListTabsState.registrations }, tabs: [...messageListTabsState.tabs], activeTabId: messageListTabsState.activeTabId, }, tasks: { tasks: [...taskState.tasks], selectedTaskId: taskState.selectedTaskId, filter: taskState.filter, showCompleted: taskState.showCompleted, }, }); } /** * Restore cached store states for the given account. Returns false if no cache * exists. * * The snapshot only captures a subset of each store's fields (the loaded data), * so we reset every store to its baseline first. Without this, fields outside * the captured subset (e.g. email selection, loading flags, tag counts) would * carry over from whatever account was active, leaking state across accounts. * `setState` merges, so the captured fields are then layered back on top. */ export function restoreAccount(accountId: string): boolean { const snapshot = cache.get(accountId); if (!snapshot) return false; clearAllStores(); useEmailStore.setState(snapshot.email); useContactStore.setState(snapshot.contact); useCalendarStore.setState(snapshot.calendar); useFilterStore.setState(snapshot.filter); useIdentityStore.setState(snapshot.identity); useVacationStore.setState(snapshot.vacation); useMessageListTabsStore.setState(snapshot.messageListTabs); useTaskStore.setState(snapshot.tasks); return true; } /** Clear all stores (used before restoring a different account) */ export function clearAllStores(): void { useEmailStore.setState({ emails: [], mailboxes: [], selectedEmail: null, selectedMailbox: '', isLoading: false, error: null, searchQuery: '', quota: null, isPushConnected: false, lastPushUpdate: null, newEmailNotification: null, selectedEmailIds: new Set(), hasMoreEmails: false, totalEmails: 0, expandedThreadIds: new Set(), threadEmailsCache: new Map(), isLoadingThread: null, selectedKeyword: null, tagCounts: {}, searchFilters: { ...DEFAULT_SEARCH_FILTERS }, isAdvancedSearchOpen: false, }); useIdentityStore.getState().clearIdentities(); useContactStore.getState().clearContacts(); useVacationStore.getState().clearState(); useCalendarStore.getState().clearState(); useFilterStore.getState().clearState(); useMessageListTabsStore.getState().clearState(); useTaskStore.getState().clearTasks(); } /** Evict cached state for one account */ export function evictAccount(accountId: string): void { cache.delete(accountId); } /** Evict all cached states */ export function evictAll(): void { cache.clear(); }