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}
/>