Merge branch 'fix-typo-drive' into 'main'
[ProtonMail-WebClient.git] / packages / calendar / calendarModelEventManager / index.ts
blobce8aeb8694a44f7682924641dc24e58fea74cdbe
1 import { queryLatestModelEventID, queryModelEvents } from '@proton/shared/lib/api/calendars';
2 import createEventManager, { EVENT_ID_KEYS, EventManager } from '@proton/shared/lib/eventManager/eventManager';
3 import type { Api, SimpleMap } from '@proton/shared/lib/interfaces';
5 type SubscribeCallback = (data: any) => void;
7 export interface CalendarModelEventManager {
8     start: (calendarIDs: string[]) => void[];
9     stop: (calendarIDs: string[]) => void[];
10     reset: (calendarIDs: string[]) => void[];
11     call: (calendarIDs: string[]) => Promise<void[]>;
12     subscribe: (calendarIDs: string[], cb: SubscribeCallback) => () => void;
13     clear: () => void;
16 const createCalendarEventManagerById = async (api: Api, calendarID: string) => {
17     const { CalendarModelEventID } = await api<{ CalendarModelEventID: string }>(queryLatestModelEventID(calendarID));
18     const eventManager = createEventManager({
19         api,
20         eventID: CalendarModelEventID,
21         query: (eventId: string) => queryModelEvents(calendarID, eventId),
22         eventIDKey: EVENT_ID_KEYS.CALENDAR,
23     });
24     eventManager.start();
25     return eventManager;
28 const getOrSetRecord = (calendarID: string, eventManagers: SimpleMap<EventManagerCacheRecord>, api: Api) => {
29     const cachedValue = eventManagers[calendarID];
30     if (!cachedValue || (cachedValue.eventManager === undefined && cachedValue.promise === undefined)) {
31         const promise = createCalendarEventManagerById(api, calendarID)
32             .then((eventManager) => {
33                 eventManagers[calendarID] = {
34                     eventManager,
35                     promise: undefined,
36                 };
37                 return eventManager;
38             })
39             .catch(() => {
40                 delete eventManagers[calendarID];
41                 return undefined;
42             });
43         const record = { promise, eventManager: undefined };
44         eventManagers[calendarID] = record;
45         return record;
46     }
47     return cachedValue;
50 type EventManagerCacheRecord =
51     | {
52           eventManager: EventManager;
53           promise: undefined;
54       }
55     | {
56           promise: Promise<EventManager | undefined>;
57           eventManager: undefined;
58       };
60 export const createCalendarModelEventManager = ({ api }: { api: Api }): CalendarModelEventManager => {
61     let eventManagers: SimpleMap<EventManagerCacheRecord> = {};
63     const clear = () => {
64         Object.values(eventManagers).forEach((record) => {
65             if (!record) {
66                 return;
67             }
68             if (record.promise) {
69                 record.promise.then((eventManager) => {
70                     if (!eventManager) {
71                         return;
72                     }
73                     eventManager.stop();
74                     eventManager.reset();
75                 });
76             }
77             if (record.eventManager) {
78                 record.eventManager.stop();
79                 record.eventManager.reset();
80             }
81         });
82         eventManagers = {};
83     };
85     const start = (calendarIDs: string[]) => {
86         return calendarIDs.map((calendarID) => {
87             return eventManagers[calendarID]?.eventManager?.start();
88         });
89     };
91     const stop = (calendarIDs: string[]) => {
92         return calendarIDs.map((calendarID) => {
93             return eventManagers[calendarID]?.eventManager?.stop();
94         });
95     };
97     const reset = (calendarIDs: string[]) => {
98         return calendarIDs.map((calendarID) => {
99             return eventManagers[calendarID]?.eventManager?.reset();
100         });
101     };
103     const call = (calendarIDs: string[]) => {
104         return Promise.all(
105             calendarIDs.map((calendarID) => {
106                 return eventManagers[calendarID]?.eventManager?.call();
107             })
108         );
109     };
111     const subscribe = (calendarIDs: string[], cb: SubscribeCallback) => {
112         let isActive = true;
113         const notify = (data: any) => {
114             cb(data);
115         };
117         const unsubscribes = calendarIDs.reduce<(() => void)[]>((acc, calendarID) => {
118             const record = getOrSetRecord(calendarID, eventManagers, api);
119             if (record.promise) {
120                 record.promise.then((eventManager) => {
121                     if (!isActive || !eventManager) {
122                         return;
123                     }
124                     acc.push(eventManager.subscribe(notify));
125                 });
126                 return acc;
127             }
128             acc.push(record.eventManager.subscribe(notify));
129             return acc;
130         }, []);
132         return () => {
133             unsubscribes.forEach((unsub) => unsub?.());
134             isActive = false;
135         };
136     };
138     return {
139         start,
140         stop,
141         reset,
142         call,
143         subscribe,
144         clear,
145     };