fix: allow adding contacts from mail recipient popover on mobile #306

This commit is contained in:
Linus Rath
2026-05-21 23:23:45 +02:00
parent dbc0eea148
commit 9b22ef810e
20 changed files with 118 additions and 8 deletions
+18 -4
View File
@@ -52,6 +52,8 @@ interface ContactFormProps {
addressBooks?: AddressBook[];
allKeywords?: string[];
defaultAddressBookId?: string;
/** Prefills the create form (ignored when `contact` is set). */
prefill?: { email?: string; name?: string };
onSave: (data: Partial<ContactCard>) => Promise<void>;
onCancel: () => void;
}
@@ -145,10 +147,22 @@ function Select({ value, onChange, children, className }: {
);
}
export function ContactForm({ contact, addressBooks, allKeywords, defaultAddressBookId, onSave, onCancel }: ContactFormProps) {
export function ContactForm({ contact, addressBooks, allKeywords, defaultAddressBookId, prefill, onSave, onCancel }: ContactFormProps) {
const t = useTranslations("contacts.form");
const isEditing = !!contact;
// Split a free-form display name into given/surname for prefill.
const prefillGivenName = (() => {
if (contact || !prefill?.name) return "";
const parts = prefill.name.trim().split(/\s+/);
return parts[0] || "";
})();
const prefillSurname = (() => {
if (contact || !prefill?.name) return "";
const parts = prefill.name.trim().split(/\s+/);
return parts.slice(1).join(" ");
})();
// Accept JSContact-standard kinds (RFC 9553) and legacy vCard-style aliases.
const findComponent = (...kinds: string[]) =>
contact?.name?.components?.find(c => kinds.includes(c.kind))?.value || "";
@@ -215,9 +229,9 @@ export function ContactForm({ contact, addressBooks, allKeywords, defaultAddress
}
const [prefix, setPrefix] = useState(findComponent("title", "prefix"));
const [givenName, setGivenName] = useState(findComponent("given"));
const [givenName, setGivenName] = useState(findComponent("given") || prefillGivenName);
const [additionalName, setAdditionalName] = useState(findComponent("given2", "additional", "middle"));
const [surname, setSurname] = useState(findComponent("surname"));
const [surname, setSurname] = useState(findComponent("surname") || prefillSurname);
const [suffix, setSuffix] = useState(findComponent("generation", "suffix"));
const [nickname, setNickname] = useState(
@@ -231,7 +245,7 @@ export function ContactForm({ contact, addressBooks, allKeywords, defaultAddress
context: e.contexts?.work ? "work" : e.contexts?.private ? "private" : "",
}));
}
return [{ address: "", context: "" }];
return [{ address: prefill?.email || "", context: "" }];
});
const [phones, setPhones] = useState<PhoneEntry[]>(() => {
+27 -1
View File
@@ -65,6 +65,7 @@ import {
PenSquare,
} from "lucide-react";
import { useTranslations } from "next-intl";
import { useRouter } from "@/i18n/navigation";
import type { Attachment as PostalMimeAttachment } from 'postal-mime';
import { useSettingsStore, KEYWORD_PALETTE } from "@/stores/settings-store";
import { useUIStore } from "@/stores/ui-store";
@@ -1137,9 +1138,34 @@ export function EmailViewer({
const [contactSidebarEmail, setContactSidebarEmail] = useState<string | null>(null);
const contacts = useContactStore((s) => s.contacts);
const { isMobile: isMobileDevice } = useDeviceDetection();
const router = useRouter();
const handleViewContactSidebar = (contact: ContactCard | null, recipientEmail: string) => {
if (isMobileDevice) return; // no sidebar on mobile
if (isMobileDevice) {
// No room for a sidebar on mobile — send the user to the contacts page
// with params describing what to show. The `from=email` flag turns the
// page's mobile back button into a router.back() that returns here.
const allRecipients = [
...(email?.from || []),
...(email?.to || []),
...(email?.cc || []),
...(email?.bcc || []),
...(email?.replyTo || []),
];
const recipientName = allRecipients.find(
(r) => r.email.toLowerCase() === recipientEmail.toLowerCase()
)?.name;
const params = new URLSearchParams();
if (contact) {
params.set('contactId', contact.id);
} else {
params.set('addEmail', recipientEmail);
if (recipientName) params.set('addName', recipientName);
}
params.set('from', 'email');
router.push(`/contacts?${params.toString()}`);
return;
}
setContactSidebarEmail(recipientEmail);
};