From 08767b3b772d88b5eb005735b7cc74fc0e58eacd Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Wed, 4 Nov 2026 11:03:34 +0100 Subject: [PATCH] fix: leave the app's own Trusted Senders book out of the Contacts sidebar --- .../__tests__/contacts-ux-pim.test.tsx | 18 ++++++++++++++++++ components/contacts/contacts-sidebar.tsx | 13 +++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/components/contacts/__tests__/contacts-ux-pim.test.tsx b/components/contacts/__tests__/contacts-ux-pim.test.tsx index 9b743586c..de42bb5d7 100644 --- a/components/contacts/__tests__/contacts-ux-pim.test.tsx +++ b/components/contacts/__tests__/contacts-ux-pim.test.tsx @@ -84,6 +84,24 @@ function renderSidebar(addressBooks: AddressBook[]) { ); } +describe('pim-22: the Contacts sidebar', () => { + it("leaves out the app's own Trusted Senders book, which Settings manages", () => { + const { unmount } = renderSidebar([ + { id: 'b1', name: 'Contacts', isDefault: true } as AddressBook, + { id: 'b2', name: 'Trusted Senders', isDefault: false } as AddressBook, + ]); + expect(screen.getByText('Contacts')).toBeInTheDocument(); + expect(screen.queryByText('Trusted Senders')).toBeNull(); + unmount(); + // Someone else's book with that name is theirs, not the app's list. + renderSidebar([ + { id: 'b1', name: 'Contacts', isDefault: true } as AddressBook, + { id: 'b3', name: 'Trusted Senders', isShared: true, accountId: 'acc-b', accountName: 'b@example.org' } as AddressBook, + ]); + expect(screen.getByText('Trusted Senders')).toBeInTheDocument(); + }); +}); + describe('pim-26: the Contacts menus', () => { it('ends "Import contacts" and "New address book" in "…", as they open a dialog', () => { renderSidebar([{ id: 'b1', name: 'Contacts', isDefault: true } as AddressBook]); diff --git a/components/contacts/contacts-sidebar.tsx b/components/contacts/contacts-sidebar.tsx index 93a387eea..ef249c3bb 100644 --- a/components/contacts/contacts-sidebar.tsx +++ b/components/contacts/contacts-sidebar.tsx @@ -10,7 +10,7 @@ import { useLongPress } from "@/hooks/use-long-press"; import { IconButton } from "@/components/ui/icon-button"; import { cn } from "@/lib/utils"; import type { ContactCard, AddressBook } from "@/lib/jmap/types"; -import { getContactDisplayName } from "@/stores/contact-store"; +import { getContactDisplayName, TRUSTED_SENDERS_BOOK_NAME } from "@/stores/contact-store"; import { useAccountStore } from "@/stores/account-store"; export type ContactCategory = "all" | "directory" | { groupId: string } | { addressBookId: string } | { keyword: string } | "uncategorized"; @@ -90,10 +90,18 @@ function saveCollapsed(state: Record) { } catch { /* ignore */ } } +/** + * The app's own "Trusted Senders" book: the senders whose images load, kept + * and managed in Settings, not a list of people. The sidebar leaves it out. + */ +export function isTrustedSendersBook(book: AddressBook): boolean { + return !book.isShared && book.name === TRUSTED_SENDERS_BOOK_NAME; +} + export function ContactsSidebar({ groups, individuals, - addressBooks, + addressBooks: allAddressBooks, activeCategory, onSelectCategory, onCreateGroup, @@ -119,6 +127,7 @@ export function ContactsSidebar({ const t = useTranslations("contacts"); const tx = useTranslations("ux_pim_contact"); const router = useRouter(); + const addressBooks = useMemo(() => allAddressBooks.filter(b => !isTrustedSendersBook(b)), [allAddressBooks]); const { contextMenu: groupContextMenu, openContextMenu: openGroupContextMenu, openContextMenuFrom: openGroupMenuFrom, closeContextMenu: closeGroupContextMenu, menuRef: groupMenuRef } = useContextMenu(); const { contextMenu: bookContextMenu, openContextMenu: openBookContextMenu, openContextMenuFrom: openBookMenuFrom, closeContextMenu: closeBookContextMenu, menuRef: bookMenuRef } = useContextMenu(); const hasBookMenu = !!(onRenameAddressBook || onShareAddressBook || onSetDefaultAddressBook || onCreateContactInBook || onDeleteAddressBook);