From 083bb1f6bc103a6693040cc0da9d475c67d0b05a Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Wed, 28 Oct 2026 05:04:13 +0100 Subject: [PATCH] fix: put New group, Import and Refresh in the phone header menu of Contacts and Files --- components/contacts/__tests__/contacts-app.test.tsx | 13 +++++++++++++ components/contacts/contact-list.tsx | 5 ++++- components/contacts/contacts-app.tsx | 8 ++++++++ components/files/files-header.tsx | 8 +++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/components/contacts/__tests__/contacts-app.test.tsx b/components/contacts/__tests__/contacts-app.test.tsx index 6e21e3ee7..f373cbb39 100644 --- a/components/contacts/__tests__/contacts-app.test.tsx +++ b/components/contacts/__tests__/contacts-app.test.tsx @@ -211,4 +211,17 @@ describe('ContactsApp', () => { act(() => { contacts!.commands.find((c) => c.id === 'new-contact')!.run(); }); expect(screen.getByPlaceholderText('middle_name')).toBeInTheDocument(); }); + + it('puts New group and Import in the phone header menu', () => { + const matchMedia = window.matchMedia; + window.matchMedia = ((query: string) => ({ ...matchMedia(query), matches: query.includes('max-width') })) as typeof window.matchMedia; + try { + renderContacts(); + fireEvent.click(screen.getByRole('button', { name: 'more' })); + fireEvent.click(screen.getByText('import.title')); + expect(screen.getByRole('dialog', { name: 'import.title' })).toBeInTheDocument(); + } finally { + window.matchMedia = matchMedia; + } + }); }); diff --git a/components/contacts/contact-list.tsx b/components/contacts/contact-list.tsx index c597bfa87..fa1bb9263 100644 --- a/components/contacts/contact-list.tsx +++ b/components/contacts/contact-list.tsx @@ -123,6 +123,8 @@ interface ContactListProps { onMoveContacts?: (ids: string[]) => void; /** Show a burger button at the start that opens the (overlay) categories sidebar. */ onMenuClick?: () => void; + /** Contacts' own entries in the phone header's ⋮. */ + phoneMenuItems?: (close: () => void) => React.ReactNode; /** The first fetch is still running: show placeholders, not "No contacts yet". */ isLoading?: boolean; } @@ -150,6 +152,7 @@ export function ContactList({ onDuplicateContact, onMoveContacts, onMenuClick, + phoneMenuItems, isLoading = false, }: ContactListProps) { const t = useTranslations("contacts"); @@ -439,7 +442,7 @@ export function ContactList({ )} - + diff --git a/components/contacts/contacts-app.tsx b/components/contacts/contacts-app.tsx index 25e1de47a..7012590b2 100644 --- a/components/contacts/contacts-app.tsx +++ b/components/contacts/contacts-app.tsx @@ -6,6 +6,7 @@ import { useSearchParams } from "next/navigation"; import { useRouter } from "@/i18n/navigation"; import { ArrowLeft, Users, UsersRound, AlertTriangle, Plus, UserPlus, Upload, BookPlus } from "@/components/icons"; import { Button } from "@/components/ui/button"; +import { ContextMenuItem } from "@/components/ui/context-menu"; import { ConfirmDialog } from "@/components/ui/confirm-dialog"; import { useConfirmDialog } from "@/hooks/use-confirm-dialog"; import { ContactList } from "@/components/contacts/contact-list"; @@ -1293,6 +1294,13 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps = onDuplicateContact={(contact) => void handleDuplicateContact(contact)} onMoveContacts={canMoveContacts ? handleMoveContacts : undefined} onMenuClick={isNarrow ? () => setNarrowSidebarOpen(true) : undefined} + phoneMenuItems={(close) => ( + // On the phone these are otherwise only in the drawer's "+". + <> + { close(); guard(handleCreateGroup)(); }} /> + { close(); setShowImportDialog(true); }} /> + + )} isLoading={supportsSync && !contactsLoaded} /> )} diff --git a/components/files/files-header.tsx b/components/files/files-header.tsx index 1c865fcdf..23bfc4849 100644 --- a/components/files/files-header.tsx +++ b/components/files/files-header.tsx @@ -367,7 +367,13 @@ export function FilesHeader({ )} - + ( + // The phone header has no room for Refresh as a button. + { close(); onRefresh(); }} disabled={isLoading} /> + )} + /> )}