From 18cf193176f7a695145d853b3eb8b8d4d37f7436 Mon Sep 17 00:00:00 2001 From: Sui Sin <103026762+suisin-deriv@users.noreply.github.com> Date: Mon, 3 Mar 2025 18:27:24 +0800 Subject: [PATCH] Suisin/chore: implement session account switching in dtrader and tradershub (#18085) * chore: implement session account switching in dtrader and tradershub * chore: fix failing test cases --- packages/api-v2/src/AuthProvider.tsx | 1 + packages/api/src/APIProvider.tsx | 3 +- packages/api/src/hooks/useAuthorize.ts | 1 + .../account-switcher-dtrader-v2.tsx | 2 +- .../Header/wallets/account-info-wallets.tsx | 7 ++-- .../account-switcher-wallet-item.tsx | 1 + .../src/App/Containers/Redirect/redirect.jsx | 22 ++++++++++++ packages/core/src/App/app.jsx | 36 +++++++++++++++++++ packages/core/src/Stores/client-store.js | 27 +++++++++++--- packages/shared/src/utils/config/config.ts | 4 +-- .../src/getActiveLoginIDFromLocalStorage.ts | 2 +- .../useWalletAccountSwitcher.spec.tsx | 2 +- .../useSyncLocalStorageClientAccounts.ts | 1 + .../src/hooks/useWalletAccountSwitcher.ts | 16 +++++++-- 14 files changed, 110 insertions(+), 15 deletions(-) diff --git a/packages/api-v2/src/AuthProvider.tsx b/packages/api-v2/src/AuthProvider.tsx index 367b2aa72b97..08adaf96218e 100644 --- a/packages/api-v2/src/AuthProvider.tsx +++ b/packages/api-v2/src/AuthProvider.tsx @@ -154,6 +154,7 @@ const AuthProvider = ({ loginIDKey, children, cookieTimeout, selectDefaultAccoun if (!activeAccount) return; localStorage.setItem(loginIDKey ?? 'active_loginid', activeLoginID); + sessionStorage.setItem(loginIDKey ?? 'active_loginid', activeLoginID); const isDemo = activeAccount.is_virtual; const shouldCreateNewWSConnection = (isDemo && wsClient?.endpoint === AppIDConstants.environments.real) || diff --git a/packages/api/src/APIProvider.tsx b/packages/api/src/APIProvider.tsx index 0d623090b39e..7b0e98d4be90 100644 --- a/packages/api/src/APIProvider.tsx +++ b/packages/api/src/APIProvider.tsx @@ -147,7 +147,8 @@ type TAPIProviderProps = { const APIProvider = ({ children, standalone = false }: PropsWithChildren) => { const WS = useWS(); const [reconnect, setReconnect] = useState(false); - const activeLoginid = window.localStorage.getItem('active_loginid'); + const activeLoginid = + window.sessionStorage.getItem('active_loginid') || window.localStorage.getItem('active_loginid'); const [environment, setEnvironment] = useState(getEnvironment(activeLoginid)); const standaloneDerivAPI = useRef(standalone ? initializeDerivAPI(() => setReconnect(true)) : null); const subscriptions = useRef>(); diff --git a/packages/api/src/hooks/useAuthorize.ts b/packages/api/src/hooks/useAuthorize.ts index 2450efa77f62..bba1b1bee500 100644 --- a/packages/api/src/hooks/useAuthorize.ts +++ b/packages/api/src/hooks/useAuthorize.ts @@ -32,6 +32,7 @@ const useAuthorize = () => { (loginid: string) => { const active_loginid = getActiveLoginIDFromLocalStorage(); if (active_loginid !== loginid) { + sessionStorage.setItem('active_loginid', loginid); localStorage.setItem('active_loginid', loginid); switchEnvironment(active_loginid); // whenever we change the loginid, we need to invalidate all queries diff --git a/packages/core/src/App/Components/Layout/Header/dtrader-v2/account-switcher-dtrader-v2.tsx b/packages/core/src/App/Components/Layout/Header/dtrader-v2/account-switcher-dtrader-v2.tsx index f8e07b8d8a9e..b1a055df4d30 100644 --- a/packages/core/src/App/Components/Layout/Header/dtrader-v2/account-switcher-dtrader-v2.tsx +++ b/packages/core/src/App/Components/Layout/Header/dtrader-v2/account-switcher-dtrader-v2.tsx @@ -123,7 +123,7 @@ const AccountSwitcherDTraderV2 = observer(({ history }: TAccountSwitcherDTraderV } }; - const getAccountItem = (item: typeof account_list[0], is_demo?: boolean) => ( + const getAccountItem = (item: (typeof account_list)[0], is_demo?: boolean) => ( wallet.loginid === wallet_loginid) ?? wallet_list?.find(wallet => wallet.loginid === loginid); @@ -126,7 +127,9 @@ const AccountInfoWallets = observer(({ is_dialog_on, toggleDialog }: TAccountInf if (active_wallet) { // get 'dtrade' loginid account linked to the current wallet linked_dtrade_trading_account_loginid = - active_wallet.dtrade_loginid || linked_wallets_accounts.dtrade?.[0]?.loginid; + sessionStorage.getItem('active_loginid') || + active_wallet.dtrade_loginid || + linked_wallets_accounts.dtrade?.[0]?.loginid; // switch to dtrade account if (linked_dtrade_trading_account_loginid && linked_dtrade_trading_account_loginid !== loginid) { diff --git a/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-item.tsx b/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-item.tsx index ed3cca542431..db6f17329edf 100644 --- a/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-item.tsx +++ b/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-item.tsx @@ -42,6 +42,7 @@ export const AccountSwitcherWalletItem = observer( if (is_dtrade_active) return; await switchAccount(dtrade_loginid); localStorage.setItem('active_wallet_loginid', loginid); + sessionStorage.setItem('active_wallet_loginid', loginid); }; return ( diff --git a/packages/core/src/App/Containers/Redirect/redirect.jsx b/packages/core/src/App/Containers/Redirect/redirect.jsx index 52c2f8a87b8f..4e42c0961d9e 100644 --- a/packages/core/src/App/Containers/Redirect/redirect.jsx +++ b/packages/core/src/App/Containers/Redirect/redirect.jsx @@ -323,6 +323,28 @@ const Redirect = observer(() => { } useEffect(() => { if (!redirected_to_route && history.location.pathname !== routes.traders_hub) { + const account_currency = url_params.get('account'); + const client_account_lists = JSON.parse(localStorage.getItem('client.accounts')); + + if (account_currency) { + let matching_loginid; + + const converted_account_currency = account_currency.toUpperCase(); + + if (converted_account_currency === 'DEMO') { + matching_loginid = Object.keys(client_account_lists).find(loginid => /^VR/.test(loginid)); + } else { + matching_loginid = Object.keys(client_account_lists).find( + loginid => + client_account_lists[loginid].currency?.toUpperCase() === converted_account_currency && + client_account_lists[loginid].account_category === 'trading' + ); + } + + if (matching_loginid) { + sessionStorage.setItem('active_loginid', matching_loginid); + } + } const route_mappings = [ { pattern: /accumulator/i, route: routes.trade, type: 'accumulator' }, { pattern: /turbos/i, route: routes.trade, type: 'turboslong' }, diff --git a/packages/core/src/App/app.jsx b/packages/core/src/App/app.jsx index 400ddc2dfeb4..76beb34ca412 100644 --- a/packages/core/src/App/app.jsx +++ b/packages/core/src/App/app.jsx @@ -51,6 +51,42 @@ const AppWithoutTranslation = ({ root_store }) => { const is_dark_mode = is_dark_mode_on || JSON.parse(localStorage.getItem('ui_store'))?.is_dark_mode_on; const language = preferred_language ?? getInitialLanguage(); + const url_query_string = window.location.search; + const url_params = new URLSearchParams(url_query_string); + const account_currency = url_params.get('account'); + const client_account_lists = JSON.parse(localStorage.getItem('client.accounts')); + + if (account_currency) { + let matching_loginid, matching_wallet_loginid; + + const converted_account_currency = account_currency.toUpperCase(); + + if (converted_account_currency === 'DEMO') { + matching_loginid = Object.keys(client_account_lists).find(loginid => /^VRTC/.test(loginid)); + matching_wallet_loginid = Object.keys(client_account_lists).find(loginid => /^VRW/.test(loginid)); + } else { + matching_loginid = Object.keys(client_account_lists).find( + loginid => + client_account_lists[loginid].currency?.toUpperCase() === converted_account_currency && + client_account_lists[loginid].account_category === 'trading' && + client_account_lists[loginid]?.landing_company !== 'virtual' + ); + matching_wallet_loginid = Object.keys(client_account_lists).find( + loginid => + client_account_lists[loginid].currency?.toUpperCase() === converted_account_currency && + client_account_lists[loginid].account_category === 'wallet' && + client_account_lists[loginid]?.landing_company !== 'virtual' + ); + } + + if (matching_loginid) { + sessionStorage.setItem('active_loginid', matching_loginid); + } + if (matching_wallet_loginid) { + sessionStorage.setItem('active_wallet_loginid', matching_wallet_loginid); + } + } + React.useEffect(() => { const dir = i18n.dir(i18n.language.toLowerCase()); document.documentElement.dir = dir; diff --git a/packages/core/src/Stores/client-store.js b/packages/core/src/Stores/client-store.js index 7856ae87b7aa..ce211e9afebe 100644 --- a/packages/core/src/Stores/client-store.js +++ b/packages/core/src/Stores/client-store.js @@ -359,6 +359,7 @@ export default class ClientStore extends BaseStore { setLoginId: action.bound, setAccounts: action.bound, setSwitched: action.bound, + setUrlParams: action.bound, setIsAuthorize: action.bound, setIsLoggingIn: action.bound, setPreSwitchAccount: action.bound, @@ -1065,11 +1066,22 @@ export default class ClientStore extends BaseStore { resetLocalStorageValues(loginid) { this.accounts[loginid].accepted_bch = 0; LocalStore.setObject(storage_key, this.accounts); - LocalStore.set('active_loginid', loginid); + sessionStorage.setItem('active_loginid', loginid); + this.setUrlParams(); this.syncWithLegacyPlatforms(loginid, toJS(this.accounts)); this.loginid = loginid; } + setUrlParams() { + const url = new URL(window.location.href); + const loginid = sessionStorage.getItem('active_wallet_loginid') || sessionStorage.getItem('active_loginid'); + const account_param = /^VR/.test(loginid) ? 'demo' : this.accounts[loginid]?.currency; + if (account_param) { + url.searchParams.set('account', account_param); + window.history.replaceState({}, '', url.toString()); + } + } + setIsAuthorize(value) { this.is_authorize = value; } @@ -1576,7 +1588,7 @@ export default class ClientStore extends BaseStore { if (['crypto_transactions_withdraw', 'payment_withdraw'].includes(action_param) && loginid_param) this.setLoginId(loginid_param); - else this.setLoginId(LocalStore.get('active_loginid')); + else this.setLoginId(window.sessionStorage.getItem('active_loginid') || LocalStore.get('active_loginid')); this.user_id = LocalStore.get('active_user_id'); this.setAccounts(LocalStore.getObject(storage_key)); this.setSwitched(''); @@ -2005,11 +2017,15 @@ export default class ClientStore extends BaseStore { //temporary workaround to sync this.loginid with selected wallet loginid if (window.location.pathname.includes(routes.wallets)) { - this.resetLocalStorageValues(localStorage.getItem('active_loginid') ?? this.loginid); + this.resetLocalStorageValues( + window.sessionStorage.getItem('active_loginid') ?? + localStorage.getItem('active_loginid') ?? + this.loginid + ); return; } - this.resetLocalStorageValues(this.loginid); + this.resetLocalStorageValues(window.sessionStorage.getItem('active_loginid') ?? this.loginid); } } @@ -2232,11 +2248,12 @@ export default class ClientStore extends BaseStore { if (active_loginid && Object.keys(client_object).length) { if (selected_account && is_wallets_selected) { localStorage.setItem('active_wallet_loginid', active_wallet_loginid); + sessionStorage.setItem('active_wallet_loginid', active_wallet_loginid); if (verification_code) { localStorage.setItem('verification_code.payment_withdraw', verification_code); } } - + sessionStorage.setItem('active_loginid', active_loginid); localStorage.setItem('active_loginid', active_loginid); localStorage.setItem('client.accounts', JSON.stringify(client_object)); this.syncWithLegacyPlatforms(active_loginid, this.accounts); diff --git a/packages/shared/src/utils/config/config.ts b/packages/shared/src/utils/config/config.ts index 742ed41d1f8c..ea966666454b 100644 --- a/packages/shared/src/utils/config/config.ts +++ b/packages/shared/src/utils/config/config.ts @@ -88,8 +88,8 @@ export const getSocketURL = (is_wallets = false) => { active_loginid_from_url = params.get('acct1'); } const local_storage_loginid = is_wallets - ? window.localStorage.getItem('active_wallet_loginid') - : window.localStorage.getItem('active_loginid'); + ? window.sessionStorage.getItem('active_wallet_loginid') || window.localStorage.getItem('active_wallet_loginid') + : window.sessionStorage.getItem('active_loginid') || window.localStorage.getItem('active_loginid'); const loginid = local_storage_loginid || active_loginid_from_url; const is_real = loginid && !/^(VRT|VRW)/.test(loginid); diff --git a/packages/utils/src/getActiveLoginIDFromLocalStorage.ts b/packages/utils/src/getActiveLoginIDFromLocalStorage.ts index bdf7c6db7d60..51cebc611a05 100644 --- a/packages/utils/src/getActiveLoginIDFromLocalStorage.ts +++ b/packages/utils/src/getActiveLoginIDFromLocalStorage.ts @@ -5,7 +5,7 @@ * @deprecated Please use 'WebSocketUtils.getActiveLoginid' from '@deriv-com/utils' instead of this. */ const getActiveLoginIDFromLocalStorage = (loginid_key = 'active_loginid') => { - const active_custom_loginid = localStorage.getItem(loginid_key); + const active_custom_loginid = sessionStorage.getItem(loginid_key) || localStorage.getItem(loginid_key); return active_custom_loginid ?? undefined; }; diff --git a/packages/wallets/src/hooks/__tests__/useWalletAccountSwitcher.spec.tsx b/packages/wallets/src/hooks/__tests__/useWalletAccountSwitcher.spec.tsx index f996f6aa3da7..fbd32132b2bb 100644 --- a/packages/wallets/src/hooks/__tests__/useWalletAccountSwitcher.spec.tsx +++ b/packages/wallets/src/hooks/__tests__/useWalletAccountSwitcher.spec.tsx @@ -106,6 +106,6 @@ describe('useWalletAccountSwitcher', () => { const switchWalletAccount = result.current; await switchWalletAccount('CRW34569'); - expect(global.localStorage.getItem('active_loginid')).toBe('CR34567'); + expect(global.sessionStorage.getItem('active_loginid')).toBe('CR34567'); }); }); diff --git a/packages/wallets/src/hooks/useSyncLocalStorageClientAccounts.ts b/packages/wallets/src/hooks/useSyncLocalStorageClientAccounts.ts index 214dafb42cbd..55b256002fab 100644 --- a/packages/wallets/src/hooks/useSyncLocalStorageClientAccounts.ts +++ b/packages/wallets/src/hooks/useSyncLocalStorageClientAccounts.ts @@ -122,6 +122,7 @@ const useSyncLocalStorageClientAccounts = () => { platform: 'dtrade', }, ]; + sessionStorage.setItem('active_loginid', newAccount.client_id); } setLocalStorageClientAccounts(localStorageData); diff --git a/packages/wallets/src/hooks/useWalletAccountSwitcher.ts b/packages/wallets/src/hooks/useWalletAccountSwitcher.ts index 1ca1bf0628d8..d2749f8a0001 100644 --- a/packages/wallets/src/hooks/useWalletAccountSwitcher.ts +++ b/packages/wallets/src/hooks/useWalletAccountSwitcher.ts @@ -7,6 +7,7 @@ const useWalletAccountSwitcher = () => { const switchWalletAccount = useCallback( async (loginid: string) => { + const url = new URL(window.location.href); const dtradeAccount = walletAccounts ?.find(account => account.loginid === loginid) ?.linked_to?.find(linkedAccount => linkedAccount.platform === 'dtrade'); @@ -16,8 +17,19 @@ const useWalletAccountSwitcher = () => { account => account.loginid === dtradeAccount?.loginid ); - if (dtradeAccount?.loginid && !linkedAccountDetails?.is_disabled) - localStorage.setItem('active_loginid', dtradeAccount.loginid); + const accountLoginId = + sessionStorage.getItem('active_wallet_loginid') || sessionStorage.getItem('active_loginid') || ''; + const accountParam = /^VR/.test(accountLoginId) + ? 'demo' + : authorizeData.account_list?.find(account => account.loginid === accountLoginId)?.currency; + if (accountParam) { + url.searchParams.set('account', accountParam); + window.history.replaceState({}, '', url.toString()); + } + + if (dtradeAccount?.loginid && !linkedAccountDetails?.is_disabled) { + sessionStorage.setItem('active_loginid', dtradeAccount.loginid); + } }, [_switchAccount, authorizeData.account_list, walletAccounts] );