Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / mail / contactEmails / index.ts
bloba8908a0315fae28c9f0eb139383751cab5cad73a
1 import { createSlice } from '@reduxjs/toolkit';
3 import { type ModelState, getInitialModelState, serverEvent } from '@proton/account';
4 import type { ProtonThunkArguments } from '@proton/redux-shared-store-types';
5 import { createAsyncModelThunk, handleAsyncModel, previousSelector } from '@proton/redux-utilities';
6 import { queryContactEmails } from '@proton/shared/lib/api/contacts';
7 import queryPages from '@proton/shared/lib/api/helpers/queryPages';
8 import { CONTACTS_REQUESTS_PER_SECOND, CONTACT_EMAILS_LIMIT } from '@proton/shared/lib/constants';
9 import { EVENT_ERRORS } from '@proton/shared/lib/errors';
10 import { hasBit } from '@proton/shared/lib/helpers/bitset';
11 import updateCollection, { sortCollection } from '@proton/shared/lib/helpers/updateCollection';
12 import type { Api } from '@proton/shared/lib/interfaces';
13 import type { ContactEmail } from '@proton/shared/lib/interfaces/contacts';
15 const name = 'contactEmails' as const;
17 export const getContactEmailsModel = (api: Api) => {
18     return queryPages(
19         (page, pageSize) => {
20             return api(
21                 queryContactEmails({
22                     Page: page,
23                     PageSize: pageSize,
24                 })
25             );
26         },
27         {
28             pageSize: CONTACT_EMAILS_LIMIT,
29             pagesPerChunk: CONTACTS_REQUESTS_PER_SECOND,
30             delayPerChunk: 1000,
31         }
32     ).then((pages) => {
33         return sortCollection(
34             'Order',
35             pages.flatMap(({ ContactEmails }) => ContactEmails)
36         );
37     });
40 interface State {
41     [name]: ModelState<ContactEmail[]>;
44 type SliceState = State[typeof name];
45 type Model = NonNullable<SliceState['value']>;
47 export const selectContactEmails = (state: State) => state[name];
49 const modelThunk = createAsyncModelThunk<Model, State, ProtonThunkArguments>(`${name}/fetch`, {
50     miss: async ({ extraArgument }) => {
51         return getContactEmailsModel(extraArgument.api);
52     },
53     previous: previousSelector(selectContactEmails),
54 });
56 const initialState = getInitialModelState<Model>();
57 const slice = createSlice({
58     name,
59     initialState,
60     reducers: {},
61     extraReducers: (builder) => {
62         handleAsyncModel(builder, modelThunk);
63         builder.addCase(serverEvent, (state, action) => {
64             if (state.value && action.payload.ContactEmails) {
65                 state.value = sortCollection(
66                     'Order',
67                     updateCollection({
68                         model: state.value,
69                         events: action.payload.ContactEmails,
70                         itemKey: 'ContactEmail',
71                     })
72                 );
73             }
74             if (state.value && hasBit(action.payload.Refresh, EVENT_ERRORS.CONTACTS)) {
75                 delete state.value;
76                 delete state.error;
77             }
78         });
79     },
80 });
82 export const contactEmailsReducer = { [name]: slice.reducer };
83 export const contactEmailsThunk = modelThunk.thunk;