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>(
35 miss: async ({ extraArgument, options, getState }) => {
36 const stateValue = getState()[name].value;
37 if (!options?.thunkArg) {
38 return stateValue ?? {};
41 const [amount, fiat, paymentMethod, gatewayProvider] = options.thunkArg;
42 const key = getQuotesByProviderKey(options.thunkArg);
44 return extraArgument.walletApi
46 .payment_gateway.getQuotes(amount, fiat, paymentMethod, gatewayProvider)
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);
57 [key]: quotesByProvider,
62 previous: ({ getState, options }) => {
63 const state = getState()[name];
64 if (!options?.thunkArg || !state.value) {
68 const [amount, fiat, paymentMethod, gatewayProvider] = options?.thunkArg;
69 const key = `${amount}_${fiat}_${paymentMethod}_${gatewayProvider}`;
71 if (state.value[key]) {
80 export const resetQuotesByProvider = createAction(`${name}/reset`);
82 const initialState = getInitialModelState<Model>();
83 const slice = createSlice({
87 extraReducers: (builder) => {
88 handleAsyncModel(builder, modelThunk).addCase(resetQuotesByProvider, () => initialState);
92 export const quotesByProviderReducer = { [name]: slice.reducer };
93 export const quotesByProviderThunk = modelThunk.thunk;