Update selected item color in Pass menu
[ProtonMail-WebClient.git] / packages / pass / store / reducers / settings.ts
blob49eaeecb80c7a2ef7a06742f695233a17b7076c4
1 import type { Reducer } from 'redux';
3 import { type PassThemeOption } from '@proton/pass/components/Layout/Theme/types';
4 import { LockMode } from '@proton/pass/lib/auth/lock/types';
5 import type { GeneratePasswordConfig } from '@proton/pass/lib/password/generator';
6 import { toggleCriteria } from '@proton/pass/lib/settings/criteria';
7 import {
8     extraPasswordToggle,
9     itemCreationSuccess,
10     lockCreateSuccess,
11     lockSync,
12     offlineToggle,
13     settingsEditSuccess,
14     updatePauseListItem,
15     userEvent,
16 } from '@proton/pass/store/actions';
17 import { passwordOptionsEdit } from '@proton/pass/store/actions/creators/password';
18 import type { MaybeNull, Unpack } from '@proton/pass/types';
19 import type {
20     AutoFillSettings,
21     AutoSaveSettings,
22     AutoSuggestSettings,
23     DomainCriterias,
24     PasskeySettings,
25 } from '@proton/pass/types/worker/settings';
26 import { or } from '@proton/pass/utils/fp/predicates';
27 import { partialMerge } from '@proton/pass/utils/object/merge';
29 export type SettingsState = {
30     autofill: AutoFillSettings;
31     autosave: AutoSaveSettings;
32     autosuggest: AutoSuggestSettings;
33     beta?: boolean;
34     createdItemsCount: number /* explicitly created, not including import */;
35     disallowedDomains: DomainCriterias;
36     extraPassword?: boolean;
37     loadDomainImages: boolean;
38     locale?: string;
39     lockMode: LockMode;
40     lockTTL?: number;
41     offlineEnabled?: boolean;
42     passkeys: PasskeySettings;
43     passwordOptions: MaybeNull<GeneratePasswordConfig>;
44     showUsernameField?: boolean;
45     theme?: PassThemeOption;
48 export const EXCLUDED_SETTINGS_KEYS = ['createdItemsCount', 'lockMode', 'extraPassword'] as const;
49 export type ExcludedProxiedSettingsKeys = Unpack<typeof EXCLUDED_SETTINGS_KEYS>;
51 /* proxied settings will also be copied on local
52  * storage in order to access them before the booting
53  * sequence  (ie: if the user has been logged out) */
54 export type ProxiedSettings = Omit<SettingsState, ExcludedProxiedSettingsKeys>;
56 export const getInitialSettings = (): ProxiedSettings => ({
57     autofill: { identity: true, twofa: true },
58     autosave: { prompt: true, passwordSuggest: true },
59     autosuggest: { password: true, email: true, passwordCopy: false },
60     disallowedDomains: {},
61     loadDomainImages: true,
62     passkeys: { get: true, create: true },
63     passwordOptions: null,
64     showUsernameField: false,
65     /* Theme is set to undefined so we can prompt <ThemeOnboardingModal> for discovery.
66      * Once we decide to no longer display that modal (e.g theme feature is not considered new anymore)
67      * then change value to PassThemeOption.OS */
68     theme: undefined,
69 });
71 const getInitialState = (): SettingsState => ({
72     createdItemsCount: 0,
73     lockMode: LockMode.NONE,
74     lockTTL: undefined,
75     ...getInitialSettings(),
76 });
78 const reducer: Reducer<SettingsState> = (state = getInitialState(), action) => {
79     if (passwordOptionsEdit.match(action)) return { ...state, passwordOptions: action.payload };
81     if (itemCreationSuccess.match(action)) {
82         return partialMerge(state, { createdItemsCount: state.createdItemsCount + 1 });
83     }
85     if (or(lockCreateSuccess.match, lockSync.match)(action)) {
86         return partialMerge(state, { lockMode: action.payload.lock.mode, lockTTL: action.payload.lock.ttl });
87     }
89     if (settingsEditSuccess.match(action)) {
90         const update = { ...state };
92         /* `disallowedDomains` update should act as a setter */
93         if ('disallowedDomains' in action.payload) update.disallowedDomains = {};
94         return partialMerge<SettingsState>(update, action.payload);
95     }
97     if (userEvent.match(action)) {
98         const locale = action.payload.UserSettings?.Locale;
99         return locale ? partialMerge(state, { locale }) : state;
100     }
102     if (updatePauseListItem.match(action)) {
103         const { hostname, criteria } = action.payload;
104         const criteriasSetting = state.disallowedDomains[hostname] ?? 0;
106         return partialMerge<SettingsState>(state, {
107             disallowedDomains: {
108                 [hostname]: toggleCriteria(criteriasSetting, criteria),
109             },
110         });
111     }
113     if (offlineToggle.success.match(action)) {
114         return partialMerge<SettingsState>(state, { offlineEnabled: action.payload });
115     }
117     if (extraPasswordToggle.success.match(action)) {
118         return partialMerge<SettingsState>(state, { extraPassword: action.payload });
119     }
121     return state;
124 export default reducer;