diff --git a/packages/wallets/src/components/WalletsAddMoreCardBanner/WalletsAddMoreCardBanner.tsx b/packages/wallets/src/components/WalletsAddMoreCardBanner/WalletsAddMoreCardBanner.tsx index 58bba9ddb237..d5ca1619dee6 100644 --- a/packages/wallets/src/components/WalletsAddMoreCardBanner/WalletsAddMoreCardBanner.tsx +++ b/packages/wallets/src/components/WalletsAddMoreCardBanner/WalletsAddMoreCardBanner.tsx @@ -1,9 +1,15 @@ import React, { useEffect } from 'react'; +import Cookies from 'js-cookie'; import { useHistory } from 'react-router-dom'; -import { useCreateWallet } from '@deriv/api-v2'; +import { useActiveWalletAccount, useCreateWallet, useIsEuRegion } from '@deriv/api-v2'; import { LabelPairedCheckMdFillIcon, LabelPairedPlusMdFillIcon } from '@deriv/quill-icons'; +import { getAccountsFromLocalStorage } from '@deriv/utils'; +import { Analytics } from '@deriv-com/analytics'; import { Localize, useTranslations } from '@deriv-com/translations'; import { Button, useDevice } from '@deriv-com/ui'; +import { URLConstants } from '@deriv-com/utils'; +import { LANDING_COMPANIES } from '../../constants/constants'; +import { isProduction, OUT_SYSTEMS_TRADERSHUB } from '../../helpers/urls'; import useSyncLocalStorageClientAccounts from '../../hooks/useSyncLocalStorageClientAccounts'; import useWalletAccountSwitcher from '../../hooks/useWalletAccountSwitcher'; import { TWalletCarouselItem } from '../../types'; @@ -25,6 +31,8 @@ const WalletsAddMoreCardBanner: React.FC = ({ const modal = useModal(); const { addWalletAccountToLocalStorage } = useSyncLocalStorageClientAccounts(); const { localize } = useTranslations(); + const { data: isEuRegion } = useIsEuRegion(); + const { data: activeWallet } = useActiveWalletAccount(); useEffect( () => { @@ -61,6 +69,35 @@ const WalletsAddMoreCardBanner: React.FC = ({ ] ); + const redirectToOutSystems = () => { + // redirect to OS Tradershub if feature is enabled + const isOutSystemsRealAccountCreationEnabled = Analytics?.getFeatureValue( + 'trigger_os_real_account_creation', + false + ); + if (isOutSystemsRealAccountCreationEnabled) { + const clientAccounts = getAccountsFromLocalStorage() ?? {}; + const loginid = activeWallet?.loginid ?? ''; + if (!loginid) return; + const authToken = clientAccounts[loginid].token; + if (!authToken) return; + const expires = new Date(new Date().getTime() + 1 * 60 * 1000); // 1 minute + + Cookies.set('os_auth_token', authToken, { domain: URLConstants.baseDomain, expires }); + + const params = new URLSearchParams({ + action: 'real-account-signup', + currency: currency ?? '', + target: LANDING_COMPANIES.MALTAINVEST, + }); + const baseUrl = isProduction() ? OUT_SYSTEMS_TRADERSHUB.PRODUCTION : OUT_SYSTEMS_TRADERSHUB.STAGING; + + const redirectURL = new URL(`${baseUrl}/redirect`); + redirectURL.search = params.toString(); + return (window.location.href = redirectURL.toString()); + } + }; + return (
@@ -82,6 +119,10 @@ const WalletsAddMoreCardBanner: React.FC = ({ if (!currency) return; + if (isEuRegion) { + return redirectToOutSystems(); + } + const createAccountResponse = await mutateAsync({ account_type: isCrypto ? 'crypto' : 'doughflow', currency, diff --git a/packages/wallets/src/components/WalletsAddMoreCardBanner/__tests__/WalletsAddMoreCardBanner.spec.tsx b/packages/wallets/src/components/WalletsAddMoreCardBanner/__tests__/WalletsAddMoreCardBanner.spec.tsx index 3b313b8f2c2c..2d9926cc1549 100644 --- a/packages/wallets/src/components/WalletsAddMoreCardBanner/__tests__/WalletsAddMoreCardBanner.spec.tsx +++ b/packages/wallets/src/components/WalletsAddMoreCardBanner/__tests__/WalletsAddMoreCardBanner.spec.tsx @@ -1,8 +1,10 @@ -import React from 'react'; +import React, { PropsWithChildren } from 'react'; import { useHistory } from 'react-router-dom'; -import { useCreateWallet } from '@deriv/api-v2'; +import { useActiveWalletAccount, useCreateWallet, useIsEuRegion } from '@deriv/api-v2'; +import { Analytics } from '@deriv-com/analytics'; import { useDevice } from '@deriv-com/ui'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { isProduction } from '../../../helpers/urls'; import useSyncLocalStorageClientAccounts from '../../../hooks/useSyncLocalStorageClientAccounts'; import useWalletAccountSwitcher from '../../../hooks/useWalletAccountSwitcher'; import { ModalProvider } from '../../ModalProvider'; @@ -20,7 +22,13 @@ type TWalletAddedSuccess = { }; jest.mock('@deriv/api-v2', () => ({ + useActiveWalletAccount: jest.fn(() => ({ + data: { loginid: 'CRW1' }, + })), useCreateWallet: jest.fn(), + useIsEuRegion: jest.fn(() => ({ + data: false, + })), })); jest.mock('react-router-dom', () => ({ @@ -31,6 +39,24 @@ jest.mock('@deriv-com/ui', () => ({ ...jest.requireActual('@deriv-com/ui'), useDevice: jest.fn(() => ({})), })); + +jest.mock('@deriv/utils', () => ({ + ...jest.requireActual('@deriv/utils'), + getAccountsFromLocalStorage: jest.fn(() => ({ + VRW1: { + token: '12345', + }, + })), +})); + +jest.mock('../../../helpers/urls', () => ({ + isProduction: jest.fn(), + OUT_SYSTEMS_TRADERSHUB: { + PRODUCTION: 'https://hub.deriv.com/tradershub', + STAGING: 'https://staging-hub.deriv.com/tradershub', + }, +})); + jest.mock('../../../hooks/useSyncLocalStorageClientAccounts', () => jest.fn()); jest.mock('../../../hooks/useWalletAccountSwitcher', () => jest.fn()); @@ -56,6 +82,8 @@ jest.mock('../../WalletAddedSuccess', () => ({ ), })); +const wrapper = ({ children }: PropsWithChildren) => {children}; + describe('WalletsAddMoreCardBanner', () => { const mockMutate = jest.fn().mockResolvedValue({ new_account_wallet: { client_id: '123', currency: 'USD' } }); const mockHistoryPush = jest.fn(); @@ -228,7 +256,63 @@ describe('WalletsAddMoreCardBanner', () => { currency: 'USD', display_balance: '0.00 USD', }); + }); + await waitFor(() => { expect(mockSwitchWalletAccount).toHaveBeenCalledWith('123'); }); }); + + it('redirects to OutSystems staging for EU users on staging', async () => { + (isProduction as jest.Mock).mockReturnValue(false); + (useIsEuRegion as jest.Mock).mockReturnValue({ data: true }); + (useActiveWalletAccount as jest.Mock).mockReturnValue({ + data: { loginid: 'VRW1' }, + }); + + Analytics.getFeatureValue = jest.fn().mockReturnValue(true); + + const originalWindowLocation = window; + Object.defineProperty(window, 'location', { + value: { href: '' }, + }); + + render(, { wrapper }); + + const addButton = screen.getByText('Add'); + fireEvent.click(addButton); + expect(window.location.href).toBe( + 'https://staging-hub.deriv.com/tradershub/redirect?action=real-account-signup¤cy=USD&target=maltainvest' + ); + + Object.defineProperty(window, 'location', { + value: originalWindowLocation, + }); + }); + + it('redirects to OutSystems production for EU users on production', async () => { + (isProduction as jest.Mock).mockReturnValue(true); + (useIsEuRegion as jest.Mock).mockReturnValue({ data: true }); + (useActiveWalletAccount as jest.Mock).mockReturnValue({ + data: { loginid: 'VRW1' }, + }); + + Analytics.getFeatureValue = jest.fn().mockReturnValue(true); + + const originalWindowLocation = window; + Object.defineProperty(window, 'location', { + value: { href: '' }, + }); + + render(, { wrapper }); + + const addButton = screen.getByText('Add'); + fireEvent.click(addButton); + expect(window.location.href).toBe( + 'https://hub.deriv.com/tradershub/redirect?action=real-account-signup¤cy=USD&target=maltainvest' + ); + + Object.defineProperty(window, 'location', { + value: originalWindowLocation, + }); + }); }); diff --git a/packages/wallets/src/constants/constants.tsx b/packages/wallets/src/constants/constants.tsx index 53f53b1576ee..f5f06509613e 100644 --- a/packages/wallets/src/constants/constants.tsx +++ b/packages/wallets/src/constants/constants.tsx @@ -62,3 +62,11 @@ export const ACCOUNT_VERIFICATION_BADGE_STATUS = { IN_REVIEW: 'in_review', NEEDS_VERIFICATION: 'needs_verification', } as const; + +export const LANDING_COMPANIES = Object.freeze({ + BVI: 'bvi', + LABUAN: 'labuan', + MALTAINVEST: 'maltainvest', + SVG: 'svg', + VANUATU: 'vanuatu', +}); diff --git a/packages/wallets/src/helpers/urls.ts b/packages/wallets/src/helpers/urls.ts index f2c2d0042f0a..01de6f92a6ae 100644 --- a/packages/wallets/src/helpers/urls.ts +++ b/packages/wallets/src/helpers/urls.ts @@ -1,4 +1,4 @@ -import { LocalStorageUtils, URLUtils } from '@deriv-com/utils'; +import { AppIDConstants, LocalStorageUtils, URLUtils } from '@deriv-com/utils'; const isBrowser = () => typeof window !== 'undefined'; @@ -83,6 +83,11 @@ export const isStaging = (domain = window.location.hostname) => { return isStagingDerivApp; }; +export const isProduction = () => { + const allDomains = Object.keys(AppIDConstants.domainAppId).map(domain => `(www\\.)?${domain.replace('.', '\\.')}`); + return new RegExp(`^(${allDomains.join('|')})$`, 'i').test(window.location.hostname); +}; + /** * @deprecated Please use 'URLUtils.getDerivStaticURL' from '@deriv-com/utils' instead of this. */ @@ -110,3 +115,8 @@ export const getStaticUrl = ( return `${host}${lang}/${normalizePath(path)}`; }; + +export const OUT_SYSTEMS_TRADERSHUB = Object.freeze({ + PRODUCTION: `https://hub.${domainUrl}/tradershub`, + STAGING: `https://staging-hub.${domainUrl}/tradershub`, +});