Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / shared / lib / contacts / surgery.ts
blob96cbfaa09cebf01e99892bef87d443ec7a912e29
1 import { isValid } from 'date-fns';
2 import { c } from 'ttag';
4 import isTruthy from '@proton/utils/isTruthy';
6 import type { VCardContact, VCardProperty } from '../interfaces/contacts/VCard';
7 import {
8     FIELDS_WITH_PREF,
9     compareVCardPropertyByPref,
10     createContactPropertyUid,
11     fromVCardProperties,
12     generateNewGroupName,
13     getVCardProperties,
14 } from './properties';
16 export const getFallbackFNValue = () => {
17     return c('Default display name vcard').t`Unknown`;
20 export const prepareForEdition = (vCardContact: VCardContact) => {
21     const result = { ...vCardContact };
23     if (!result.fn || result.fn.length === 0) {
24         result.fn = [{ field: 'fn', value: '', uid: createContactPropertyUid() }];
25     }
27     if (!result.photo || result.photo.length === 0) {
28         result.photo = [{ field: 'photo', value: '', uid: createContactPropertyUid() }];
29     }
31     if (!result.email || result.email.length === 0) {
32         result.email = [{ field: 'email', value: '', uid: createContactPropertyUid() }];
33     }
35     if (!result.n) {
36         result.n = {
37             field: 'n',
38             value: {
39                 familyNames: [''],
40                 givenNames: [''],
41                 additionalNames: [''],
42                 honorificPrefixes: [''],
43                 honorificSuffixes: [''],
44             },
45             uid: createContactPropertyUid(),
46         };
47     }
49     return result;
52 export const prepareForSaving = (vCardContact: VCardContact) => {
53     const properties = getVCardProperties(vCardContact);
54     const newProperties = properties.filter((property) => {
55         if (property.field === 'adr') {
56             return property.value && Object.values(property.value).some(isTruthy);
57         }
58         if (property.field === 'bday' || property.field === 'aniversary') {
59             return property.value.text || (property.value.date && isValid(property.value.date));
60         }
61         if (property.field === 'gender') {
62             return isTruthy(property.value?.text);
63         }
64         return isTruthy(property.value);
65     });
66     const result = fromVCardProperties(newProperties);
68     if (result.categories) {
69         // Array-valued categories pose problems to ICAL (even though a vcard with CATEGORIES:ONE,TWO
70         // will be parsed into a value ['ONE', 'TWO'], ICAL.js fails to transform it back). So we convert
71         // an array-valued category into several properties
72         result.categories = result.categories.flatMap((category) => {
73             if (Array.isArray(category.value)) {
74                 return category.value.map((value) => ({ ...category, value }));
75             } else {
76                 return [category];
77             }
78         });
79     }
81     // Add `pref` to email, adr, tel, key to save order
82     (FIELDS_WITH_PREF as (keyof VCardContact)[]).forEach((field) => {
83         if (result[field] && result[field]) {
84             result[field] = (result[field] as VCardProperty[])
85                 .sort(compareVCardPropertyByPref)
86                 .map((property, index) => ({ ...property, params: { ...property.params, pref: index + 1 } })) as any;
87         }
88     });
90     // Add `group` if missing for email.
91     if (result.email) {
92         const existingGroups = result.email.map(({ group }) => group).filter(isTruthy);
94         result.email = result.email.map((property) => {
95             if (property.group) {
96                 return property;
97             } else {
98                 const group = generateNewGroupName(existingGroups);
99                 existingGroups.push(group);
100                 return { ...property, group };
101             }
102         });
103     }
105     return result;
109  * Some contacts might miss the "FN" property, but we expect one for the vCard to be valid.
110  * In that case, use the contact email as FN instead.
111  * If no email is found, return undefined
112  */
113 export const getSupportedContactName = (contact: VCardContact) => {
114     return contact.email?.[0]?.value;