Use source loader for email sprite icons
[ProtonMail-WebClient.git] / packages / wallet / utils / eventLoop.ts
blob80943db5fce79c04e8dd9b9e2f81b617ab14d65f
1 import { createAction } from '@reduxjs/toolkit';
2 import compact from 'lodash/compact';
4 import type { WasmApiWalletAccount, WasmApiWalletKey, WasmApiWalletSettings } from '@proton/andromeda';
5 import { EVENT_ACTIONS } from '@proton/shared/lib/constants';
6 import { type CreateEventItemUpdate } from '@proton/shared/lib/helpers/updateCollection';
7 import { type DecryptedKey } from '@proton/shared/lib/interfaces';
9 import type { IWasmApiWalletData } from '../types';
10 import type { WalletAccountEvent, WalletEvent, WalletEventLoop } from '../types/eventLoop';
11 import { replaceAt } from './array';
12 import { decryptWallet } from './wallet';
14 export const eventLoopEvent = createAction<WalletEventLoop>('server event');
16 const findCreatedWalletKeyFromEvents = (walletID: string, events: WalletEventLoop) => {
17     return events.WalletKeys?.find(
18         (walletKeyAction): walletKeyAction is CreateEventItemUpdate<WasmApiWalletKey, 'WalletKey'> =>
19             walletKeyAction.Action === EVENT_ACTIONS.CREATE && walletKeyAction.WalletKey.WalletID === walletID
20     )?.WalletKey;
23 const findCreatedWalletSettingsFromEvents = (walletID: string, events: WalletEventLoop) => {
24     return events.WalletSettings?.find(
25         (walletKeyAction): walletKeyAction is CreateEventItemUpdate<WasmApiWalletSettings, 'WalletSettings'> =>
26             walletKeyAction.Action === EVENT_ACTIONS.CREATE && walletKeyAction.WalletSettings.WalletID === walletID
27     )?.WalletSettings;
30 const findCreatedWalletAccountsFromEvents = (walletID: string, events: WalletEventLoop) => {
31     return (
32         events.WalletAccounts?.filter(
33             (
34                 walletAccountsAction
35             ): walletAccountsAction is CreateEventItemUpdate<WasmApiWalletAccount, 'WalletAccount'> =>
36                 walletAccountsAction.Action === EVENT_ACTIONS.CREATE &&
37                 walletAccountsAction.WalletAccount.WalletID === walletID
38         ).map((walletAccountsAction) => walletAccountsAction.WalletAccount) ?? []
39     );
42 export const stateFromWalletEvent = (
43     walletEvent: WalletEvent,
44     eventLoop: WalletEventLoop,
45     currentApiWalletsData: IWasmApiWalletData[],
46     userKeys: DecryptedKey[]
47 ): Promise<IWasmApiWalletData[]> => {
48     switch (walletEvent.Action) {
49         case EVENT_ACTIONS.CREATE:
50             return (async () => {
51                 if (currentApiWalletsData.some((data) => data.Wallet.ID === walletEvent.ID)) {
52                     return currentApiWalletsData;
53                 }
55                 // WalletKey and WalletSettings should be create at the same time
56                 const walletKey = findCreatedWalletKeyFromEvents(walletEvent.ID, eventLoop);
57                 const walletSettings = findCreatedWalletSettingsFromEvents(walletEvent.ID, eventLoop);
58                 const walletAccounts = findCreatedWalletAccountsFromEvents(walletEvent.ID, eventLoop);
60                 const apiWalletData = {
61                     Wallet: walletEvent.Wallet,
62                     WalletKey: walletKey,
63                     WalletSettings: walletSettings,
64                     WalletAccounts: walletAccounts,
65                 };
67                 const wallet = await decryptWallet({
68                     apiWalletData,
69                     userKeys,
70                 });
72                 return compact([...currentApiWalletsData, wallet]);
73             })();
74         case EVENT_ACTIONS.UPDATE:
75             return (async () => {
76                 const index = currentApiWalletsData.findIndex((wallet) => wallet.Wallet.ID === walletEvent.ID);
78                 const apiWalletData = {
79                     ...currentApiWalletsData[index],
80                     Wallet: { ...currentApiWalletsData[index].Wallet, ...walletEvent.Wallet },
81                 };
83                 const wallet = await decryptWallet({
84                     apiWalletData,
85                     userKeys,
86                 });
88                 if (index && index > -1) {
89                     return compact(replaceAt(currentApiWalletsData, index, wallet));
90                 }
92                 return compact(currentApiWalletsData);
93             })();
94         case EVENT_ACTIONS.DELETE:
95             return Promise.resolve(
96                 currentApiWalletsData.filter((walletData) => walletData.Wallet.ID != walletEvent.ID)
97             );
98         default:
99             return Promise.resolve(currentApiWalletsData);
100     }
103 export const stateFromWalletAccountEvent = (
104     walletAccountEvent: WalletAccountEvent,
105     currentWallets: IWasmApiWalletData[],
106     userKeys: DecryptedKey[]
107 ): Promise<IWasmApiWalletData[]> => {
108     switch (walletAccountEvent.Action) {
109         case EVENT_ACTIONS.CREATE:
110             return (async () => {
111                 const index = currentWallets.findIndex(
112                     (wallet) => wallet.Wallet.ID === walletAccountEvent.WalletAccount.WalletID
113                 );
115                 const apiWalletData = {
116                     ...currentWallets[index],
117                     WalletAccounts: [...currentWallets[index].WalletAccounts, walletAccountEvent.WalletAccount],
118                 };
120                 const wallet = await decryptWallet({
121                     apiWalletData,
122                     userKeys,
123                 });
125                 if (index && index > -1) {
126                     replaceAt(currentWallets, index, wallet);
127                 }
129                 return Promise.resolve(currentWallets);
130             })();
131         case EVENT_ACTIONS.UPDATE:
132             return (async () => {
133                 const walletIndex = currentWallets.findIndex(
134                     (wallet) => wallet.Wallet.ID === walletAccountEvent.WalletAccount.WalletID
135                 );
137                 const walletAtIndex = currentWallets[walletIndex];
139                 if (walletAtIndex) {
140                     const accountIndex = walletAtIndex.WalletAccounts.findIndex(
141                         (walletAccount) => walletAccount.ID === walletAccountEvent.ID
142                     );
144                     const apiWalletData = {
145                         ...walletAtIndex,
146                         WalletAccounts: replaceAt(walletAtIndex.WalletAccounts, accountIndex, {
147                             ...walletAtIndex.WalletAccounts[accountIndex],
148                             ...walletAccountEvent.WalletAccount,
149                         }),
150                     };
152                     const wallet = await decryptWallet({
153                         apiWalletData,
154                         userKeys,
155                     });
157                     if (accountIndex > -1) {
158                         return compact(replaceAt(currentWallets, walletIndex, wallet));
159                     }
160                 }
162                 return Promise.resolve(currentWallets);
163             })();
164         case EVENT_ACTIONS.DELETE:
165             return Promise.resolve(
166                 currentWallets.map(({ WalletAccounts, ...rest }) => ({
167                     ...rest,
168                     WalletAccounts: WalletAccounts.filter(
169                         (walletAccount) => walletAccount.ID !== walletAccountEvent.ID
170                     ),
171                 }))
172             );
173     }