'use client'; // Native tab strip for plugin-registered message-list category tabs // (Gmail-style Primary / Promotions / Social / Updates). Renders above the // email list; the active tab's resolved JMAP filter is ANDed into the // mailbox query by email-store.fetchEmails. Plugins only contribute tab // DEFINITIONS (stores/message-list-tabs-store.ts) - no plugin iframe here. import { useEffect, useRef } from 'react'; import { icons as lucideIcons, type LucideIcon } from 'lucide-react'; import { useMessageListTabsStore } from '@/stores/message-list-tabs-store'; import { useEmailStore } from '@/stores/email-store'; import { useAuthStore } from '@/stores/auth-store'; import { cn } from '@/lib/utils'; export function MessageListTabs() { const tabs = useMessageListTabsStore((s) => s.tabs); const mailboxRoles = useMessageListTabsStore((s) => s.mailboxRoles); const activeTabId = useMessageListTabsStore((s) => s.activeTabId); const tabCounts = useMessageListTabsStore((s) => s.tabCounts); const selectedMailbox = useEmailStore((s) => s.selectedMailbox); const mailboxes = useEmailStore((s) => s.mailboxes); const selectedKeyword = useEmailStore((s) => s.selectedKeyword); const searchQuery = useEmailStore((s) => s.searchQuery); const isUnifiedView = useEmailStore((s) => s.isUnifiedView); const client = useAuthStore((s) => s.client); const mailbox = mailboxes.find((mb) => mb.id === selectedMailbox); const role = mailbox?.role?.toLowerCase() ?? null; // Tabs only make sense on a plain mailbox view: tag views, searches and // unified fan-outs bypass the category filter in fetchEmails, so the strip // must disappear rather than lie about what's being shown. const visible = tabs.length > 0 && !!role && mailboxRoles.includes(role) && !selectedKeyword && !searchQuery && !isUnifiedView; useEffect(() => { if (!visible || !client || !mailbox) return; const jmapMailboxId = mailbox.originalId || mailbox.id; const accountId = mailbox.isShared ? mailbox.accountId : undefined; void useMessageListTabsStore.getState().refreshCounts(client, jmapMailboxId, accountId); // eslint-disable-next-line react-hooks/exhaustive-deps }, [visible, client, selectedMailbox, tabs]); // A plugin registering (or clearing) tabs after the list was fetched leaves // the visible list out of sync with the strip's active-tab filter - refetch // exactly when the merged tab set changes, never on ordinary view switches // (those already refetch through their own flows). const prevTabsRef = useRef(tabs); useEffect(() => { if (prevTabsRef.current === tabs) return; prevTabsRef.current = tabs; if (client) void useEmailStore.getState().fetchEmails(client); }, [tabs, client]); if (!visible) return null; const handleSelect = (tabId: string) => { if (tabId === activeTabId) return; useMessageListTabsStore.getState().setActiveTab(tabId, selectedMailbox); if (client) void useEmailStore.getState().fetchEmails(client); }; return (