Merge branch 'renovate/playwright' into 'main'
[ProtonMail-WebClient.git] / packages / account / user / index.ts
blob7816c32f053a7f995ed4a731e839aa0bd458b222
1 import { createSlice } from '@reduxjs/toolkit';
3 import type { ProtonThunkArguments } from '@proton/redux-shared-store-types';
4 import {
5     createAsyncModelThunk,
6     getFetchedAt,
7     getFetchedEphemeral,
8     handleAsyncModel,
9     previousSelector,
10 } from '@proton/redux-utilities';
11 import { getUser } from '@proton/shared/lib/api/user';
12 import { DAY } from '@proton/shared/lib/constants';
13 import type { User, UserModel } from '@proton/shared/lib/interfaces';
14 import { formatUser } from '@proton/shared/lib/user/helpers';
16 import { serverEvent } from '../eventLoop';
17 import { initEvent } from '../init';
18 import { getInitialModelState } from '../initialModelState';
19 import type { ModelState } from '../interface';
21 const name = 'user' as const;
23 export interface UserState {
24     [name]: ModelState<UserModel>;
27 type SliceState = UserState[typeof name];
28 type Model = NonNullable<SliceState['value']>;
30 export const selectUser = (state: UserState) => state.user;
32 const modelThunk = createAsyncModelThunk<Model, UserState, ProtonThunkArguments>(`${name}/fetch`, {
33     expiry: 7 * DAY,
34     miss: ({ extraArgument }) => {
35         return extraArgument.api<{ User: User }>(getUser()).then(({ User }) => {
36             return formatUser(User);
37         });
38     },
39     previous: previousSelector(selectUser),
40 });
42 const initialState = getInitialModelState<Model>();
43 const slice = createSlice({
44     name,
45     initialState,
46     reducers: {},
47     extraReducers: (builder) => {
48         handleAsyncModel(builder, modelThunk);
49         builder
50             .addCase(initEvent, (state, action) => {
51                 if (action.payload.User) {
52                     state.value = formatUser(action.payload.User);
53                     state.meta.fetchedAt = getFetchedAt();
54                     state.meta.fetchedEphemeral = getFetchedEphemeral();
55                 }
56             })
57             .addCase(serverEvent, (state, action) => {
58                 if (state.value && (action.payload.User || action.payload.UsedSpace)) {
59                     const user = action.payload.User || state.value;
60                     if (action.payload.UsedSpace !== undefined) {
61                         user.UsedSpace = action.payload.UsedSpace;
62                     }
63                     if (action.payload.UsedBaseSpace !== undefined) {
64                         user.UsedBaseSpace = action.payload.UsedBaseSpace;
65                     }
66                     if (action.payload.UsedDriveSpace !== undefined) {
67                         user.UsedDriveSpace = action.payload.UsedDriveSpace;
68                     }
69                     if (action.payload.ProductUsedSpace !== undefined) {
70                         user.ProductUsedSpace = action.payload.ProductUsedSpace;
71                     }
72                     state.value = formatUser(user);
73                 }
74             });
75     },
76 });
78 export const userReducer = { [name]: slice.reducer };
79 export const userThunk = modelThunk.thunk;