Update all non-major dependencies
[ProtonMail-WebClient.git] / applications / calendar / src / app / helpers / sendPreferences.ts
blob24ff02b2d5811185dbd30a10dbcbd9309e352e70
1 import { reformatApiErrorMessage } from '@proton/shared/lib/calendar/api';
2 import { getAttendeeEmail } from '@proton/shared/lib/calendar/attendees';
3 import { getHasRecurrenceId } from '@proton/shared/lib/calendar/vcalHelper';
4 import type { SimpleMap } from '@proton/shared/lib/interfaces';
5 import type { VcalVeventComponent } from '@proton/shared/lib/interfaces/calendar';
7 import type { AugmentedSendPreferences } from '../containers/calendar/interface';
8 import type { InviteActions } from '../interfaces/Invite';
9 import { INVITE_ACTION_TYPES } from '../interfaces/Invite';
11 const { CHANGE_PARTSTAT, DECLINE_INVITATION, NONE, SEND_INVITATION, CANCEL_INVITATION, SEND_UPDATE } =
12     INVITE_ACTION_TYPES;
14 export const getCleanSendDataFromSendPref = ({
15     emailsWithError,
16     sendPreferencesMap,
17     inviteActions,
18     vevent,
19     cancelVevent,
20 }: {
21     sendPreferencesMap: SimpleMap<AugmentedSendPreferences>;
22     inviteActions: InviteActions;
23     vevent: VcalVeventComponent;
24     cancelVevent?: VcalVeventComponent;
25     emailsWithError: string[];
26 }) => {
27     const { type, addedAttendees = [], removedAttendees = [] } = inviteActions;
28     const hasAddedAttendees = !!addedAttendees.length;
29     const hasRemovedAttendees = !!removedAttendees.length;
30     const addedCleanAttendees = addedAttendees.filter(
31         (attendee) => !emailsWithError.includes(getAttendeeEmail(attendee))
32     );
33     const invitedEmails = (vevent?.attendee || []).map((attendee) => getAttendeeEmail(attendee));
34     const addedEmails = addedAttendees.map((attendee) => getAttendeeEmail(attendee));
35     const addedEmailsWithError = addedEmails.filter((email) => emailsWithError.includes(email));
36     const existingEmails = invitedEmails.filter((email) => !addedEmails.includes(email));
37     const removedCleanAttendees = removedAttendees.filter(
38         (attendee) => !emailsWithError.includes(getAttendeeEmail(attendee))
39     );
40     const removedEmails = removedAttendees.map((attendee) => getAttendeeEmail(attendee));
41     const removedEmailsWithError = removedEmails.filter((email) => emailsWithError.includes(email));
42     const invitedCleanAttendees = vevent?.attendee?.filter(
43         (attendee) => !emailsWithError.includes(getAttendeeEmail(attendee))
44     );
45     const invitedCleanOfAddedAttendees = vevent?.attendee?.filter((attendee) => {
46         const email = getAttendeeEmail(attendee);
47         return existingEmails.includes(email) || !emailsWithError.includes(email);
48     });
49     const invitedEmailsWithError = (vevent?.attendee || [])
50         .map((attendee) => getAttendeeEmail(attendee))
51         .filter((email) => emailsWithError.includes(email));
52     const cancelledCleanAttendees = cancelVevent?.attendee?.filter(
53         (attendee) => !emailsWithError.includes(getAttendeeEmail(attendee))
54     );
55     const cancelledEmailsWithError = (cancelVevent?.attendee || [])
56         .map((attendee) => getAttendeeEmail(attendee))
57         .filter((email) => emailsWithError.includes(email));
58     const organizerEmail = vevent?.organizer ? getAttendeeEmail(vevent.organizer) : undefined;
59     const organizerEmailWithError =
60         organizerEmail && emailsWithError.includes(organizerEmail) ? organizerEmail : undefined;
62     const cleanData = {
63         inviteActions: {
64             ...inviteActions,
65             addedAttendees: addedCleanAttendees,
66         },
67         vevent: {
68             ...vevent,
69             attendee: invitedCleanOfAddedAttendees || [],
70         },
71         cancelVevent,
72         sendPreferencesMap,
73         emailsWithError: [],
74     };
76     if (type === SEND_INVITATION) {
77         if (!vevent) {
78             throw new Error('Cannot create event without vevent component');
79         }
80         if (!hasAddedAttendees && !hasRemovedAttendees) {
81             if (getHasRecurrenceId(vevent)) {
82                 // we're creating a single edit, in that case we want to keep attendees with errors
83                 return {
84                     ...cleanData,
85                     inviteActions: {
86                         ...cleanData.inviteActions,
87                     },
88                     emailsWithError: [...invitedEmailsWithError, ...addedEmailsWithError, ...removedEmailsWithError],
89                 };
90             }
91             // it's a new invitation
92             return {
93                 ...cleanData,
94                 vevent: {
95                     ...vevent,
96                     attendee: invitedCleanAttendees,
97                 },
98                 inviteActions: {
99                     ...cleanData.inviteActions,
100                     type: invitedCleanAttendees?.length
101                         ? INVITE_ACTION_TYPES.SEND_INVITATION
102                         : INVITE_ACTION_TYPES.NONE,
103                 },
104                 emailsWithError: invitedEmailsWithError,
105             };
106         }
107         // the event exists already
108         const hasAddedOrRemoved = addedCleanAttendees.length || removedCleanAttendees.length;
109         return {
110             ...cleanData,
111             inviteActions: {
112                 ...cleanData.inviteActions,
113                 type: hasAddedOrRemoved ? SEND_INVITATION : NONE,
114             },
115             emailsWithError: [...addedEmailsWithError, ...removedEmailsWithError],
116         };
117     }
118     if (type === SEND_UPDATE) {
119         const cannotNotify = !invitedCleanAttendees?.length && !removedCleanAttendees?.length;
120         return {
121             ...cleanData,
122             inviteActions: {
123                 ...cleanData.inviteActions,
124                 type: cannotNotify ? NONE : SEND_UPDATE,
125             },
126             emailsWithError: [...invitedEmailsWithError, ...addedEmailsWithError, ...removedEmailsWithError],
127         };
128     }
129     if (type === CANCEL_INVITATION) {
130         return {
131             ...cleanData,
132             inviteActions: {
133                 ...cleanData.inviteActions,
134                 type: cancelledCleanAttendees?.length ? CANCEL_INVITATION : NONE,
135             },
136             emailsWithError: cancelledEmailsWithError,
137         };
138     }
139     if ([CHANGE_PARTSTAT, DECLINE_INVITATION].includes(type)) {
140         return {
141             sendPreferencesMap,
142             inviteActions: {
143                 ...inviteActions,
144                 type: NONE,
145             },
146             vevent,
147             cancelVevent,
148             emailsWithError: [organizerEmailWithError],
149         };
150     }
151     return cleanData;
154 export const getSendPrefErrorMap = (sendPreferencesMap: SimpleMap<AugmentedSendPreferences>) => {
155     return Object.entries(sendPreferencesMap).reduce<SimpleMap<string>>((acc, [email, sendPrefs]) => {
156         const error = sendPrefs?.error;
157         if (error) {
158             acc[email] = reformatApiErrorMessage(error.message);
159         }
160         return acc;
161     }, {});