1 import type { Reducer } from 'redux';
3 import { PassErrorCode } from '@proton/pass/lib/api/errors';
5 intoCustomMonitorAddress,
7 intoProtonMonitorAddress,
8 } from '@proton/pass/lib/monitor/monitor.utils';
9 import { AddressType, type MonitorAddress, type MonitorDomain } from '@proton/pass/lib/monitor/types';
14 resolveAddressMonitor,
17 } from '@proton/pass/store/actions';
18 import type { MaybeNull } from '@proton/pass/types';
19 import { partialMerge } from '@proton/pass/utils/object/merge';
20 import lastItem from '@proton/utils/lastItem';
22 export type MonitorState = MaybeNull<{
23 custom: MonitorAddress<AddressType.CUSTOM>[];
24 preview: MonitorDomain[];
25 proton: MonitorAddress<AddressType.PROTON>[];
26 customDomains: boolean;
30 const monitorReducer: Reducer<MonitorState> = (state = null, action) => {
31 if (getBreaches.success.match(action)) {
33 custom: action.payload.CustomEmails?.map(intoCustomMonitorAddress) ?? [],
34 preview: action.payload.DomainsPeek?.map(intoMonitorDomain) ?? [],
35 proton: action.payload.Addresses?.map(intoProtonMonitorAddress) ?? [],
36 customDomains: action.payload.HasCustomDomains,
37 total: action.payload.EmailsCount,
42 if (addCustomAddress.success.match(action)) {
43 return partialMerge(state, {
44 custom: state.custom.concat(intoCustomMonitorAddress(action.payload)),
48 if (verifyCustomAddress.success.match(action)) {
49 const breached = (action.payload.breachCount ?? 0) > 0;
51 return partialMerge(state, {
52 total: state.total + Number(breached),
53 custom: state.custom.map((breach) => {
54 if (breach.addressId !== action.payload.addressId) return breach;
55 return action.payload;
60 if (verifyCustomAddress.failure.match(action)) {
61 const addressId = lastItem(action.meta.request.id.split('::'));
62 if (action.payload.code === PassErrorCode.NOT_ALLOWED && addressId) {
63 return partialMerge(state, { custom: state.custom.filter((breach) => breach.addressId !== addressId) });
67 if (deleteCustomAddress.success.match(action)) {
68 const breach = state.custom.find((breach) => breach.addressId === action.payload);
69 const breached = (breach?.breachCount ?? 0) > 0;
71 return partialMerge(state, {
72 total: Math.max(0, state.total - Number(breached)),
73 custom: state.custom.filter((breach) => breach.addressId !== action.payload),
77 if (resolveAddressMonitor.success.match(action)) {
78 const dto = action.payload;
81 case AddressType.ALIAS: {
82 return partialMerge(state, { total: Math.max(0, state.total - 1) });
85 case AddressType.CUSTOM: {
86 const address = state.custom.find(({ addressId }) => addressId === dto.addressId);
87 const breached = (address?.breachCount ?? 0) > 0;
90 ? partialMerge(state, {
91 total: Math.max(0, state.total - Number(breached)),
92 custom: state.custom.map((breach) => {
93 if (breach.addressId !== dto.addressId) return breach;
94 return { ...breach, breachCount: 0, breached: false };
100 case AddressType.PROTON: {
101 const address = state.proton.find(({ addressId }) => addressId === dto.addressId);
102 const breached = (address?.breachCount ?? 0) > 0;
105 ? partialMerge(state, {
106 total: Math.max(0, state.total - Number(breached)),
107 proton: state.proton.map((breach) => {
108 if (breach.addressId !== dto.addressId) return breach;
109 return { ...breach, breachCount: 0, breached: false };
117 if (toggleAddressMonitor.success.match(action)) {
118 const type = action.payload.type;
119 if (type === AddressType.ALIAS) return state;
121 return partialMerge(state, {
122 [type]: state[type].map((breach) =>
123 action.payload.type === AddressType.ALIAS || breach.addressId !== action.payload.addressId
134 export default monitorReducer;