Skip to content

Commit

Permalink
[WALL] Rostislav / WALL-3069 / Use requests instead of subscriptions …
Browse files Browse the repository at this point in the history
…for exchange rates in transfer messages and transfer inputs (deriv-com#12229)

* refactor: the thing

* refactor: a few corrections

* refactor: rename `useExchangeRate`

* refactor: move logic to context, different names

* fix: param mismatch + refactor for insurance

* refactor: move limits mgmt to context

* fix: param
  • Loading branch information
rostislav-deriv authored Dec 18, 2023
1 parent 9c79cff commit 164b965
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 105 deletions.
3 changes: 2 additions & 1 deletion packages/api/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ export { default as useDocumentUpload } from './useDocumentUpload';
export { default as useDxtradeAccountsList } from './useDxtradeAccountsList';
export { default as useDxtradeServiceToken } from './useDxtradeServiceToken';
export { default as useDynamicLeverage } from './useDynamicLeverage';
export { default as useExchangeRate } from './useExchangeRate';
export { default as useExchangeRateSubscription } from './useExchangeRateSubscription';
export { default as useGetAccountStatus } from './useGetAccountStatus';
export { default as useGetExchangeRate } from './useGetExchangeRate';
export { default as useIdentityDocumentVerificationAdd } from './useIdentityDocumentVerificationAdd';
export { default as useIsEuRegion } from './useIsEuRegion';
export { default as useJurisdictionStatus } from './useJurisdictionStatus';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type TPayload = Required<
>;

/** A custom hook that gets exchange rates from base currency to target currency */
const useExchangeRate = () => {
const useExchangeRateSubscription = () => {
const { data, subscribe: _subscribe, ...rest } = useSubscription('exchange_rates');

const subscribe = useCallback(
Expand All @@ -25,4 +25,4 @@ const useExchangeRate = () => {
};
};

export default useExchangeRate;
export default useExchangeRateSubscription;
15 changes: 15 additions & 0 deletions packages/api/src/hooks/useGetExchangeRate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import useQuery from '../useQuery';

type TProps = Required<Parameters<typeof useQuery<'exchange_rates'>>[1]>['payload'];

const useGetExchangeRate = ({ base_currency, loginid, target_currency }: TProps) => {
const { data, ...rest } = useQuery('exchange_rates', { payload: { base_currency, loginid, target_currency } });

return {
/** The exchange rates response */
data: data?.exchange_rates,
...rest,
};
};

export default useGetExchangeRate;
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useCallback, useEffect } from 'react';
import { useFormikContext } from 'formik';
import { useDebounce } from 'usehooks-ts';
import { useExchangeRate } from '@deriv/api';
import { ATMAmountInput, Timer } from '../../../../../../components';
import { useTransfer } from '../../provider';
import type { TInitialTransferFormValues } from '../../types';
Expand All @@ -14,11 +13,18 @@ type TProps = {
const MAX_DIGITS = 14;

const TransferFormAmountInput: React.FC<TProps> = ({ fieldName }) => {
const { data: exchangeRate, subscribe, unsubscribe } = useExchangeRate();
const { activeWallet } = useTransfer();
const { setFieldValue, setValues, values } = useFormikContext<TInitialTransferFormValues>();
const { fromAccount, fromAmount, toAccount, toAmount } = values;

const { activeWalletExchangeRates, refetchAccountLimits, refetchExchangeRates } = useTransfer();

const refetchExchangeRatesAndLimits = useCallback(() => {
refetchAccountLimits();
const newRates = refetchExchangeRates();

return newRates;
}, [refetchAccountLimits, refetchExchangeRates]);

const isFromAmountFieldName = fieldName === 'fromAmount';
const isSameCurrency = fromAccount?.currency === toAccount?.currency;
const isAmountInputDisabled = fieldName === 'toAmount' && !toAccount;
Expand All @@ -36,28 +42,11 @@ const TransferFormAmountInput: React.FC<TProps> = ({ fieldName }) => {
? fromAccount?.currencyConfig?.fractional_digits
: toAccount?.currencyConfig?.fractional_digits;

useEffect(() => {
if (!fromAccount?.currency || !toAccount?.currency || !activeWallet?.loginid) return;
subscribe({
base_currency: fromAccount?.currency,
loginid: activeWallet?.loginid,
target_currency: toAccount?.currency,
});
return () => unsubscribe();
}, [
activeWallet?.currency,
activeWallet?.loginid,
fromAccount?.currency,
subscribe,
toAccount?.currency,
unsubscribe,
]);

const amountConverterHandler = useCallback(
(value: number) => {
if (!toAccount?.currency || !exchangeRate?.rates || !isAmountFieldActive) return;
if (!toAccount?.currency || !activeWalletExchangeRates?.rates || !isAmountFieldActive) return;

const toRate = exchangeRate.rates[toAccount.currency];
const toRate = activeWalletExchangeRates.rates[toAccount.currency];

if (isFromAmountFieldName) {
const convertedToAmount = Number(
Expand All @@ -72,7 +61,7 @@ const TransferFormAmountInput: React.FC<TProps> = ({ fieldName }) => {
}
},
[
exchangeRate?.rates,
activeWalletExchangeRates?.rates,
fromAccount?.currencyConfig?.fractional_digits,
isAmountFieldActive,
isFromAmountFieldName,
Expand Down Expand Up @@ -106,14 +95,18 @@ const TransferFormAmountInput: React.FC<TProps> = ({ fieldName }) => {
);

const onTimerCompleteHandler = useCallback(() => {
if (!toAccount?.currency || !exchangeRate?.rates) return;

const toRate = exchangeRate.rates[toAccount.currency];
const convertedToAmount = Number((fromAmount * toRate).toFixed(toAccount?.currencyConfig?.fractional_digits));
setFieldValue('toAmount', convertedToAmount);
refetchExchangeRatesAndLimits().then(res => {
const newRates = res.data?.exchange_rates;
if (!newRates?.rates || !toAccount?.currency) return;
const toRate = newRates.rates[toAccount.currency];
const convertedToAmount = Number(
(fromAmount * toRate).toFixed(toAccount?.currencyConfig?.fractional_digits)
);
setFieldValue('toAmount', convertedToAmount);
});
}, [
exchangeRate?.rates,
fromAmount,
refetchExchangeRatesAndLimits,
setFieldValue,
toAccount?.currency,
toAccount?.currencyConfig?.fractional_digits,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@ import React from 'react';
import { useFormikContext } from 'formik';
import { FadedAnimatedList, WalletAlertMessage } from '../../../../../../components';
import { useTransferMessages } from '../../hooks';
import { useTransfer } from '../../provider';
import { TInitialTransferFormValues } from '../../types';
import './TransferMessages.scss';

const TransferMessages = () => {
const { values } = useFormikContext<TInitialTransferFormValues>();

const messages = useTransferMessages(values.fromAccount, values.toAccount, values);
const { USDExchangeRates, accountLimits, activeWalletExchangeRates } = useTransfer();

const messages = useTransferMessages({
accountLimits,
activeWalletExchangeRates,
formData: values,
fromAccount: values.fromAccount,
toAccount: values.toAccount,
USDExchangeRates,
});

return (
<FadedAnimatedList className='wallets-transfer-messages'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ export type TMessage = {
};

export type TMessageFnProps = {
USDExchangeRates?: THooks.ExchangeRate;
activeWallet: THooks.ActiveWalletAccount;
activeWalletExchangeRates?: THooks.ExchangeRate;
displayMoney?: (amount: number, currency: string, fractionalDigits: number) => string;
exchangeRates?: THooks.ExchangeRate;
limits?: THooks.AccountLimits;
sourceAccount: NonNullable<TAccount>;
sourceAmount: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from 'react';
import { useAccountLimits, useActiveWalletAccount, useAuthorize, useExchangeRate, usePOI } from '@deriv/api';
import { useCallback } from 'react';
import { useActiveWalletAccount, useAuthorize, usePOI } from '@deriv/api';
import { displayMoney as displayMoney_ } from '@deriv/api/src/utils';
import { THooks } from '../../../../../../types';
import { TAccount, TInitialTransferFormValues } from '../../types';
Expand All @@ -10,65 +10,32 @@ import {
} from './utils/messageFunctions';
import { TMessage, TMessageFnProps } from './types';

const useTransferMessages = (
fromAccount: NonNullable<TAccount> | undefined,
toAccount: NonNullable<TAccount> | undefined,
formData: TInitialTransferFormValues
) => {
type TProps = {
USDExchangeRates?: THooks.ExchangeRate;
accountLimits?: THooks.AccountLimits;
activeWalletExchangeRates?: THooks.ExchangeRate;
formData: TInitialTransferFormValues;
fromAccount: NonNullable<TAccount> | undefined;
toAccount: NonNullable<TAccount> | undefined;
};

const useTransferMessages = ({
USDExchangeRates,
accountLimits,
activeWalletExchangeRates,
formData,
fromAccount,
toAccount,
}: TProps) => {
const { data: authorizeData } = useAuthorize();
const { data: activeWallet } = useActiveWalletAccount();
const { preferred_language: preferredLanguage } = authorizeData;
const { data: poi } = usePOI();
const { data: accountLimits } = useAccountLimits();
const { data: exchangeRatesRaw, subscribe, unsubscribe } = useExchangeRate();

const [exchangeRates, setExchangeRates] = useState<THooks.ExchangeRate>();

const isTransferBetweenWallets =
fromAccount?.account_category === 'wallet' && toAccount?.account_category === 'wallet';
const isAccountVerified = poi?.is_verified;

useEffect(
() => setExchangeRates(prev => ({ ...prev, rates: { ...prev?.rates, ...exchangeRatesRaw?.rates } })),
[exchangeRatesRaw?.rates]
);

useEffect(() => {
if (!fromAccount?.currency || !toAccount?.currency || !activeWallet?.currency || !activeWallet?.loginid) return;
unsubscribe();
if (!isAccountVerified && isTransferBetweenWallets) {
subscribe({
base_currency: activeWallet.currency,
loginid: activeWallet.loginid,
target_currency:
activeWallet.loginid === fromAccount.loginid ? toAccount.currency : fromAccount.currency,
});
} else {
subscribe({
base_currency: 'USD',
loginid: activeWallet.loginid,
target_currency: toAccount.currency,
});
if (fromAccount.currency !== toAccount.currency)
subscribe({
base_currency: 'USD',
loginid: activeWallet.loginid,
target_currency: fromAccount.currency,
});
return unsubscribe;
}
}, [
activeWallet?.currency,
activeWallet?.loginid,
fromAccount?.currency,
fromAccount?.loginid,
isAccountVerified,
isTransferBetweenWallets,
subscribe,
toAccount?.currency,
unsubscribe,
]);

const displayMoney = useCallback(
(amount: number, currency: string, fractionalDigits: number) =>
displayMoney_(amount, currency, {
Expand Down Expand Up @@ -96,12 +63,13 @@ const useTransferMessages = (
messageFns.forEach(messageFn => {
const message = messageFn({
activeWallet,
activeWalletExchangeRates,
displayMoney,
exchangeRates,
limits: accountLimits,
sourceAccount: fromAccount,
sourceAmount,
targetAccount: toAccount,
USDExchangeRates,
});
if (message) messages.push(message);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { TMessageFnProps } from '../types';
// this function should work once BE WALL-1440 is delivered
const lifetimeAccountLimitsBetweenWalletsMessageFn = ({
activeWallet,
activeWalletExchangeRates,
displayMoney,
exchangeRates,
limits,
sourceAccount,
sourceAmount,
Expand All @@ -23,9 +23,11 @@ const lifetimeAccountLimitsBetweenWalletsMessageFn = ({

if (
!sourceAccount.currency ||
!exchangeRates?.rates?.[sourceAccount.currency] ||
(sourceAccount.currency !== activeWallet.currency &&
!activeWalletExchangeRates?.rates?.[sourceAccount.currency]) ||
!targetAccount.currency ||
!exchangeRates?.rates?.[targetAccount.currency] ||
(targetAccount.currency !== activeWallet.currency &&
!activeWalletExchangeRates?.rates?.[targetAccount.currency]) ||
!sourceAccount.currencyConfig ||
!targetAccount.currencyConfig
)
Expand All @@ -35,10 +37,14 @@ const lifetimeAccountLimitsBetweenWalletsMessageFn = ({

const allowedSumConverted =
allowedSumActiveWalletCurrency *
(exchangeRates?.rates[transferDirection === 'from' ? targetAccount.currency : sourceAccount.currency] ?? 1);
(activeWalletExchangeRates?.rates?.[
transferDirection === 'from' ? targetAccount.currency : sourceAccount.currency
] ?? 1);
const availableSumConverted =
availableSumActiveWalletCurrency *
(exchangeRates?.rates[transferDirection === 'from' ? targetAccount.currency : sourceAccount.currency] ?? 1);
(activeWalletExchangeRates?.rates?.[
transferDirection === 'from' ? targetAccount.currency : sourceAccount.currency
] ?? 1);

const sourceCurrencyLimit = transferDirection === 'from' ? allowedSumActiveWalletCurrency : allowedSumConverted;
const targetCurrencyLimit = transferDirection === 'from' ? allowedSumConverted : allowedSumActiveWalletCurrency;
Expand Down Expand Up @@ -89,8 +95,8 @@ const lifetimeAccountLimitsBetweenWalletsMessageFn = ({
};

const cumulativeAccountLimitsMessageFn = ({
USDExchangeRates,
displayMoney,
exchangeRates,
limits,
sourceAccount,
sourceAmount,
Expand All @@ -112,19 +118,19 @@ const cumulativeAccountLimitsMessageFn = ({

if (
!sourceAccount.currency ||
!exchangeRates?.rates?.[sourceAccount.currency] ||
(sourceAccount.currency !== 'USD' && !USDExchangeRates?.rates?.[sourceAccount.currency]) ||
!targetAccount.currency ||
!exchangeRates?.rates?.[targetAccount.currency] ||
(targetAccount.currency !== 'USD' && !USDExchangeRates?.rates?.[targetAccount.currency]) ||
!sourceAccount.currencyConfig ||
!targetAccount.currencyConfig
)
return null;

const sourceCurrencyLimit = allowedSumUSD * (exchangeRates.rates[sourceAccount.currency] ?? 1);
const targetCurrencyLimit = allowedSumUSD * (exchangeRates.rates[targetAccount.currency] ?? 1);
const sourceCurrencyLimit = allowedSumUSD * (USDExchangeRates?.rates?.[sourceAccount.currency] ?? 1);
const targetCurrencyLimit = allowedSumUSD * (USDExchangeRates?.rates?.[targetAccount.currency] ?? 1);

const sourceCurrencyRemainder = availableSumUSD * (exchangeRates.rates[sourceAccount.currency] ?? 1);
const targetCurrencyRemainder = availableSumUSD * (exchangeRates.rates[targetAccount.currency] ?? 1);
const sourceCurrencyRemainder = availableSumUSD * (USDExchangeRates?.rates?.[sourceAccount.currency] ?? 1);
const targetCurrencyRemainder = availableSumUSD * (USDExchangeRates?.rates?.[targetAccount.currency] ?? 1);

const formattedSourceCurrencyLimit = displayMoney?.(
sourceCurrencyLimit,
Expand Down
Loading

0 comments on commit 164b965

Please sign in to comment.