}L)IkX#p(jIbLeMI+7O6})QDQ%!Z+<^_g^xIM3NncqfLquA=S;Q+>C`;K%|
zD#Hqg6`bn!h)f;;jZ70`MR;8aaoXwI&~^M=UMmfDout_bdz$J!_}sg#eo0VUIYZ&H
zckTV-1UjV*V>mho_p;)K07io1TwZ$NrJWc7wNa1rW@7lb}^cy}-N
zENaoSE_Pzl9m}qJUa(UcBC3V+rnlMJU!_ODC2I&;ZGsHNp34qii5lvF*=nr#UNWRI
zh;H0o6?jdUH5!!=OC0pADeNwyfXMdiy{ldN27YFsi?O32J*LD8%)QTq?sIdFni7tC
zC6TW-12mwZQ{(gK%;VlIx+Hv3ZOvr@Z2}2`8C6Hg);HQHn){huL8U!MW8B-NAI;6H
zOT#Di$hkQ`B_l7uA<5fj-wWSv*AMsrwts!HWQV$!bNVIAWNp}pEdVrX?R3#Uu8TEa
zgQ6~_kP@nvrDpe>iF^_MkpOjln}i@#j@
z?T*qfRfQL?r-@LNmI@{kmkp$tq*GOsek$=z1|1*Kdm&bxRFwBFEQ@ug@Sy(u`naNF
z!yi7q=Hw!}Ud$69cG*O~Dg#S=Cwb^g7*|y<3V7OI!=)3cH;vh{YgDQNkPuB_yNnV1
z?}9%D23xdQ6w)sWn?QiC_>`*H&vEF1r{(e(pZ3a|in4hxzIqYO95tOTi^H6N!0)V;
z_}kdS4c_oJ_+%X
zv@4>YL^~LlYrP@XRWnGlNDh0A5Dvxfg*cNO9TWB_;6SzbVCE)1G6+N3#!7k?31K(SI1m3
zspIsqEuhCqZGQe_rv5Dx7099f*P-N_Ujj0N8UisSz#Xw*R&h%>7njMHvKI}{Vu!rwMa`wrfMf2
z-F^_~B@_4lJ)iX;icSpVYhHLkh}2FUu7RiqHms*_ZE*|!`z;K>53RXUy+ScjNaMAS
zJ*yx-&?i4FP~Mz~HE%@d+dSM>{(EkNy*J_`7mpXwgmsDf;^!suVH^*k%%At+Ru_i-
zKzdfyOBZ5G@cV#|=Yn0)xq!qxi&<{`Di!wi#fG@qU*%$Y76C(PHaDyU`bVGY$
zS%IB>q2jFjX309My8ExGPcAb{%(LJ@HdWy=wsm_BkBQg4jzF5uqtV%hce{Ke&vtFxGS=wneIRUtFCGWQ3#>%UfpT*rVF@cr?n>9i$L
z7Z>3-*+l^kF1mIHNiD<3^`O{=6|}opi-Bt7pP##rxjIS-fHsBWlqvm-+9;Z->B6PVIt4mWDck*COM_Wv8zM4Yic-qYC
z<)j+OO935GLpt&S=$1BKLIWT^!k8?@boQ(rOw6lk=&{>8*8`!vp4T4osULw%$9soU
zG~yRN?<2H+p`axR3mP85bIlE?wNO&wX_^wfhNpmk`HSi
zYvXl&kzJB}SzkZF|xH
z9)dqY+m$7QVGd`2JGc_Id~TA~x!?43j--hrGn@@_=s%Z1Zl_h_YmUA}a>Ev5#u(N5
zt?0%%he%a`$f3`leK_A`h(vlC!U{#^ILEO_r8R}sUiw^@W9&&k{A{m8jtEfWRohY1
z(3)Sm-VnIVb>qsa7ut3uh)RpE!r>O?-+B6y1#L|(&x($oOq`BX*V+#NQ-BREv=1k}
zlCC6egPxt9C3#jnMvUk4u4kyHG2VkGzX#PsrAJEf&J65^Mt4Ss+iV~thP0Q_Zq~WI
z`lv70WlwlS**q8(vssPch}uGr54w%nSAQ7hviqoY5XSRo*<)!4b}z~}kKW%H@%NSL
zs(1P2DlYHf&ZcuAL>5MsPVG#InMuBJT!YL5Ncq<5(Cw_N70SFq-mc<$MG(u1eiHAE
zn|Eup#F%ixiTBub)Is6kS^3j}GX3VBcb2~jAqx=Iqw3C{JDVwV*L$l;7q_0Dj$W=xATmNqF&Lm7`=v_e5{!C8IoSS#SRR@=b
ziSJ_2GIYRZ339SEJKTJFPTj(e4uXW;Xz1y19gDBkh20O-1>tE2IgOP1l`Y}vsm20z
zKIiM>Z~Y1?3ib~3s_4FLXuZAMM=M@8>m`hr8`gIdoA9mx%^7G7{rT<`s7eW~#lx_5
ztaS6;&vHaoqi6@4S3eHvAZ%yk9h}3b_t~+}Fx6Z%lzl^~jB@%)fPUbGL`QZ#(jD`d>iE
z5Dq0|;dh4_#@br8gj{YK)2~x14C+06{FH5UZCFBj$s*K&jq~x`i0(0hh$`I8eU*3R
zLXWB6Q}tho^5MjNwk}7T8QLP=HGg0ryvzD;VuFhXh<-v@w<}BJE3JZ0@J=XU^R>Nu
z9=uimAO!46Ef_)Nc6@*$JR)v0+M;lu?jch9quTvV5!E!ZC&H|8bvp?F8fmdC_
zuEV@n#sV7jyFoPLEJSPA4touH&0xz8YY@yBM@8uDZ>vh
zsdr!*7G}~nPj^z+8x4qk@hOC=>++A=x5oLH+bG%pP2+!FO6@P6)r*GRRKKiJy2hji
zsu{fCuMY8~IV`0Aw4?_ED(OAyd@+YI)%%)T2RVL};`=&uu2H%kF|dwsmn=7jil
zvs*7N_N_(O5lF&OUzpBLN?aMj%UFLvS1#;@lE1mm9}28jAv|?0r#bCeBNaQ|s+V_O
zHj;>uzo6UsGCP{V!cp%l^pIi_gy=#{dlFLk+1~Og7Y|%@B7Y2MEq70f8a>_dJ1Q~2
zk8}&(pcQj@dUUbvGjw)x-Y)1WM&3xa-u?5i&g2>An=0ZAlrlPgIA>^arvHXSoU
zhtK}OXHi*(cWdEo<)NPOBLrom8Smi*qu-rm4e7AgnLq!LeZ!*R*|qU{yUX#^(FGuB
ze+*U6SR2woXC1%^^WVKW3vXu8)^1iv-ICI{Dt7BlsM1%S=)RMD77{ktWFFUK++1_I
z7vKNLcm4#jw^$?ln~Q7rRhfqh=D2JJh~P)*lKscPCal#<_f9Sj?*4X*^I+v^a|7=_
zUt~wlFw+guZ=Q@7kpB!s-3k@jPq+^s8KPxbY#tCEMPn%?MS&lF!9^588RKYh-?I^3
zbL8{%5z4oUb<_wY5oHk-ExRDVBy^*LYRXBj388gW4TIP@?Qg1ZKT)~m
z)Ikitc(xpU+e`L;g@YMA(jBCZCK@#5=&o3mp_gAWWbW0{<4lNY-vs$t3Z5L-oP8>=
zo#%M!?0sD>80|^$hR_K(R6ax-3A^*m!bkRo
zs-Vq~xN?D0_T?pK;3GH=sDL6{eyU1u_&{8U##VdG3TVCj9JYHr$xg5_1)~d2$+oeU
zXv1m4g*hf-+53-tvs&PkV9ztDE7<$
z_T#`1sX@vgHj8n4Z?7_a9m_nZ{?<*j&5QF#6l@+gem{Q)#kx@EaYzz3_eWxK&ibC&
zq>zuK?xbQU)oq4;W@Ap?7!8VA_d5o4x`>b~4UB$3m*T--JZKBfBNCkESuCDaj3jno&tdp-<325
z=11`ND`!}>(=BkaB>_nll>sCf-F^9Fa#dK>LudXEXm32XP-KVTZtW|Vo)0Ai>xnZT
z*6mciSBmEz7K0UA&G>EfWO)tCf{eW%q$cGLJU5bp$aFV1XSi=cA&h5O@v|Ar1VNF7soC)U*I
zR*Y#^oW+tFn*d%M_G_-5_kFiX-f*0hA!mADd&>S@7ym7qy5-?T7)Mh4#im{w$umZH
z{8!e-l77FlI%LMN9Q?PbhcHK`Dy1B~=}zCe68ELTC`I?oykEV`R0ip$;U~}FX4MVb
zY}Ot6B!CgT>1H*d4s_#7Wpx%_mv21p`=>o;x(&L-?B95Je>_bs^S;%Y_Ui@D=0>TK
zK>FAnaO6u#mD~0p#=6JHn^sBHAj`Yj1o+&E<(Bix#f$j`o8uM3n8y=x|6XZ9I7vS+
zE&EdpjF$7SbLzN1gmmgOo}QYmB{5k`Z0d9u+)WzO3LLDr1Db=r%-bGYv*=?`$1q=l}8o
zjrNba{yI(?W1d36P91ZZ7O-j6TD(@?Y|zUO)r(`4LSmvM`wbKoS7NfX=Myi3DLGYr@XsyY8
zv7GUx359Yh()s9|dUZ@itXvWd)~}ISxLR~yT@7pLtIr_mxo;#w9_QfIy}TMW*ReG0
z{`s17UHsei@tDf)NV>2QdsL+EiJDS8GuSJqBXMlKKyjIbKXAX-tU5s~~EU=2gIW}NnioY+Xfkgdl(m*ikwn|zbBo-4y^
zQ`Ot+?LgW%1`F0xR%Bv0@`4g%5I^bR67ssjBnk+@%D7Y#$%q^d*
z3RhZt%&QJ|{wSfyBPK9T%Mn@jT2GbTQ_T^;l!oJ&{7pF%sWI@YYU--b2wdi4vRtgF
z$S!udF;faK$loN)>hX3E;rLw30g>IY4cSH&>qk!x?S!;>b4xUK({wmqRcyLmh
z0UcDV*S88QMw?IKaMS^$qG_o0{6%7>dN`#abjvJ<~
z_{!<Bq``)5ve6IES_@Qm%lr@$3Vz
zuO~MGZItzMc}(&e3G?Hw5x$SJj)FIEKK{h|?thzCK#&8o1=`GJW`dy~PMVvHL^wxO
zL?Z7eiK8YB@rwx~u{gP;3}?T&mzh=O!9Q60!Q1uHAhPWSUBa!vaPZ@r1+l8pwa#{j
zZM*n8i(8qDSoK4JfAbGV#>v)KXQ4-ip5}9uF>cl8L~I$Y{z>(KACK$iLZj^rB#<*Z
zbP?bV+~?WAVK7HcY0e;x>+d+96l}!E7A0N*p{aIskQZ$l`GNh7w8{a0r>>RFuq96m
z^pCTLcd-h?ThC+m$K=_*r*F3;Ib4RJ2}6`meTm|V>(l83SZTZOsln&~PCMk9sLT3{
z-wSE(0<0o3<^B~B`;W1Rh!%tb`#k>Tjc@Ag)63L_<|9pq(RIHU3JDI_e;G!T^P}6r
zri`ScTZ|01h68;aJLWx_x=l?2ax4p&2ZHWyL?&oy4?V2zZn7ck3cm!DHgctM%ja?z
ze-qZ!a$7ZaDpp49Ne2tOQXvc8x3^ioxj}^NgMQp
Date: Tue, 19 Dec 2023 16:20:01 +0400
Subject: [PATCH 009/187] [WALL] Aum/WALL-3091/positive demo transfer wallet to
app messages (#12277)
* feat: added cumulative transfer messages for demo transfer
* chore: fixed the formatting of the limit in message
* refactor: moved message functions into separate files
* chore: fixed merge conflict and added changes for the message functions
* chore: fixed cTrader issue and limits updates
---
.../useTransferMessages.ts | 4 +-
.../utils/cumulativeAccountLimitsMessageFn.ts | 126 ++++++++++
.../hooks/useTransferMessages/utils/index.ts | 9 +
...imeAccountLimitsBetweenWalletsMessageFn.ts | 97 ++++++++
.../utils/messageFunctions.ts | 220 ------------------
.../transferFeesBetweenWalletsMessageFn.ts | 36 +++
.../Transfer/provider/TransferProvider.tsx | 3 +-
7 files changed, 272 insertions(+), 223 deletions(-)
create mode 100644 packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/cumulativeAccountLimitsMessageFn.ts
create mode 100644 packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/index.ts
create mode 100644 packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/lifetimeAccountLimitsBetweenWalletsMessageFn.ts
delete mode 100644 packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/messageFunctions.ts
create mode 100644 packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/transferFeesBetweenWalletsMessageFn.ts
diff --git a/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/useTransferMessages.ts b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/useTransferMessages.ts
index e195b4cd42ce..16af4bdbb567 100644
--- a/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/useTransferMessages.ts
+++ b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/useTransferMessages.ts
@@ -3,12 +3,12 @@ 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';
+import { TMessage, TMessageFnProps } from './types';
import {
cumulativeAccountLimitsMessageFn,
lifetimeAccountLimitsBetweenWalletsMessageFn,
transferFeesBetweenWalletsMessageFn,
-} from './utils/messageFunctions';
-import { TMessage, TMessageFnProps } from './types';
+} from './utils';
type TProps = {
USDExchangeRates?: THooks.ExchangeRate;
diff --git a/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/cumulativeAccountLimitsMessageFn.ts b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/cumulativeAccountLimitsMessageFn.ts
new file mode 100644
index 000000000000..17bd401c1f66
--- /dev/null
+++ b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/cumulativeAccountLimitsMessageFn.ts
@@ -0,0 +1,126 @@
+import { TMessageFnProps } from '../types';
+
+const cumulativeAccountLimitsMessageFn = ({
+ activeWallet,
+ activeWalletExchangeRates,
+ displayMoney,
+ limits,
+ sourceAccount,
+ sourceAmount,
+ targetAccount,
+}: TMessageFnProps) => {
+ const isTransferBetweenWallets =
+ sourceAccount.account_category === 'wallet' && targetAccount.account_category === 'wallet';
+ const isSameCurrency = sourceAccount.currency === targetAccount.currency;
+
+ const isDemoTransfer = activeWallet?.is_virtual;
+
+ const keyAccountType =
+ [sourceAccount, targetAccount].find(acc => acc.account_category !== 'wallet')?.account_type ?? 'wallets';
+
+ const platformKey = keyAccountType === 'standard' ? 'dtrade' : keyAccountType;
+
+ const allowedSumUSD = isDemoTransfer
+ ? //@ts-expect-error needs backend type
+ (limits?.daily_cumulative_amount_transfers?.virtual?.allowed as number)
+ : //@ts-expect-error needs backend type
+ (limits?.daily_cumulative_amount_transfers?.[platformKey]?.allowed as number);
+
+ const availableSumUSD = isDemoTransfer
+ ? //@ts-expect-error needs backend type
+ (limits?.daily_cumulative_amount_transfers?.virtual?.available as number)
+ : //@ts-expect-error needs backend type
+ (limits?.daily_cumulative_amount_transfers?.[platformKey]?.available as number);
+
+ if (
+ !sourceAccount.currency ||
+ !targetAccount.currency ||
+ !sourceAccount.currencyConfig ||
+ !targetAccount.currencyConfig
+ )
+ return null;
+
+ const formattedDemoLimit = displayMoney?.(
+ availableSumUSD,
+ sourceAccount.currencyConfig.display_code,
+ sourceAccount.currencyConfig.fractional_digits
+ );
+
+ if (isDemoTransfer) {
+ if (allowedSumUSD === availableSumUSD) {
+ return {
+ text: `Your daily transfer limit for virtual funds is ${formattedDemoLimit}.`,
+ type: 'success',
+ } as const;
+ }
+ return {
+ text: `Your remaining daily transfer limit for virtual funds is ${formattedDemoLimit}.`,
+ type: 'success',
+ } as const;
+ }
+
+ // separated the exchangeRates check to prevent checking for demo transfer
+ if (
+ (sourceAccount.currency !== activeWallet.currency &&
+ !activeWalletExchangeRates?.rates?.[sourceAccount.currency]) ||
+ (targetAccount.currency !== activeWallet.currency &&
+ !activeWalletExchangeRates?.rates?.[targetAccount.currency])
+ )
+ return null;
+
+ const sourceCurrencyLimit = allowedSumUSD * (activeWalletExchangeRates?.rates?.[sourceAccount.currency] ?? 1);
+ const targetCurrencyLimit = allowedSumUSD * (activeWalletExchangeRates?.rates?.[targetAccount.currency] ?? 1);
+
+ const sourceCurrencyRemainder = availableSumUSD * (activeWalletExchangeRates?.rates?.[sourceAccount.currency] ?? 1);
+ const targetCurrencyRemainder = availableSumUSD * (activeWalletExchangeRates?.rates?.[targetAccount.currency] ?? 1);
+
+ const formattedSourceCurrencyLimit = displayMoney?.(
+ sourceCurrencyLimit,
+ sourceAccount.currencyConfig.display_code,
+ sourceAccount.currencyConfig.fractional_digits
+ );
+ const formattedTargetCurrencyLimit = displayMoney?.(
+ targetCurrencyLimit,
+ targetAccount.currencyConfig.display_code,
+ targetAccount.currencyConfig?.fractional_digits
+ );
+
+ const formattedSourceCurrencyRemainder = displayMoney?.(
+ sourceCurrencyRemainder,
+ sourceAccount.currencyConfig.display_code,
+ sourceAccount.currencyConfig.fractional_digits
+ );
+ const formattedTargetCurrencyRemainder = displayMoney?.(
+ targetCurrencyRemainder,
+ targetAccount.currencyConfig?.display_code,
+ targetAccount.currencyConfig?.fractional_digits
+ );
+
+ if (availableSumUSD === 0)
+ return {
+ text: `You have reached your daily transfer limit of ${formattedSourceCurrencyLimit} ${
+ !isSameCurrency ? ` (${formattedTargetCurrencyLimit})` : ''
+ } between your ${
+ isTransferBetweenWallets ? 'Wallets' : `${sourceAccount.accountName} and ${targetAccount.accountName}`
+ }. The limit will reset at 00:00 GMT.`,
+ type: 'error' as const,
+ };
+
+ if (allowedSumUSD === availableSumUSD) {
+ return {
+ text: `The daily transfer limit between your ${
+ isTransferBetweenWallets ? 'Wallets' : `${sourceAccount.accountName} and ${targetAccount.accountName}`
+ } is ${formattedSourceCurrencyLimit}${!isSameCurrency ? ` (${formattedTargetCurrencyLimit})` : ''}.`,
+ type: sourceAmount > sourceCurrencyRemainder ? ('error' as const) : ('success' as const),
+ };
+ }
+
+ return {
+ text: `The remaining daily transfer limit between ${
+ isTransferBetweenWallets ? 'Wallets' : `your ${sourceAccount.accountName} and ${targetAccount.accountName}`
+ } is ${formattedSourceCurrencyRemainder}${!isSameCurrency ? ` (${formattedTargetCurrencyRemainder})` : ''}.`,
+ type: sourceAmount > sourceCurrencyRemainder ? ('error' as const) : ('success' as const),
+ };
+};
+
+export default cumulativeAccountLimitsMessageFn;
diff --git a/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/index.ts b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/index.ts
new file mode 100644
index 000000000000..4239f0a0977a
--- /dev/null
+++ b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/index.ts
@@ -0,0 +1,9 @@
+import cumulativeAccountLimitsMessageFn from './cumulativeAccountLimitsMessageFn';
+import lifetimeAccountLimitsBetweenWalletsMessageFn from './lifetimeAccountLimitsBetweenWalletsMessageFn';
+import transferFeesBetweenWalletsMessageFn from './transferFeesBetweenWalletsMessageFn';
+
+export {
+ cumulativeAccountLimitsMessageFn,
+ lifetimeAccountLimitsBetweenWalletsMessageFn,
+ transferFeesBetweenWalletsMessageFn,
+};
diff --git a/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/lifetimeAccountLimitsBetweenWalletsMessageFn.ts b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/lifetimeAccountLimitsBetweenWalletsMessageFn.ts
new file mode 100644
index 000000000000..94a700b432cb
--- /dev/null
+++ b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/lifetimeAccountLimitsBetweenWalletsMessageFn.ts
@@ -0,0 +1,97 @@
+import { TMessageFnProps } from '../types';
+
+// this function should work once BE WALL-1440 is delivered
+const lifetimeAccountLimitsBetweenWalletsMessageFn = ({
+ activeWallet,
+ activeWalletExchangeRates,
+ displayMoney,
+ limits,
+ sourceAccount,
+ sourceAmount,
+ targetAccount,
+}: TMessageFnProps) => {
+ if (sourceAccount?.account_category !== 'wallet' || targetAccount?.account_category !== 'wallet') return null;
+
+ const sourceWalletType = sourceAccount.account_type === 'crypto' ? 'crypto' : 'fiat';
+ const targetWalletType = targetAccount.account_type === 'crypto' ? 'crypto' : 'fiat';
+ const limitsCaseKey = `${sourceWalletType}_to_${targetWalletType}` as const;
+
+ //@ts-expect-error needs backend type
+ const allowedSumActiveWalletCurrency = limits?.lifetime_transfers?.[limitsCaseKey]?.allowed as number;
+ //@ts-expect-error needs backend type
+ const availableSumActiveWalletCurrency = limits?.lifetime_transfers?.[limitsCaseKey]?.available as number;
+
+ if (
+ !sourceAccount.currency ||
+ (sourceAccount.currency !== activeWallet.currency &&
+ !activeWalletExchangeRates?.rates?.[sourceAccount.currency]) ||
+ !targetAccount.currency ||
+ (targetAccount.currency !== activeWallet.currency &&
+ !activeWalletExchangeRates?.rates?.[targetAccount.currency]) ||
+ !sourceAccount.currencyConfig ||
+ !targetAccount.currencyConfig
+ )
+ return null;
+
+ const transferDirection = activeWallet.loginid === sourceAccount.loginid ? 'from' : 'to';
+
+ const allowedSumConverted =
+ allowedSumActiveWalletCurrency *
+ (activeWalletExchangeRates?.rates?.[
+ transferDirection === 'from' ? targetAccount.currency : sourceAccount.currency
+ ] ?? 1);
+ const availableSumConverted =
+ availableSumActiveWalletCurrency *
+ (activeWalletExchangeRates?.rates?.[
+ transferDirection === 'from' ? targetAccount.currency : sourceAccount.currency
+ ] ?? 1);
+
+ const sourceCurrencyLimit = transferDirection === 'from' ? allowedSumActiveWalletCurrency : allowedSumConverted;
+ const targetCurrencyLimit = transferDirection === 'from' ? allowedSumConverted : allowedSumActiveWalletCurrency;
+
+ const sourceCurrencyRemainder =
+ transferDirection === 'from' ? availableSumActiveWalletCurrency : availableSumConverted;
+ const targetCurrencyRemainder =
+ transferDirection === 'from' ? availableSumConverted : availableSumActiveWalletCurrency;
+
+ const formattedSourceCurrencyLimit = displayMoney?.(
+ sourceCurrencyLimit,
+ sourceAccount.currencyConfig.display_code,
+ sourceAccount.currencyConfig.fractional_digits
+ );
+ const formattedTargetCurrencyLimit = displayMoney?.(
+ targetCurrencyLimit,
+ targetAccount.currencyConfig.display_code,
+ targetAccount.currencyConfig?.fractional_digits
+ );
+
+ const formattedSourceCurrencyRemainder = displayMoney?.(
+ sourceCurrencyRemainder,
+ sourceAccount.currencyConfig.display_code,
+ sourceAccount.currencyConfig.fractional_digits
+ );
+ const formattedTargetCurrencyRemainder = displayMoney?.(
+ targetCurrencyRemainder,
+ targetAccount.currencyConfig?.display_code,
+ targetAccount.currencyConfig?.fractional_digits
+ );
+
+ if (availableSumActiveWalletCurrency === 0)
+ return {
+ text: `You've reached the lifetime transfer limit from your ${sourceAccount.accountName} to any ${targetWalletType} Wallet. Verify your account to upgrade the limit.`,
+ type: 'error' as const,
+ };
+
+ if (allowedSumActiveWalletCurrency === availableSumActiveWalletCurrency)
+ return {
+ text: `The lifetime transfer limit from ${sourceAccount.accountName} to any ${targetWalletType} Wallet is ${formattedSourceCurrencyLimit} (${formattedTargetCurrencyLimit}).`,
+ type: sourceAmount > sourceCurrencyRemainder ? ('error' as const) : ('success' as const),
+ };
+
+ return {
+ text: `Remaining lifetime transfer limit is ${formattedSourceCurrencyRemainder} (${formattedTargetCurrencyRemainder}). Verify your account to upgrade the limit.`,
+ type: sourceAmount > sourceCurrencyRemainder ? ('error' as const) : ('success' as const),
+ };
+};
+
+export default lifetimeAccountLimitsBetweenWalletsMessageFn;
diff --git a/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/messageFunctions.ts b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/messageFunctions.ts
deleted file mode 100644
index d6393c95165e..000000000000
--- a/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/messageFunctions.ts
+++ /dev/null
@@ -1,220 +0,0 @@
-import { TMessageFnProps } from '../types';
-
-// this function should work once BE WALL-1440 is delivered
-const lifetimeAccountLimitsBetweenWalletsMessageFn = ({
- activeWallet,
- activeWalletExchangeRates,
- displayMoney,
- limits,
- sourceAccount,
- sourceAmount,
- targetAccount,
-}: TMessageFnProps) => {
- if (sourceAccount?.account_category !== 'wallet' || targetAccount?.account_category !== 'wallet') return null;
-
- const sourceWalletType = sourceAccount.account_type === 'crypto' ? 'crypto' : 'fiat';
- const targetWalletType = targetAccount.account_type === 'crypto' ? 'crypto' : 'fiat';
- const limitsCaseKey = `${sourceWalletType}_to_${targetWalletType}` as const;
-
- //@ts-expect-error needs backend type
- const allowedSumActiveWalletCurrency = limits?.lifetime_transfers?.[limitsCaseKey].allowed as number;
- //@ts-expect-error needs backend type
- const availableSumActiveWalletCurrency = limits?.lifetime_transfers?.[limitsCaseKey].available as number;
-
- if (
- !sourceAccount.currency ||
- (sourceAccount.currency !== activeWallet.currency &&
- !activeWalletExchangeRates?.rates?.[sourceAccount.currency]) ||
- !targetAccount.currency ||
- (targetAccount.currency !== activeWallet.currency &&
- !activeWalletExchangeRates?.rates?.[targetAccount.currency]) ||
- !sourceAccount.currencyConfig ||
- !targetAccount.currencyConfig
- )
- return null;
-
- const transferDirection = activeWallet.loginid === sourceAccount.loginid ? 'from' : 'to';
-
- const allowedSumConverted =
- allowedSumActiveWalletCurrency *
- (activeWalletExchangeRates?.rates?.[
- transferDirection === 'from' ? targetAccount.currency : sourceAccount.currency
- ] ?? 1);
- const availableSumConverted =
- availableSumActiveWalletCurrency *
- (activeWalletExchangeRates?.rates?.[
- transferDirection === 'from' ? targetAccount.currency : sourceAccount.currency
- ] ?? 1);
-
- const sourceCurrencyLimit = transferDirection === 'from' ? allowedSumActiveWalletCurrency : allowedSumConverted;
- const targetCurrencyLimit = transferDirection === 'from' ? allowedSumConverted : allowedSumActiveWalletCurrency;
-
- const sourceCurrencyRemainder =
- transferDirection === 'from' ? availableSumActiveWalletCurrency : availableSumConverted;
- const targetCurrencyRemainder =
- transferDirection === 'from' ? availableSumConverted : availableSumActiveWalletCurrency;
-
- const formattedSourceCurrencyLimit = displayMoney?.(
- sourceCurrencyLimit,
- sourceAccount.currencyConfig.display_code,
- sourceAccount.currencyConfig.fractional_digits
- );
- const formattedTargetCurrencyLimit = displayMoney?.(
- targetCurrencyLimit,
- targetAccount.currencyConfig.display_code,
- targetAccount.currencyConfig?.fractional_digits
- );
-
- const formattedSourceCurrencyRemainder = displayMoney?.(
- sourceCurrencyRemainder,
- sourceAccount.currencyConfig.display_code,
- sourceAccount.currencyConfig.fractional_digits
- );
- const formattedTargetCurrencyRemainder = displayMoney?.(
- targetCurrencyRemainder,
- targetAccount.currencyConfig?.display_code,
- targetAccount.currencyConfig?.fractional_digits
- );
-
- if (availableSumActiveWalletCurrency === 0)
- return {
- text: `You've reached the lifetime transfer limit from your ${sourceAccount.accountName} to any ${targetWalletType} Wallet. Verify your account to upgrade the limit.`,
- type: 'error' as const,
- };
-
- if (allowedSumActiveWalletCurrency === availableSumActiveWalletCurrency)
- return {
- text: `The lifetime transfer limit from ${sourceAccount.accountName} to any ${targetWalletType} Wallet is ${formattedSourceCurrencyLimit} (${formattedTargetCurrencyLimit}).`,
- type: sourceAmount > sourceCurrencyRemainder ? ('error' as const) : ('success' as const),
- };
-
- return {
- text: `Remaining lifetime transfer limit is ${formattedSourceCurrencyRemainder} (${formattedTargetCurrencyRemainder}). Verify your account to upgrade the limit.`,
- type: sourceAmount > sourceCurrencyRemainder ? ('error' as const) : ('success' as const),
- };
-};
-
-const cumulativeAccountLimitsMessageFn = ({
- USDExchangeRates,
- displayMoney,
- limits,
- sourceAccount,
- sourceAmount,
- targetAccount,
-}: TMessageFnProps) => {
- const isTransferBetweenWallets =
- sourceAccount.account_category === 'wallet' && targetAccount.account_category === 'wallet';
- const isSameCurrency = sourceAccount.currency === targetAccount.currency;
-
- const keyAccountType =
- [sourceAccount, targetAccount].find(acc => acc.account_category !== 'wallet')?.account_type ?? 'wallets';
-
- const platformKey = keyAccountType === 'standard' ? 'dtrade' : keyAccountType;
-
- //@ts-expect-error needs backend type
- const allowedSumUSD = limits?.daily_cumulative_amount_transfers?.[platformKey].allowed as number;
- //@ts-expect-error needs backend type
- const availableSumUSD = limits?.daily_cumulative_amount_transfers?.[platformKey].available as number;
-
- if (
- !sourceAccount.currency ||
- (sourceAccount.currency !== 'USD' && !USDExchangeRates?.rates?.[sourceAccount.currency]) ||
- !targetAccount.currency ||
- (targetAccount.currency !== 'USD' && !USDExchangeRates?.rates?.[targetAccount.currency]) ||
- !sourceAccount.currencyConfig ||
- !targetAccount.currencyConfig
- )
- return null;
-
- const sourceCurrencyLimit = allowedSumUSD * (USDExchangeRates?.rates?.[sourceAccount.currency] ?? 1);
- const targetCurrencyLimit = allowedSumUSD * (USDExchangeRates?.rates?.[targetAccount.currency] ?? 1);
-
- const sourceCurrencyRemainder = availableSumUSD * (USDExchangeRates?.rates?.[sourceAccount.currency] ?? 1);
- const targetCurrencyRemainder = availableSumUSD * (USDExchangeRates?.rates?.[targetAccount.currency] ?? 1);
-
- const formattedSourceCurrencyLimit = displayMoney?.(
- sourceCurrencyLimit,
- sourceAccount.currencyConfig.display_code,
- sourceAccount.currencyConfig.fractional_digits
- );
- const formattedTargetCurrencyLimit = displayMoney?.(
- targetCurrencyLimit,
- targetAccount.currencyConfig.display_code,
- targetAccount.currencyConfig?.fractional_digits
- );
-
- const formattedSourceCurrencyRemainder = displayMoney?.(
- sourceCurrencyRemainder,
- sourceAccount.currencyConfig.display_code,
- sourceAccount.currencyConfig.fractional_digits
- );
- const formattedTargetCurrencyRemainder = displayMoney?.(
- targetCurrencyRemainder,
- targetAccount.currencyConfig?.display_code,
- targetAccount.currencyConfig?.fractional_digits
- );
-
- if (availableSumUSD === 0)
- return {
- text: `You have reached your daily transfer limit of ${formattedSourceCurrencyLimit} ${
- !isSameCurrency ? ` (${formattedTargetCurrencyLimit})` : ''
- } between your ${
- isTransferBetweenWallets ? 'Wallets' : `${sourceAccount.accountName} and ${targetAccount.accountName}`
- }. The limit will reset at 00:00 GMT.`,
- type: 'error' as const,
- };
-
- if (allowedSumUSD === availableSumUSD)
- return {
- text: `The daily transfer limit between your ${
- isTransferBetweenWallets ? 'Wallets' : `${sourceAccount.accountName} and ${targetAccount.accountName}`
- } is ${formattedSourceCurrencyLimit}${!isSameCurrency ? ` (${formattedTargetCurrencyLimit})` : ''}.`,
- type: sourceAmount > sourceCurrencyRemainder ? ('error' as const) : ('success' as const),
- };
-
- return {
- text: `The remaining daily transfer limit between ${
- isTransferBetweenWallets ? 'Wallets' : `your ${sourceAccount.accountName} and ${targetAccount.accountName}`
- } is ${formattedSourceCurrencyRemainder}${!isSameCurrency ? ` (${formattedTargetCurrencyRemainder})` : ''}.`,
- type: sourceAmount > sourceCurrencyRemainder ? ('error' as const) : ('success' as const),
- };
-};
-
-const transferFeesBetweenWalletsMessageFn = ({
- displayMoney,
- sourceAccount,
- sourceAmount,
- targetAccount,
-}: TMessageFnProps) => {
- if (!sourceAccount.currency || !sourceAccount.currencyConfig || !sourceAmount || !targetAccount.currency)
- return null;
-
- const minimumFeeAmount = 1 / Math.pow(10, sourceAccount.currencyConfig.fractional_digits);
-
- const minimumFeeText = displayMoney?.(
- minimumFeeAmount,
- sourceAccount.currency,
- sourceAccount.currencyConfig.fractional_digits
- );
-
- const feePercentage = sourceAccount.currencyConfig?.transfer_between_accounts.fees[targetAccount.currency];
-
- const feeAmount = (feePercentage * sourceAmount) / 100;
-
- const feeMessageText = displayMoney?.(
- feeAmount > minimumFeeAmount ? feeAmount : minimumFeeAmount,
- sourceAccount.currency,
- sourceAccount.currencyConfig.fractional_digits
- );
-
- return {
- text: `Fee: ${feeMessageText} (${feePercentage}% transfer fee or ${minimumFeeText}, whichever is higher, applies for fund transfers between your ${targetAccount.accountName} and cryptocurrency Wallets)`,
- type: 'info' as const,
- };
-};
-
-export {
- cumulativeAccountLimitsMessageFn,
- lifetimeAccountLimitsBetweenWalletsMessageFn,
- transferFeesBetweenWalletsMessageFn,
-};
diff --git a/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/transferFeesBetweenWalletsMessageFn.ts b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/transferFeesBetweenWalletsMessageFn.ts
new file mode 100644
index 000000000000..f752914e924d
--- /dev/null
+++ b/packages/wallets/src/features/cashier/modules/Transfer/hooks/useTransferMessages/utils/transferFeesBetweenWalletsMessageFn.ts
@@ -0,0 +1,36 @@
+import { TMessageFnProps } from '../types';
+
+const transferFeesBetweenWalletsMessageFn = ({
+ displayMoney,
+ sourceAccount,
+ sourceAmount,
+ targetAccount,
+}: TMessageFnProps) => {
+ if (!sourceAccount.currency || !sourceAccount.currencyConfig || !sourceAmount || !targetAccount.currency)
+ return null;
+
+ const minimumFeeAmount = 1 / Math.pow(10, sourceAccount.currencyConfig.fractional_digits);
+
+ const minimumFeeText = displayMoney?.(
+ minimumFeeAmount,
+ sourceAccount.currency,
+ sourceAccount.currencyConfig.fractional_digits
+ );
+
+ const feePercentage = sourceAccount.currencyConfig?.transfer_between_accounts.fees[targetAccount.currency];
+
+ const feeAmount = (feePercentage * sourceAmount) / 100;
+
+ const feeMessageText = displayMoney?.(
+ feeAmount > minimumFeeAmount ? feeAmount : minimumFeeAmount,
+ sourceAccount.currency,
+ sourceAccount.currencyConfig.fractional_digits
+ );
+
+ return {
+ text: `Fee: ${feeMessageText} (${feePercentage}% transfer fee or ${minimumFeeText}, whichever is higher, applies for fund transfers between your ${targetAccount.accountName} and cryptocurrency Wallets)`,
+ type: 'info' as const,
+ };
+};
+
+export default transferFeesBetweenWalletsMessageFn;
diff --git a/packages/wallets/src/features/cashier/modules/Transfer/provider/TransferProvider.tsx b/packages/wallets/src/features/cashier/modules/Transfer/provider/TransferProvider.tsx
index 1b09a0ddc1a9..cce38b5e790e 100644
--- a/packages/wallets/src/features/cashier/modules/Transfer/provider/TransferProvider.tsx
+++ b/packages/wallets/src/features/cashier/modules/Transfer/provider/TransferProvider.tsx
@@ -108,8 +108,9 @@ const TransferProvider: React.FC> = ({ accounts:
const resetTransfer = useCallback(() => {
setReceipt(undefined);
+ refetchAccountLimits();
requestTransferAccounts();
- }, [requestTransferAccounts]);
+ }, [refetchAccountLimits, requestTransferAccounts]);
useEffect(() => {
if (!transferAccounts) requestTransferAccounts();
From 6f3d3fe82405a80dadcce5cd8eb8d3fee690f830 Mon Sep 17 00:00:00 2001
From: yauheni-deriv <103182683+yauheni-deriv@users.noreply.github.com>
Date: Tue, 19 Dec 2023 16:44:30 +0300
Subject: [PATCH 010/187] fix: [COJ]/evgeniy/coj-423/fix handling unusual IDV
errors (#12340)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: “yauheni-kryzhyk-deriv” <“yauheni@deriv.me”>
---
packages/shared/src/utils/helpers/format-response.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/shared/src/utils/helpers/format-response.ts b/packages/shared/src/utils/helpers/format-response.ts
index 3797749d42f0..d3a6f6e38f4f 100644
--- a/packages/shared/src/utils/helpers/format-response.ts
+++ b/packages/shared/src/utils/helpers/format-response.ts
@@ -93,7 +93,7 @@ export const formatIDVError = (errors: Array, status_code: stri
const status: Array = [];
errors.forEach(error => {
- const error_key: TIDVErrorStatus = IDV_ERROR_STATUS[error].code;
+ const error_key: TIDVErrorStatus = IDV_ERROR_STATUS[error]?.code;
if (error_key) {
status.push(error_key);
}
From dd87fb09e05532ff301b9c5fcf498563093a531c Mon Sep 17 00:00:00 2001
From: maryia-matskevich-deriv
<103181650+maryia-matskevich-deriv@users.noreply.github.com>
Date: Wed, 20 Dec 2023 04:35:53 +0300
Subject: [PATCH 011/187] [BOT] Maryia/test: recent component from load-modal
folder (#12343)
* test: recent component from load-modal folder
* fix: remove isMobile
---
.../load-modal/__tests__/recent.spec.tsx | 62 +++++++++++++++++++
.../bot-web-ui/src/stores/load-modal-store.ts | 8 +--
2 files changed, 66 insertions(+), 4 deletions(-)
create mode 100644 packages/bot-web-ui/src/components/load-modal/__tests__/recent.spec.tsx
diff --git a/packages/bot-web-ui/src/components/load-modal/__tests__/recent.spec.tsx b/packages/bot-web-ui/src/components/load-modal/__tests__/recent.spec.tsx
new file mode 100644
index 000000000000..3cea3ec1984c
--- /dev/null
+++ b/packages/bot-web-ui/src/components/load-modal/__tests__/recent.spec.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import { mockStore, StoreProvider } from '@deriv/stores';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { render, screen } from '@testing-library/react';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { mock_ws } from 'Utils/mock';
+import { DBotStoreProvider, mockDBotStore } from 'Stores/useDBotStore';
+import Recent from '../recent';
+
+jest.mock('@deriv/bot-skeleton/src/scratch/blockly', () => jest.fn());
+jest.mock('@deriv/bot-skeleton/src/scratch/dbot', () => ({}));
+jest.mock('@deriv/bot-skeleton/src/scratch/hooks/block_svg', () => jest.fn());
+
+const strategy = {
+ name: '',
+ xml: '',
+ save_type: '',
+ timestamp: 1,
+};
+
+const recent_strategies = [
+ { ...strategy, name: 'martingale', id: '1' },
+ { ...strategy, name: 'd_alembert', id: '2' },
+ { ...strategy, name: 'oscar_grind', id: '3' },
+];
+
+describe('Recent component of load modal', () => {
+ let wrapper: ({ children }: { children: JSX.Element }) => JSX.Element;
+
+ const mock_store = mockStore({});
+ const mock_DBot_store = mockDBotStore(mock_store, mock_ws);
+
+ beforeAll(() => {
+ wrapper = ({ children }: { children: JSX.Element }) => (
+
+
+ {children}
+
+
+ );
+ });
+
+ it('should render Recent component without any recent bots strategies when recent_strategies array is empty', () => {
+ const { container } = render(, { wrapper });
+
+ const text_message = screen.getByText('You do not have any recent bots');
+ expect(text_message).toBeInTheDocument();
+ expect(container).toBeInTheDocument();
+ });
+
+ it('should render Recent component with recent bots strategies, title and preview when recent_strategies are exist', () => {
+ mock_DBot_store?.load_modal.setRecentStrategies(recent_strategies);
+ const { container } = render(, { wrapper });
+
+ const strategies_title = screen.getByText('Recent');
+ const strategy_previw = screen.getByText('Preview');
+
+ expect(strategies_title).toBeInTheDocument();
+ expect(strategy_previw).toBeInTheDocument();
+ expect(container).toBeInTheDocument();
+ });
+});
diff --git a/packages/bot-web-ui/src/stores/load-modal-store.ts b/packages/bot-web-ui/src/stores/load-modal-store.ts
index deba5863dfa0..b020254e0649 100644
--- a/packages/bot-web-ui/src/stores/load-modal-store.ts
+++ b/packages/bot-web-ui/src/stores/load-modal-store.ts
@@ -14,7 +14,7 @@ interface ILoadModalStore {
is_open_button_loading: boolean;
is_strategy_loaded: boolean;
loaded_local_file: File | null;
- recent_strategies: string[];
+ recent_strategies: TStrategy[];
dashboard_strategies: Array;
selected_strategy_id: string | undefined;
is_strategy_removed: boolean;
@@ -40,7 +40,7 @@ interface ILoadModalStore {
setActiveTabIndex: (index: number) => void;
setLoadedLocalFile: (loaded_local_file: File | null) => void;
setDashboardStrategies: (strategies: Array) => void;
- setRecentStrategies: (recent_strategies: string[]) => void;
+ setRecentStrategies: (recent_strategies: TStrategy[]) => void;
setSelectedStrategyId: (selected_strategy_id: string) => void;
toggleExplanationExpand: () => void;
toggleLoadModal: () => void;
@@ -130,7 +130,7 @@ export default class LoadModalStore implements ILoadModalStore {
is_explanation_expand = false;
is_open_button_loading = false;
loaded_local_file: File | null = null;
- recent_strategies: Array = [];
+ recent_strategies: Array = [];
dashboard_strategies: Array | [] = [];
selected_strategy_id = '';
is_strategy_loaded = false;
@@ -428,7 +428,7 @@ export default class LoadModalStore implements ILoadModalStore {
this.loaded_local_file = loaded_local_file;
};
- setRecentStrategies = (recent_strategies: string[]): void => {
+ setRecentStrategies = (recent_strategies: TStrategy[]): void => {
this.recent_strategies = recent_strategies;
};
From b70fc6792d36ef986c633490aa7714f8aed72622 Mon Sep 17 00:00:00 2001
From: henry-deriv <118344354+henry-deriv@users.noreply.github.com>
Date: Wed, 20 Dec 2023 10:26:16 +0800
Subject: [PATCH 012/187] [DTRA] henry/webrel-55/fix: add test cases and add
history as dev dependency (#12268)
* fix: add test cases and add history as dev dependency
* fix: change variable to snake case
---
packages/trader/package.json | 1 +
.../trade-footer-extensions.spec.tsx | 66 +++++++++++++++++++
2 files changed, 67 insertions(+)
create mode 100644 packages/trader/src/App/Containers/__tests__/trade-footer-extensions.spec.tsx
diff --git a/packages/trader/package.json b/packages/trader/package.json
index d15ec737c6e5..c2205d0315f0 100644
--- a/packages/trader/package.json
+++ b/packages/trader/package.json
@@ -60,6 +60,7 @@
"html-loader": "^1.3.2",
"html-webpack-plugin": "^5.0.0-beta.5",
"html-webpack-tags-plugin": "^2.0.17",
+ "history": "^5.0.0",
"ignore-styles": "^5.0.1",
"jsdom": "^21.1.1",
"jsdom-global": "^2.1.1",
diff --git a/packages/trader/src/App/Containers/__tests__/trade-footer-extensions.spec.tsx b/packages/trader/src/App/Containers/__tests__/trade-footer-extensions.spec.tsx
new file mode 100644
index 000000000000..c39e637b94b7
--- /dev/null
+++ b/packages/trader/src/App/Containers/__tests__/trade-footer-extensions.spec.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import TraderProviders from '../../../trader-providers';
+import TradeFooterExtensions from '../trade-footer-extensions';
+import { mockStore } from '@deriv/stores';
+import { RouteComponentProps, Router } from 'react-router-dom';
+import { MemoryHistory, createMemoryHistory } from 'history';
+
+describe('', () => {
+ let mock_store: ReturnType,
+ router_prop: Partial,
+ custom_history: MemoryHistory;
+ beforeEach(() => {
+ mock_store = {
+ ...mockStore({
+ client: {
+ is_logged_in: false,
+ },
+ portfolio: {
+ active_positions_count: 0,
+ },
+ ui: {
+ is_positions_drawer_on: false,
+ populateFooterExtensions: jest.fn(item => item[0]),
+ },
+ }),
+ };
+ custom_history = createMemoryHistory({ initialEntries: ['/test'] });
+ });
+ const renderTraderFooterExtensions = (props: Partial) => {
+ custom_history = createMemoryHistory({ initialEntries: [props.location.pathname] });
+ return render(
+