From f71fd1d949f99e1e8037fa7c3548f659b7473af2 Mon Sep 17 00:00:00 2001 From: sergei-deriv Date: Fri, 5 Apr 2024 15:52:34 +0300 Subject: [PATCH 1/7] feat: add startInitTimers to main and create performance metrics file --- package-lock.json | 114 ++++++ package.json | 1 + src/assets/svgs/personal-details-example.svg | 354 +++++++++---------- src/main.tsx | 4 + src/utils/index.ts | 1 + src/utils/performance-metrics-methods.ts | 78 ++++ 6 files changed, 371 insertions(+), 181 deletions(-) create mode 100644 src/utils/performance-metrics-methods.ts diff --git a/package-lock.json b/package-lock.json index c799008..577414d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "traders-hub", "version": "0.0.0", "dependencies": { + "@deriv-com/analytics": "~1.4.13", "@deriv-com/api-hooks": "^0.0.21", "@deriv-com/ui": "1.12.19", "@deriv-com/utils": "^0.0.11", @@ -1692,6 +1693,19 @@ "postcss-selector-parser": "^6.0.13" } }, + "node_modules/@deriv-com/analytics": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@deriv-com/analytics/-/analytics-1.4.13.tgz", + "integrity": "sha512-BRdL2h3U733qiDQ+Y9QE8ZWs7D6F3l7lZ6k/aR8Jfwa+WjMa6xR1+pOlbTl86rT7GVLnClhGQvtcEDMIHjzUWQ==", + "dependencies": { + "@growthbook/growthbook": "^0.29.0", + "rudder-sdk-js": "^2.35.0" + }, + "engines": { + "node": "18.x", + "npm": "9.x" + } + }, "node_modules/@deriv-com/api-hooks": { "version": "0.0.21", "resolved": "https://registry.npmjs.org/@deriv-com/api-hooks/-/api-hooks-0.0.21.tgz", @@ -1937,6 +1951,17 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@growthbook/growthbook": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@growthbook/growthbook/-/growthbook-0.29.0.tgz", + "integrity": "sha512-hRYtBw1cg3fqjBRKRfazkRfCJyFpIxjdEUjmwkFaSBorzVDiX35gcp8x83vytQdx5E9xfQo3x/m9Z1yEMDrN7A==", + "dependencies": { + "dom-mutator": "^0.5.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -2901,6 +2926,38 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@lukeed/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==", + "dependencies": { + "@lukeed/csprng": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@ndhoule/each": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@ndhoule/each/-/each-2.0.1.tgz", + "integrity": "sha512-wHuJw6x+rF6Q9Skgra++KccjBozCr9ymtna0FhxmV/8xT/hZ2ExGYR8SV8prg8x4AH/7mzDYErNGIVHuzHeybw==", + "dependencies": { + "@ndhoule/keys": "^2.0.0" + } + }, + "node_modules/@ndhoule/keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ndhoule/keys/-/keys-2.0.0.tgz", + "integrity": "sha512-vtCqKBC1Av6dsBA8xpAO+cgk051nfaI+PnmTZep2Px0vYrDvpUmLxv7z40COlWH5yCpu3gzNhepk+02yiQiZNw==" + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", @@ -3166,6 +3223,34 @@ "win32" ] }, + "node_modules/@segment/localstorage-retry": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@segment/localstorage-retry/-/localstorage-retry-1.3.0.tgz", + "integrity": "sha512-myp6eh0J+2Zj+lBi1tTa5LAaudPLOfS7H1rlx0F2vx/IROyI8A3bli2HISVhuTy7AeSqSZIVkfma/UQCOj8zxg==", + "dependencies": { + "@lukeed/uuid": "^2.0.0", + "@ndhoule/each": "^2.0.1", + "@ndhoule/keys": "^2.0.0", + "component-emitter": "^1.2.1", + "debug": "^0.7.4" + } + }, + "node_modules/@segment/localstorage-retry/node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@segment/localstorage-retry/node_modules/debug": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha512-EohAb3+DSHSGx8carOSKJe8G0ayV5/i609OD0J2orCkuyae7SyZSz2aoLmQF2s0Pj5gITDebwPH7GFBlqOUQ1Q==", + "engines": { + "node": "*" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -5606,6 +5691,17 @@ "dot-prop": "^5.1.0" } }, + "node_modules/component-emitter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-2.0.0.tgz", + "integrity": "sha512-4m5s3Me2xxlVKG9PkZpQqHQR7bgpnN7joDMJ4yvVkVXngjoITG76IaZmzmywSeRTeTpc6N6r3H3+KyUurV8OYw==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -6347,6 +6443,14 @@ "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true }, + "node_modules/dom-mutator": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/dom-mutator/-/dom-mutator-0.5.0.tgz", + "integrity": "sha512-bbeX8HWE8JGzraFgbVBX4ws2g3heZFuTtrleQBuN7huy+7n2n7etSuVnot3/1z3jdY2MiwuvoS4Ep1UT2rrGBw==", + "engines": { + "node": ">=10" + } + }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -14644,6 +14748,16 @@ "linux" ] }, + "node_modules/rudder-sdk-js": { + "version": "2.48.6", + "resolved": "https://registry.npmjs.org/rudder-sdk-js/-/rudder-sdk-js-2.48.6.tgz", + "integrity": "sha512-9pkMZjbNXwGMkG6bjUzay7ymKuEF3BO83L4auP3J2VWVw8C2vg12NJvThMVgAsJBIJwr0u+LDxdavInIvWMa3Q==", + "deprecated": "This package is deprecated. Please switch to the latest @rudderstack/analytics-js package. For more details visit, https://www.rudderstack.com/docs/sources/event-streams/sdks/rudderstack-javascript-sdk/.", + "dependencies": { + "@segment/localstorage-retry": "1.3.0", + "component-emitter": "2.0.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", diff --git a/package.json b/package.json index 7deed82..54e01c9 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "prepare": "husky install" }, "dependencies": { + "@deriv-com/analytics": "~1.4.13", "@deriv-com/api-hooks": "^0.0.21", "@deriv-com/ui": "1.12.19", "@deriv-com/utils": "^0.0.11", diff --git a/src/assets/svgs/personal-details-example.svg b/src/assets/svgs/personal-details-example.svg index 3f86a68..743dc41 100644 --- a/src/assets/svgs/personal-details-example.svg +++ b/src/assets/svgs/personal-details-example.svg @@ -1,182 +1,174 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main.tsx b/src/main.tsx index 2bbe384..88a2bf3 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -6,6 +6,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { CFDProvider, RealAccountCreationProvider, UIProvider } from '@/providers'; +import { startInitPerformanceTimers } from '@/utils'; import { Header } from './components/Header/Header.tsx'; import App from './App.tsx'; @@ -14,6 +15,9 @@ import './index.css'; const queryClient = new QueryClient(); +// function to start the timer for login/signup/redirect +startInitPerformanceTimers(); + ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/src/utils/index.ts b/src/utils/index.ts index e5d5ee2..0e580ef 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,2 +1,3 @@ export * from './tailwind'; export * from './password'; +export * from './performance-metrics-methods'; diff --git a/src/utils/performance-metrics-methods.ts b/src/utils/performance-metrics-methods.ts new file mode 100644 index 0000000..37e32fe --- /dev/null +++ b/src/utils/performance-metrics-methods.ts @@ -0,0 +1,78 @@ +import { Analytics } from '@deriv-com/analytics'; + +declare global { + interface Window { + performance_metrics: { + create_ctrader_account_time: number; + create_dxtrade_account_time: number; + create_mt5_account_time: number; + load_cashier_time: number; + load_crypto_deposit_cashier_time: number; + load_fiat_deposit_cashier_time: number; + login_time: number; + redirect_from_deriv_com_time: number; + signup_time: number; + switch_currency_accounts_time: number; + switch_from_demo_to_real_time: number; + switch_from_real_to_demo_time: number; + }; + } +} + +// action type will be updated based on the type from Analytics package when it will be updated +export const startPerformanceEventTimer = (action: keyof typeof Window.prototype.performance_metrics) => { + if (!window.performance_metrics) { + window.performance_metrics = { + create_ctrader_account_time: 0, + create_dxtrade_account_time: 0, + create_mt5_account_time: 0, + load_cashier_time: 0, + load_crypto_deposit_cashier_time: 0, + load_fiat_deposit_cashier_time: 0, + login_time: 0, + redirect_from_deriv_com_time: 0, + signup_time: 0, + switch_currency_accounts_time: 0, + switch_from_demo_to_real_time: 0, + switch_from_real_to_demo_time: 0, + }; + } + + window.performance_metrics[action] = Date.now(); +}; + +export const setPerformanceValue = (action: keyof typeof Window.prototype.performance_metrics) => { + if (window.performance_metrics?.[action]) { + const value = (Date.now() - window.performance_metrics[action]) / 1000; + window.performance_metrics[action] = 0; + + const event_name = 'ce_traders_hub_v3_performance_metrics'; + // @ts-expect-error types will be added in the next version of analytics package + Analytics.trackEvent(event_name, { + action, + value, + device: true ? 'mobile' : 'desktop', + }); + } +}; + +export const startInitPerformanceTimers = () => { + const url = new URL(window.location.href); + const urlParams = url.searchParams; + + // start the timer for signup + if (urlParams.get('action') === 'signup') startPerformanceEventTimer('signup_time'); + + // start the timer for login + if (urlParams.get('acct1')) startPerformanceEventTimer('login_time'); + + // start the timer for redirect from deriv.com + if (urlParams.get('redirect_from') === 'deriv_com') { + startPerformanceEventTimer('redirect_from_deriv_com_time'); + + // we delete all query parameters in useQueryParams() hook, but made decision + // to delete 'redirect_from' param here, because later this hook can be changed + urlParams.delete('redirect_from'); + history.replaceState(null, '', url.toString()); + } +}; From ce124020dc8bd6b8304262cabe0a898ea92ec9a4 Mon Sep 17 00:00:00 2001 From: sergei-deriv Date: Mon, 8 Apr 2024 11:11:56 +0300 Subject: [PATCH 2/7] feat: add startPerformanceEventTimer for deposit button --- src/components/CurrencySwitcher/CurrencySwitcher.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/CurrencySwitcher/CurrencySwitcher.tsx b/src/components/CurrencySwitcher/CurrencySwitcher.tsx index 5b8a89d..bf1f8f8 100644 --- a/src/components/CurrencySwitcher/CurrencySwitcher.tsx +++ b/src/components/CurrencySwitcher/CurrencySwitcher.tsx @@ -6,8 +6,9 @@ import { Button } from '@deriv-com/ui'; import { CurrencySwitcherLoader } from '@/components'; import { IconToCurrencyMapper } from '@/constants'; -import { useActiveDerivTradingAccount, useQueryParams, useRegulationFlags } from '@/hooks'; +import { useActiveDerivTradingAccount, useCurrencyConfig, useQueryParams, useRegulationFlags } from '@/hooks'; import { THooks } from '@/types'; +import { startPerformanceEventTimer } from '@/utils'; import { DemoCurrencySwitcherAccountInfo, RealCurrencySwitcherAccountInfo } from './CurrencySwitcherAccountInfo'; @@ -19,6 +20,7 @@ type AccountActionButtonProps = { const AccountActionButton = ({ balance, isDemo }: AccountActionButtonProps) => { const { mutate: resetVirtualBalance } = useTopupVirtual(); const { activeLoginid } = useAuthData(); + const { data: currencyConfig } = useCurrencyConfig(); const navigate = useNavigate(); let buttonText = 'Deposit'; if (isDemo && balance !== 10000) { @@ -36,7 +38,10 @@ const AccountActionButton = ({ balance, isDemo }: AccountActionButtonProps) => { loginid: activeLoginid, }); } else { - navigate('/cashier/deposit'); + if (currencyConfig?.currency?.isCrypto) + startPerformanceEventTimer('load_crypto_deposit_cashier_time'); + else startPerformanceEventTimer('load_fiat_deposit_cashier_time'); + navigate('/cashier/deposit#deposit'); } }} variant='outlined' From ce017b2e4ee9c5b7b5e743a851f7125392ca00f4 Mon Sep 17 00:00:00 2001 From: sergei-deriv Date: Mon, 8 Apr 2024 12:00:55 +0300 Subject: [PATCH 3/7] feat: add all possible performance timers for now --- src/components/TotalAssets/TotalAssets.tsx | 19 +++++++++++++++++-- .../TradingAccountsList.tsx | 2 ++ src/hooks/useAccountSwitcher.ts | 4 ++++ src/pages/signup/signup.tsx | 9 +++++++++ src/utils/performance-metrics-methods.ts | 4 ++-- 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/components/TotalAssets/TotalAssets.tsx b/src/components/TotalAssets/TotalAssets.tsx index a4e9eab..0c762ae 100644 --- a/src/components/TotalAssets/TotalAssets.tsx +++ b/src/components/TotalAssets/TotalAssets.tsx @@ -1,11 +1,26 @@ import { twMerge } from 'tailwind-merge'; -import { Text } from '@deriv-com/ui'; +import { Text, useDevice } from '@deriv-com/ui'; import { useActiveDerivTradingAccount } from '@/hooks'; +import { setPerformanceValue } from '@/utils'; + +import { TotalAssetsLoader } from '../Loaders'; const TotalAssets = () => { - const { data: activeDerivTradingAccount } = useActiveDerivTradingAccount(); + const { data: activeDerivTradingAccount, isFetching } = useActiveDerivTradingAccount(); + const { isMobile } = useDevice(); + + // need to add more conditions to show the loader + if (isFetching) { + return ; + } + + setPerformanceValue('login_time', isMobile); + setPerformanceValue('redirect_from_deriv_com_time', isMobile); + setPerformanceValue('switch_currency_accounts_time', isMobile); + setPerformanceValue('switch_from_demo_to_real_time', isMobile); + setPerformanceValue('switch_from_real_to_demo_time', isMobile); return (
diff --git a/src/components/TradingAccountsList/TradingAccountsList.tsx b/src/components/TradingAccountsList/TradingAccountsList.tsx index 6c5a1da..463d902 100644 --- a/src/components/TradingAccountsList/TradingAccountsList.tsx +++ b/src/components/TradingAccountsList/TradingAccountsList.tsx @@ -6,6 +6,7 @@ import { Text } from '@deriv-com/ui'; import { IconComponent } from '@/components'; import { IconToCurrencyMapper } from '@/constants'; import { useActiveDerivTradingAccount, useDerivTradingAccountsList, useQueryParams, useRegulationFlags } from '@/hooks'; +import { startPerformanceEventTimer } from '@/utils'; export const TradingAccountsList = () => { const { data: tradingAccountsList } = useDerivTradingAccountsList(); @@ -15,6 +16,7 @@ export const TradingAccountsList = () => { const { closeModal } = useQueryParams(); const handleSwitchAccount = (loginid: string) => { + startPerformanceEventTimer('switch_currency_accounts_time'); switchAccount(loginid); closeModal(); }; diff --git a/src/hooks/useAccountSwitcher.ts b/src/hooks/useAccountSwitcher.ts index aa482f7..f2cb2a9 100644 --- a/src/hooks/useAccountSwitcher.ts +++ b/src/hooks/useAccountSwitcher.ts @@ -4,6 +4,7 @@ import { useAuthData } from '@deriv-com/api-hooks'; import { Regulation } from '@/constants'; import { useUIContext } from '@/providers'; +import { startPerformanceEventTimer } from '@/utils'; import { useActiveDerivTradingAccount, @@ -66,6 +67,9 @@ export const useAccountSwitcher = () => { const loginId = account.value === accountTypes[0].value ? demoLoginId : firstRealLoginId; if (loginId) { + if (account.value === accountTypes[0].value) + startPerformanceEventTimer('switch_from_real_to_demo_time'); + else startPerformanceEventTimer('switch_from_demo_to_real_time'); switchAccount(loginId); } diff --git a/src/pages/signup/signup.tsx b/src/pages/signup/signup.tsx index cb11e78..d2bceb0 100644 --- a/src/pages/signup/signup.tsx +++ b/src/pages/signup/signup.tsx @@ -1,6 +1,15 @@ import { Link } from 'react-router-dom'; +import { useDevice } from '@deriv-com/ui'; + +import { setPerformanceValue } from '@/utils'; + export const Signup = () => { + const { isMobile } = useDevice(); + + // leave it here for now + setPerformanceValue('signup_time', isMobile); + return ( <>

Signup

diff --git a/src/utils/performance-metrics-methods.ts b/src/utils/performance-metrics-methods.ts index 37e32fe..ddf84e8 100644 --- a/src/utils/performance-metrics-methods.ts +++ b/src/utils/performance-metrics-methods.ts @@ -41,7 +41,7 @@ export const startPerformanceEventTimer = (action: keyof typeof Window.prototype window.performance_metrics[action] = Date.now(); }; -export const setPerformanceValue = (action: keyof typeof Window.prototype.performance_metrics) => { +export const setPerformanceValue = (action: keyof typeof Window.prototype.performance_metrics, isMobile = false) => { if (window.performance_metrics?.[action]) { const value = (Date.now() - window.performance_metrics[action]) / 1000; window.performance_metrics[action] = 0; @@ -51,7 +51,7 @@ export const setPerformanceValue = (action: keyof typeof Window.prototype.perfor Analytics.trackEvent(event_name, { action, value, - device: true ? 'mobile' : 'desktop', + device: isMobile ? 'mobile' : 'desktop', }); } }; From f30014a63035e972adcfc6f914b6a589d555edc1 Mon Sep 17 00:00:00 2001 From: sergei-deriv Date: Tue, 16 Apr 2024 14:24:49 +0300 Subject: [PATCH 4/7] feat: add performance metric for mt5 creation --- src/hooks/useMT5AccountHandler.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hooks/useMT5AccountHandler.ts b/src/hooks/useMT5AccountHandler.ts index 4a428f5..2b4bb5a 100644 --- a/src/hooks/useMT5AccountHandler.ts +++ b/src/hooks/useMT5AccountHandler.ts @@ -2,6 +2,7 @@ import { Category, CFDPlatforms, Jurisdiction, MarketType } from '@cfd/constants import { useMT5NewAccount, useTradingPlatformPasswordChange } from '@deriv-com/api-hooks'; import { useCFDContext } from '@/providers'; +import { setPerformanceValue, startPerformanceEventTimer } from '@/utils'; import { useAccountStatus, useActiveDerivTradingAccount, useAvailableMT5Accounts, useSettings } from '.'; @@ -12,7 +13,7 @@ export const useMT5AccountHandler = () => { isPending: createMT5AccountLoading, isSuccess: isCreateMT5AccountSuccess, status: createMT5AccountStatus, - mutate: createMT5Account, + mutateAsync: createMT5Account, } = useMT5NewAccount(); const { isPending: tradingPlatformPasswordChangeLoading, mutateAsync: tradingPasswordChange } = useTradingPlatformPasswordChange(); @@ -35,6 +36,7 @@ export const useMT5AccountHandler = () => { // in order to create account, we need to set a password through trading_platform_password_change endpoint first // then only mt5_create_account can be called, otherwise it will response an error for password required const handleSubmit = async (password: string) => { + startPerformanceEventTimer('create_mt5_account_time'); if (isMT5PasswordNotSet) { await tradingPasswordChange({ new_password: password, @@ -43,6 +45,7 @@ export const useMT5AccountHandler = () => { } await createPassword(password); + setPerformanceValue('create_mt5_account_time'); }; const createPassword = (password: string) => From 7acffb8944bb9b9e229b13fa78e37bbb0a3d9747 Mon Sep 17 00:00:00 2001 From: sergei-deriv Date: Tue, 16 Apr 2024 15:04:52 +0300 Subject: [PATCH 5/7] feat: add check for formatted balance and fix tests --- src/components/TotalAssets/TotalAssets.tsx | 7 ++++--- .../TotalAssets/__tests__/TotalAssets.spec.tsx | 5 +++++ src/hooks/__tests__/useMT5AccountHandler.spec.ts | 16 ++++++++-------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/components/TotalAssets/TotalAssets.tsx b/src/components/TotalAssets/TotalAssets.tsx index 2b19b43..f6c69bc 100644 --- a/src/components/TotalAssets/TotalAssets.tsx +++ b/src/components/TotalAssets/TotalAssets.tsx @@ -8,12 +8,13 @@ import { setPerformanceValue } from '@/utils'; import { TotalAssetsLoader } from '../Loaders'; const TotalAssets = () => { - const { data: activeDerivTradingAccount, isFetching } = useActiveDerivTradingAccount(); + const { data: activeDerivTradingAccount } = useActiveDerivTradingAccount(); const { formattedTotalBalance } = useTotalAssets(); const { isMobile } = useDevice(); - // need to add more conditions to show the loader - if (isFetching) { + // need to add more conditions to show the loader and wait until all accounts are measured + // or wait when BE team completes the task to measure TotalAssets on BE + if (!formattedTotalBalance) { return ; } diff --git a/src/components/TotalAssets/__tests__/TotalAssets.spec.tsx b/src/components/TotalAssets/__tests__/TotalAssets.spec.tsx index 2cbd46f..1b36b78 100644 --- a/src/components/TotalAssets/__tests__/TotalAssets.spec.tsx +++ b/src/components/TotalAssets/__tests__/TotalAssets.spec.tsx @@ -13,6 +13,11 @@ jest.mock('@/hooks', () => ({ jest.mock('@deriv-com/ui', () => ({ Text: ({ children }: { children: ReactNode }) =>
{children}
, + useDevice: jest.fn(() => ({ + isDesktop: true, + isMobile: false, + isTablet: false, + })), })); describe('TotalAssets', () => { diff --git a/src/hooks/__tests__/useMT5AccountHandler.spec.ts b/src/hooks/__tests__/useMT5AccountHandler.spec.ts index 7747653..bacfbfb 100644 --- a/src/hooks/__tests__/useMT5AccountHandler.spec.ts +++ b/src/hooks/__tests__/useMT5AccountHandler.spec.ts @@ -33,7 +33,7 @@ describe('useMT5AccountHandler', () => { isPending: false, isSuccess: false, status: 'idle', - mutate: jest.fn(), + mutateAsync: jest.fn(), }); (useTradingPlatformPasswordChange as jest.Mock).mockReturnValue({ isPending: false, mutateAsync: jest.fn() }); (useActiveDerivTradingAccount as jest.Mock).mockReturnValue({ data: {} }); @@ -63,7 +63,7 @@ describe('useMT5AccountHandler', () => { }, }); (useMT5NewAccount as jest.Mock).mockReturnValue({ - mutate: mockCreateMT5Account, + mutateAsync: mockCreateMT5Account, }); (useTradingPlatformPasswordChange as jest.Mock).mockReturnValue({ mutateAsync: mockTradingPasswordChange, @@ -90,7 +90,7 @@ describe('useMT5AccountHandler', () => { }, }); (useMT5NewAccount as jest.Mock).mockReturnValue({ - mutate: mockCreateMT5Account, + mutateAsync: mockCreateMT5Account, }); (useTradingPlatformPasswordChange as jest.Mock).mockReturnValue({ mutateAsync: mockTradingPasswordChange, @@ -122,7 +122,7 @@ describe('useMT5AccountHandler', () => { }, }); (useMT5NewAccount as jest.Mock).mockReturnValue({ - mutate: mockCreateMT5Account, + mutateAsync: mockCreateMT5Account, }); (useTradingPlatformPasswordChange as jest.Mock).mockReturnValue({ mutateAsync: mockTradingPasswordChange, @@ -154,7 +154,7 @@ describe('useMT5AccountHandler', () => { }, }); (useMT5NewAccount as jest.Mock).mockReturnValue({ - mutate: mockCreateMT5Account, + mutateAsync: mockCreateMT5Account, }); (useAvailableMT5Accounts as jest.Mock).mockReturnValue({ data: mockAccounts, @@ -182,7 +182,7 @@ describe('useMT5AccountHandler', () => { }, }); (useMT5NewAccount as jest.Mock).mockReturnValue({ - mutate: mockCreateMT5Account, + mutateAsync: mockCreateMT5Account, }); (useTradingPlatformPasswordChange as jest.Mock).mockReturnValue({ mutateAsync: mockTradingPasswordChange, @@ -215,7 +215,7 @@ describe('useMT5AccountHandler', () => { }, }); (useMT5NewAccount as jest.Mock).mockReturnValue({ - mutate: mockCreateMT5Account, + mutateAsync: mockCreateMT5Account, }); (useTradingPlatformPasswordChange as jest.Mock).mockReturnValue({ mutateAsync: mockTradingPasswordChange, @@ -248,7 +248,7 @@ describe('useMT5AccountHandler', () => { }, }); (useMT5NewAccount as jest.Mock).mockReturnValue({ - mutate: mockCreateMT5Account, + mutateAsync: mockCreateMT5Account, }); (useTradingPlatformPasswordChange as jest.Mock).mockReturnValue({ mutateAsync: mockTradingPasswordChange, From 7b5e60b6b7f4a4037d562f1c26712bef305a536d Mon Sep 17 00:00:00 2001 From: sergei-deriv Date: Wed, 17 Apr 2024 11:36:13 +0300 Subject: [PATCH 6/7] feat: implement review comments --- src/components/CurrencySwitcher/CurrencySwitcher.tsx | 2 +- src/components/TotalAssets/TotalAssets.tsx | 2 +- .../AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx | 2 +- .../__tests__/AccountOpeningSuccessModal.spec.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/CurrencySwitcher/CurrencySwitcher.tsx b/src/components/CurrencySwitcher/CurrencySwitcher.tsx index 49de589..d6baa08 100644 --- a/src/components/CurrencySwitcher/CurrencySwitcher.tsx +++ b/src/components/CurrencySwitcher/CurrencySwitcher.tsx @@ -41,7 +41,7 @@ const AccountActionButton = ({ balance, isDemo }: AccountActionButtonProps) => { if (currencyConfig?.currency?.isCrypto) startPerformanceEventTimer('load_crypto_deposit_cashier_time'); else startPerformanceEventTimer('load_fiat_deposit_cashier_time'); - navigate('/cashier/deposit#deposit'); + navigate('https://app.deriv.com/cashier/deposit#deposit'); } }} variant='outlined' diff --git a/src/components/TotalAssets/TotalAssets.tsx b/src/components/TotalAssets/TotalAssets.tsx index f6c69bc..283589c 100644 --- a/src/components/TotalAssets/TotalAssets.tsx +++ b/src/components/TotalAssets/TotalAssets.tsx @@ -12,7 +12,7 @@ const TotalAssets = () => { const { formattedTotalBalance } = useTotalAssets(); const { isMobile } = useDevice(); - // need to add more conditions to show the loader and wait until all accounts are measured + // TODO: need to add more conditions to show the loader and wait until all accounts are measured // or wait when BE team completes the task to measure TotalAssets on BE if (!formattedTotalBalance) { return ; diff --git a/src/modals/AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx b/src/modals/AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx index 07cb54a..0b58b81 100644 --- a/src/modals/AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx +++ b/src/modals/AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx @@ -47,7 +47,7 @@ export const AccountOpeningSuccessModal = () => { const handleNavigateToDeposit = () => { reset(); closeModal(); - navigate('/cashier/deposit'); + navigate('https://app.deriv.com/cashier/deposit'); }; return ( { expect(reset).toHaveBeenCalled(); expect(closeModal).toHaveBeenCalled(); - expect(navigate).toHaveBeenCalledWith('/cashier/deposit'); + expect(navigate).toHaveBeenCalledWith('https://app.deriv.com/cashier/deposit'); }); it('uses USD as the default currency if state.currency is undefined', () => { From e90e2e3144f524f9574cc6b0d594bd5e0fed57c1 Mon Sep 17 00:00:00 2001 From: sergei-deriv Date: Thu, 18 Apr 2024 12:26:20 +0300 Subject: [PATCH 7/7] feat: change useNavigate to window.location.href --- .../CurrencySwitcher/CurrencySwitcher.tsx | 6 ++--- .../AccountOpeningSuccessModal.tsx | 6 ++--- .../AccountOpeningSuccessModal.spec.tsx | 27 ++++++++++++------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/components/CurrencySwitcher/CurrencySwitcher.tsx b/src/components/CurrencySwitcher/CurrencySwitcher.tsx index d6baa08..b9ef71f 100644 --- a/src/components/CurrencySwitcher/CurrencySwitcher.tsx +++ b/src/components/CurrencySwitcher/CurrencySwitcher.tsx @@ -1,11 +1,10 @@ -import { useNavigate } from 'react-router-dom'; - import { StandaloneChevronDownBoldIcon } from '@deriv/quill-icons'; import { useAuthData, useTopupVirtual } from '@deriv-com/api-hooks'; import { Button } from '@deriv-com/ui'; import { CurrencySwitcherLoader } from '@/components'; import { IconToCurrencyMapper } from '@/constants'; +import { derivUrls } from '@/helpers'; import { useActiveDerivTradingAccount, useCurrencyConfig, useQueryParams, useRegulationFlags } from '@/hooks'; import { THooks } from '@/types'; import { startPerformanceEventTimer } from '@/utils'; @@ -21,7 +20,6 @@ const AccountActionButton = ({ balance, isDemo }: AccountActionButtonProps) => { const { mutate: resetVirtualBalance } = useTopupVirtual(); const { activeLoginid } = useAuthData(); const { data: currencyConfig } = useCurrencyConfig(); - const navigate = useNavigate(); let buttonText = 'Deposit'; if (isDemo && balance !== 10000) { buttonText = 'Reset Balance'; @@ -41,7 +39,7 @@ const AccountActionButton = ({ balance, isDemo }: AccountActionButtonProps) => { if (currencyConfig?.currency?.isCrypto) startPerformanceEventTimer('load_crypto_deposit_cashier_time'); else startPerformanceEventTimer('load_fiat_deposit_cashier_time'); - navigate('https://app.deriv.com/cashier/deposit#deposit'); + window.location.href = `${derivUrls.DERIV_APP_PRODUCTION}/cashier/deposit#deposit`; } }} variant='outlined' diff --git a/src/modals/AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx b/src/modals/AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx index 0b58b81..0c9fa73 100644 --- a/src/modals/AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx +++ b/src/modals/AccountOpeningSuccessModal/AccountOpeningSuccessModal.tsx @@ -1,10 +1,9 @@ -import { useNavigate } from 'react-router-dom'; - import { Button, Modal, Text, useDevice } from '@deriv-com/ui'; import Checkmark from '@/assets/svgs/checkmark.svg?react'; import { ButtonGroup, IconComponent } from '@/components'; import { ActionScreen } from '@/components/ActionScreen'; +import { derivUrls } from '@/helpers'; import { useQueryParams } from '@/hooks'; import { useRealAccountCreationContext } from '@/providers'; @@ -41,13 +40,12 @@ export const AccountOpeningSuccessModal = () => { const { isSuccessModalOpen, reset } = useRealAccountCreationContext(); const { isDesktop } = useDevice(); const { state } = useRealAccountCreationContext(); - const navigate = useNavigate(); const { closeModal } = useQueryParams(); const handleNavigateToDeposit = () => { reset(); closeModal(); - navigate('https://app.deriv.com/cashier/deposit'); + window.location.href = `${derivUrls.DERIV_APP_PRODUCTION}/cashier/deposit`; }; return ( ({ useQueryParams: jest.fn(), })); -jest.mock('react-router-dom', () => ({ - useNavigate: jest.fn(), -})); - jest.mock('@deriv-com/ui', () => ({ ...jest.requireActual('@deriv-com/ui'), Modal: ({ children }: { children: ReactNode }) =>
{children}
, @@ -30,6 +26,21 @@ jest.mock('@deriv-com/ui', () => ({ })); describe('AccountOpeningSuccessModal', () => { + const currentLocation = { ...window.location }; + + beforeEach(() => { + Object.defineProperty(window, 'location', { + value: { + href: '', + }, + writable: true, + }); + }); + + afterEach(() => { + Object.defineProperty(window, 'location', currentLocation); + }); + it('renders correctly', () => { (useRealAccountCreationContext as jest.Mock).mockReturnValue({ isSuccessModalOpen: true, @@ -52,14 +63,12 @@ describe('AccountOpeningSuccessModal', () => { it('calls reset, closeModal, and navigate when the Deposit button is clicked', () => { const reset = jest.fn(); const closeModal = jest.fn(); - const navigate = jest.fn(); (useRealAccountCreationContext as jest.Mock).mockReturnValue({ isSuccessModalOpen: true, reset, state: { currency: 'USD' }, }); (useQueryParams as jest.Mock).mockReturnValue({ closeModal }); - (useNavigate as jest.Mock).mockReturnValue(navigate); render(); @@ -67,7 +76,8 @@ describe('AccountOpeningSuccessModal', () => { expect(reset).toHaveBeenCalled(); expect(closeModal).toHaveBeenCalled(); - expect(navigate).toHaveBeenCalledWith('https://app.deriv.com/cashier/deposit'); + + expect(window.location.href).toBe(`${derivUrls.DERIV_APP_PRODUCTION}/cashier/deposit`); }); it('uses USD as the default currency if state.currency is undefined', () => { @@ -78,7 +88,6 @@ describe('AccountOpeningSuccessModal', () => { }; (useRealAccountCreationContext as jest.Mock).mockReturnValue(mockContext); (useQueryParams as jest.Mock).mockReturnValue({ closeModal: jest.fn() }); - (useNavigate as jest.Mock).mockReturnValue(jest.fn()); render();