feat: allow contact cards for organizations #701
This commit is contained in:
@@ -445,6 +445,48 @@ describe("generateVCard", () => {
|
||||
const vcf = generateVCard([contact]);
|
||||
expect(vcf).toContain("NOTE:Has comma\\, semicolon\\; and newline\\nhere");
|
||||
});
|
||||
|
||||
it("uses the organization name as FN for organization cards (issue #701)", () => {
|
||||
const contact: ContactCard = {
|
||||
id: "c4",
|
||||
addressBookIds: {},
|
||||
kind: "org",
|
||||
name: { full: "Acme Corp" },
|
||||
organizations: { o0: { name: "Acme Corp" } },
|
||||
};
|
||||
|
||||
const vcf = generateVCard([contact]);
|
||||
expect(vcf).toContain("KIND:org");
|
||||
expect(vcf).toContain("FN:Acme Corp");
|
||||
expect(vcf).toContain("ORG:Acme Corp");
|
||||
});
|
||||
|
||||
it("falls back to ORG for FN when the card has no name at all", () => {
|
||||
const contact: ContactCard = {
|
||||
id: "c5",
|
||||
addressBookIds: {},
|
||||
kind: "org",
|
||||
organizations: { o0: { name: "Acme Corp" } },
|
||||
};
|
||||
|
||||
expect(generateVCard([contact])).toContain("FN:Acme Corp");
|
||||
});
|
||||
});
|
||||
|
||||
describe("organization-only cards (issue #701)", () => {
|
||||
it("keeps a vCard that has only an organization name", () => {
|
||||
const parsed = parseVCard([
|
||||
"BEGIN:VCARD",
|
||||
"VERSION:4.0",
|
||||
"KIND:org",
|
||||
"ORG:Acme Corp",
|
||||
"END:VCARD",
|
||||
].join("\r\n"));
|
||||
|
||||
expect(parsed).toHaveLength(1);
|
||||
expect(parsed[0].kind).toBe("org");
|
||||
expect(parsed[0].organizations?.o0.name).toBe("Acme Corp");
|
||||
});
|
||||
});
|
||||
|
||||
describe("round-trip: parse → generate → parse", () => {
|
||||
|
||||
+8
-2
@@ -844,7 +844,9 @@ function buildContact(raw: Record<string, string[]>): ContactCard | null {
|
||||
|
||||
const hasName = card.name && (card.name.components?.length ?? 0) > 0 || !!card.name?.full;
|
||||
const hasEmail = card.emails && Object.keys(card.emails).length > 0;
|
||||
if (!hasName && !hasEmail && card.kind !== "group") return null;
|
||||
// An organization name identifies the card just as well as a personal name.
|
||||
const hasOrg = !!Object.values(card.organizations || {})[0]?.name;
|
||||
if (!hasName && !hasEmail && !hasOrg && card.kind !== "group") return null;
|
||||
|
||||
return card;
|
||||
}
|
||||
@@ -882,7 +884,11 @@ function generateSingleVCard(contact: ContactCard): string {
|
||||
const suffix = findKind("generation", "suffix");
|
||||
const additional = findKind("given2", "additional", "middle");
|
||||
|
||||
const fn = [prefix, given, additional, surname, suffix].filter(Boolean).join(" ") || contact.name?.full || "";
|
||||
// FN is mandatory in vCard, so fall back to the organization name for org cards.
|
||||
const fn = [prefix, given, additional, surname, suffix].filter(Boolean).join(" ")
|
||||
|| contact.name?.full
|
||||
|| Object.values(contact.organizations || {})[0]?.name
|
||||
|| "";
|
||||
if (fn) {
|
||||
lines.push(`FN:${encodeValue(fn)}`);
|
||||
lines.push(`N:${encodeValue(surname)};${encodeValue(given)};${encodeValue(additional)};${encodeValue(prefix)};${encodeValue(suffix)}`);
|
||||
|
||||
Reference in New Issue
Block a user