diff --git a/components/contacts/__tests__/contact-list.test.tsx b/components/contacts/__tests__/contact-list.test.tsx index 2f1c9c8db..915a1e3f8 100644 --- a/components/contacts/__tests__/contact-list.test.tsx +++ b/components/contacts/__tests__/contact-list.test.tsx @@ -183,4 +183,14 @@ describe('ContactList', () => { }); }); + + it("writes to a contact from the right-click menu in the app's composer, not through mailto:", () => { + const onComposeContact = vi.fn(); + const href = window.location.href; + render(); + fireEvent.contextMenu(screen.getByText('Alice Smith')); + fireEvent.click(screen.getByText('context_menu.send_email')); + expect(onComposeContact).toHaveBeenCalledWith(alice); + expect(window.location.href).toBe(href); + }); }); diff --git a/components/contacts/contact-context-menu.tsx b/components/contacts/contact-context-menu.tsx index d8c85ec68..67c445e5e 100644 --- a/components/contacts/contact-context-menu.tsx +++ b/components/contacts/contact-context-menu.tsx @@ -47,6 +47,8 @@ interface ContactContextMenuProps { onEdit: () => void; onDelete: () => void; onAddToGroup: () => void; + /** Writes to the contact in the app's composer. */ + onCompose?: () => void; onDuplicate?: () => void; onBatchExport?: () => void; onBatchAddToGroup?: () => void; @@ -65,6 +67,7 @@ export function ContactContextMenu({ onEdit, onDelete, onAddToGroup, + onCompose, onDuplicate, onBatchExport, onBatchAddToGroup, @@ -81,11 +84,6 @@ export function ContactContextMenu({ onClose(); }; - const handleSendEmail = () => { - if (!email) return; - window.location.href = `mailto:${email}`; - }; - const handleCall = () => { if (!phone) return; window.location.href = `tel:${phone}`; @@ -146,11 +144,11 @@ export function ContactContextMenu({ {(email || phone) && } - {email && ( + {email && onCompose && ( )} {phone && ( diff --git a/components/contacts/contact-list.tsx b/components/contacts/contact-list.tsx index f736593a7..0428cc0b5 100644 --- a/components/contacts/contact-list.tsx +++ b/components/contacts/contact-list.tsx @@ -114,6 +114,8 @@ interface ContactListProps { onEditContact: (id: string) => void; onDeleteContact: (contact: ContactCard) => void; onAddContactToGroup: (id: string) => void; + /** Opens the app's composer to the contact. */ + onComposeContact?: (contact: ContactCard) => void; /** Show a burger button at the start that opens the (overlay) categories sidebar. */ onMenuClick?: () => void; /** The first fetch is still running: show placeholders, not "No contacts yet". */ @@ -139,6 +141,7 @@ export function ContactList({ onEditContact, onDeleteContact, onAddContactToGroup, + onComposeContact, onMenuClick, isLoading = false, }: ContactListProps) { @@ -650,6 +653,7 @@ export function ContactList({ onEdit={() => onEditContact(contextMenu.data!.id)} onDelete={() => onDeleteContact(contextMenu.data!)} onAddToGroup={() => onAddContactToGroup(contextMenu.data!.id)} + onCompose={onComposeContact ? () => onComposeContact(contextMenu.data!) : undefined} onBatchExport={onBulkExport} onBatchAddToGroup={onBulkAddToGroup} onBatchDelete={onBulkDelete} diff --git a/components/contacts/contacts-app.tsx b/components/contacts/contacts-app.tsx index 17795efe8..00022db5b 100644 --- a/components/contacts/contacts-app.tsx +++ b/components/contacts/contacts-app.tsx @@ -1199,6 +1199,7 @@ function ContactsAppContent({ linkSegments: routeSegments }: ContactsAppProps = onEditContact={guard(handleEditContact)} onDeleteContact={handleDeleteContact} onAddContactToGroup={guard(handleAddContactToGroup)} + onComposeContact={handleComposeContact} onMenuClick={isNarrow ? () => setNarrowSidebarOpen(true) : undefined} isLoading={supportsSync && !contactsLoaded} />