fix: open the composer from a contact's right-click Send email instead of leaving the app

This commit is contained in:
Linus Rath
2026-10-28 03:08:21 +01:00
parent 5447c40b7b
commit 2e86f7af07
4 changed files with 20 additions and 7 deletions
@@ -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(<ContactList {...defaultProps} onComposeContact={onComposeContact} />);
fireEvent.contextMenu(screen.getByText('Alice Smith'));
fireEvent.click(screen.getByText('context_menu.send_email'));
expect(onComposeContact).toHaveBeenCalledWith(alice);
expect(window.location.href).toBe(href);
});
});
+5 -7
View File
@@ -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({
<ContextMenuItem icon={Eye} label={t("context_menu.open")} onClick={handle(onOpen)} />
<ContextMenuItem icon={Pencil} label={t("context_menu.edit")} onClick={handle(onEdit)} />
{(email || phone) && <ContextMenuSeparator />}
{email && (
{email && onCompose && (
<ContextMenuItem
icon={Mail}
label={t("context_menu.send_email")}
onClick={handle(handleSendEmail)}
onClick={handle(onCompose)}
/>
)}
{phone && (
+4
View File
@@ -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}
+1
View File
@@ -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}
/>