diff --git a/apps/web/src/pages/mail.tsx b/apps/web/src/pages/mail.tsx index 43e8358..e9c8980 100644 --- a/apps/web/src/pages/mail.tsx +++ b/apps/web/src/pages/mail.tsx @@ -99,6 +99,7 @@ export function MailPage() { const [mailFilter, setMailFilter] = React.useState("all") const [selectedMailboxId, setSelectedMailboxId] = React.useState(() => localStorage.getItem("lanqin:selected-mailbox") || "") const [selectedExternalAccountId, setSelectedExternalAccountId] = React.useState("") + const [expandedExternalAccountIds, setExpandedExternalAccountIds] = React.useState([]) const [externalFolder, setExternalFolder] = React.useState("INBOX") const [darkMode, setDarkMode] = React.useState(getInitialTheme) const [displayMode] = useDisplayMode() @@ -164,8 +165,16 @@ export function MailPage() { React.useEffect(() => { if (externalImapEnabled) return setSelectedExternalAccountId("") + setExpandedExternalAccountIds([]) if (mailView === "external") setMailView("folder") }, [externalImapEnabled, mailView]) + React.useEffect(() => { + const ids = new Set((externalMailAccounts.data?.items || []).map((item) => item.id)) + setExpandedExternalAccountIds((current) => { + const next = current.filter((id) => ids.has(id)) + return next.length === current.length ? current : next + }) + }, [externalMailAccounts.data?.items]) const inboxProbe = useQuery({ queryKey: ["mail-notifications", activeMailboxId], queryFn: () => api.messages("Inbox", "", "", activeMailboxId), @@ -761,6 +770,7 @@ export function MailPage() { } function openExternalFolder(account: ExternalImapAccount, folderName = "INBOX") { setSelectedExternalAccountId(account.id) + setExpandedExternalAccountIds([account.id]) setExternalFolder(folderName) setMailView("external") setSelectedLabelId("") @@ -768,6 +778,21 @@ export function MailPage() { setMailFilter("all") setMobileSidebarOpen(false) } + function toggleExternalAccount(account: ExternalImapAccount) { + if (sidebarCollapsed) { + openExternalFolder(account, "INBOX") + return + } + const expanded = expandedExternalAccountIds.includes(account.id) + if (expanded) { + setExpandedExternalAccountIds((items) => items.filter((id) => id !== account.id)) + return + } + setExpandedExternalAccountIds([account.id]) + if (selectedExternalAccountId !== account.id || mailView !== "external") { + openExternalFolder(account, "INBOX") + } + } function reorderCustomFolder(draggedId: string, target: FolderDropTarget) { if (!canOrganizeMail || reorderFolders.isPending) return const foldersByID = new Map((folders.data?.items || []).map((item) => [item.id, item])) @@ -1041,20 +1066,31 @@ export function MailPage() { {!sidebarCollapsed && 外部邮箱} - {externalAccountItems.map((account) => ( + {externalAccountItems.map((account) => { + const expanded = expandedExternalAccountIds.includes(account.id) + return ( openExternalFolder(account, "INBOX")} + title={`${externalAccountLabel(account)}${account.name && account.name !== externalAccountLabel(account) ? ` · ${account.name}` : ""}`} + onClick={() => toggleExternalAccount(account)} > - {!sidebarCollapsed && {account.name}} - {!sidebarCollapsed && {account.storageMode === "local" ? "同步" : "直连"}} + {!sidebarCollapsed && ( + <> + + {externalAccountLabel(account)} + {externalAccountSubtitle(account)} + + + + )} - {!sidebarCollapsed && mailView === "external" && selectedExternalAccountId === account.id && externalFolderItems.map((item) => ( + {!sidebarCollapsed && expanded && externalFolderItems.map((item) => ( ))} + {!sidebarCollapsed && expanded && externalFolders.isLoading && } - ))} + )})} } @@ -1558,6 +1595,17 @@ function getEmptyMessage(mailView: MailView, folder: string, total: number) { return "当前文件夹没有邮件" } +function externalAccountLabel(account: ExternalImapAccount) { + return account.oauthEmail || account.username || account.name || "外部邮箱" +} + +function externalAccountSubtitle(account: ExternalImapAccount) { + const label = externalAccountLabel(account) + const mode = account.storageMode === "local" ? "同步" : "直连" + const name = account.name && account.name !== label ? account.name : "" + return [name, account.host, mode].filter(Boolean).join(" · ") +} + function NoMailboxState({ onOpenSettings }: { onOpenSettings: () => void }) { return (