Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / wallet / store / slices / quotesByProvider.ts
blob85a15fca668556e0e891e75b1a1b782af66a9dd2
1 import { createAction, createSlice } from '@reduxjs/toolkit';
3 import type { ModelState } from '@proton/account';
4 import { getInitialModelState } from '@proton/account';
5 import type { WasmGatewayProvider, WasmPaymentMethod, WasmQuote } from '@proton/andromeda';
6 import { createAsyncModelThunk, handleAsyncModel } from '@proton/redux-utilities';
7 import { MINUTE } from '@proton/shared/lib/constants';
8 import { type SimpleMap } from '@proton/shared/lib/interfaces';
10 import type { WalletThunkArguments } from '../thunk';
12 const name = 'quotes_by_provider' as const;
14 export type GetQuotesArgs = [number, string, WasmPaymentMethod?, WasmGatewayProvider?];
16 export type QuotesByProvider = Partial<Record<WasmGatewayProvider, WasmQuote[]>>;
17 type QuotesByProviderByKey = SimpleMap<QuotesByProvider>;
18 export const getQuotesByProviderKey = (args: GetQuotesArgs) => {
19     const [amount, fiat, paymentMethod, gatewayProvider] = args;
20     return `${amount}_${fiat}_${paymentMethod}_${gatewayProvider}`;
23 export interface QuotesByProviderState {
24     [name]: ModelState<QuotesByProviderByKey>;
27 type SliceState = QuotesByProviderState[typeof name];
28 type Model = NonNullable<SliceState['value']>;
30 export const selectQuotesByProvider = (state: QuotesByProviderState) => state[name];
32 const modelThunk = createAsyncModelThunk<Model, QuotesByProviderState, WalletThunkArguments, GetQuotesArgs>(
33     `${name}/fetch`,
34     {
35         miss: async ({ extraArgument, options, getState }) => {
36             const stateValue = getState()[name].value;
37             if (!options?.thunkArg) {
38                 return stateValue ?? {};
39             }
41             const [amount, fiat, paymentMethod, gatewayProvider] = options.thunkArg;
42             const key = getQuotesByProviderKey(options.thunkArg);
44             return extraArgument.walletApi
45                 .clients()
46                 .payment_gateway.getQuotes(amount, fiat, paymentMethod, gatewayProvider)
47                 .then((quotes) => {
48                     const quotesByProvider = quotes.data.reduce((acc, current) => {
49                         const provider = current[0];
50                         const quotes = current[1];
52                         return { ...acc, [provider]: quotes.data };
53                     }, {} as QuotesByProvider);
55                     return {
56                         ...stateValue,
57                         [key]: quotesByProvider,
58                     };
59                 });
60         },
61         expiry: 1 * MINUTE,
62         previous: ({ getState, options }) => {
63             const state = getState()[name];
64             if (!options?.thunkArg || !state.value) {
65                 return undefined;
66             }
68             const [amount, fiat, paymentMethod, gatewayProvider] = options?.thunkArg;
69             const key = `${amount}_${fiat}_${paymentMethod}_${gatewayProvider}`;
71             if (state.value[key]) {
72                 return state;
73             }
75             return undefined;
76         },
77     }
80 export const resetQuotesByProvider = createAction(`${name}/reset`);
82 const initialState = getInitialModelState<Model>();
83 const slice = createSlice({
84     name,
85     initialState,
86     reducers: {},
87     extraReducers: (builder) => {
88         handleAsyncModel(builder, modelThunk).addCase(resetQuotesByProvider, () => initialState);
89     },
90 });
92 export const quotesByProviderReducer = { [name]: slice.reducer };
93 export const quotesByProviderThunk = modelThunk.thunk;