diff --git a/packages/api/jest.config.js b/packages/api/jest.config.js
index f53d37480f70..207910d7e732 100644
--- a/packages/api/jest.config.js
+++ b/packages/api/jest.config.js
@@ -1 +1,5 @@
-module.exports = require('../../jest.config.base');
+const baseConfigForPackages = require('../../jest.config.base');
+
+module.exports = {
+ ...baseConfigForPackages,
+};
diff --git a/packages/cashier/src/components/account-prompt-dialog/__tests__/account-prompt-dialog.spec.tsx b/packages/cashier/src/components/account-prompt-dialog/__tests__/account-prompt-dialog.spec.tsx
deleted file mode 100644
index ff1ecdc3bb71..000000000000
--- a/packages/cashier/src/components/account-prompt-dialog/__tests__/account-prompt-dialog.spec.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react';
-import { render, screen } from '@testing-library/react';
-import { mockStore } from '@deriv/stores';
-import AccountPromptDialog from '../account-prompt-dialog';
-import CashierProviders from '../../../cashier-providers';
-
-jest.mock('@deriv/components', () => ({
- ...jest.requireActual('@deriv/components'),
- Dialog: () =>
Dialog
,
-}));
-
-describe('', () => {
- const mock_root_store = mockStore({
- client: {
- accounts: {
- CR90000001: { is_virtual: 0, currency: 'USD' },
- CR90000002: { is_virtual: 0, currency: 'BTC' },
- },
- },
- modules: {
- cashier: {
- account_prompt_dialog: {
- continueRoute: jest.fn(),
- is_confirmed: false,
- last_location: '',
- onCancel: jest.fn(),
- onConfirm: jest.fn(),
- should_show: true,
- },
- },
- },
- });
- it('should render dialog', () => {
- render(, {
- wrapper: ({ children }) => {children},
- });
-
- expect(screen.getByText('Dialog')).toBeInTheDocument();
- });
-});
diff --git a/packages/cashier/src/components/account-prompt-dialog/account-prompt-dialog.tsx b/packages/cashier/src/components/account-prompt-dialog/account-prompt-dialog.tsx
deleted file mode 100644
index 3730ad1a65f6..000000000000
--- a/packages/cashier/src/components/account-prompt-dialog/account-prompt-dialog.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-import { Dialog } from '@deriv/components';
-import { isCryptocurrency } from '@deriv/shared';
-import { localize, Localize } from '@deriv/translations';
-import { useStore, observer } from '@deriv/stores';
-import { useCashierStore } from '../../stores/useCashierStores';
-
-const AccountPromptDialog = observer(() => {
- const { client } = useStore();
- const { accounts } = client;
- const { account_prompt_dialog } = useCashierStore();
- const { continueRoute, is_confirmed, last_location, onCancel, onConfirm, should_show } = account_prompt_dialog;
-
- React.useEffect(continueRoute, [is_confirmed, last_location, continueRoute]);
-
- const non_crypto_account_loginid = React.useMemo(
- () =>
- Object.entries(accounts).reduce((initial_value, [loginid, settings]) => {
- return !settings.is_virtual && !isCryptocurrency(settings.currency || '') ? loginid : initial_value;
- }, ''),
- [accounts]
- );
-
- const non_crypto_currency = non_crypto_account_loginid && accounts[non_crypto_account_loginid].currency;
-
- return (
-
- );
-});
-
-export default AccountPromptDialog;
diff --git a/packages/cashier/src/components/account-prompt-dialog/index.ts b/packages/cashier/src/components/account-prompt-dialog/index.ts
deleted file mode 100644
index 96805fec7b2c..000000000000
--- a/packages/cashier/src/components/account-prompt-dialog/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import AccountPromptDialog from './account-prompt-dialog';
-
-export default AccountPromptDialog;
diff --git a/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding-details.spec.tsx b/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding-details.spec.tsx
deleted file mode 100644
index f8aa21047d28..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding-details.spec.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import React from 'react';
-import { fireEvent, render, screen } from '@testing-library/react';
-import CashierOnboardingDetails from '../cashier-onboarding-details';
-import type { TCashierOnboardingProvider } from '../cashier-onboarding-providers';
-
-describe('', () => {
- let props: TCashierOnboardingProvider;
- beforeEach(() => {
- props = {
- detail_click: jest.fn(),
- detail_description: 'Deposit via the following payment methods:',
- detail_header: 'Deposit via bank wire, credit card, and e-wallet',
- is_dark_mode_on: false,
- is_mobile: false,
- detail_contents: [
- {
- icons: [
- {
- dark: 'IcWalletCreditDebitDark',
- light: 'IcWalletCreditDebitLight',
- },
- ],
- },
- ],
- };
- });
-
- it('should show the proper messages', () => {
- render();
-
- expect(screen.getByText('Deposit via bank wire, credit card, and e-wallet')).toBeInTheDocument();
- expect(screen.getByText('Deposit via the following payment methods:')).toBeInTheDocument();
- });
-
- it('should show contain the correct className, when detail_contents has icons', () => {
- render();
-
- expect(screen.getByTestId('dt_cashier_onboarding_detail_array')).toBeInTheDocument();
- });
-
- it('should trigger onClick callback, when the user clicks on the block with details', () => {
- render();
-
- const details_block = screen.getByTestId('dt_cashier_onboarding_detail_div');
- fireEvent.click(details_block);
-
- expect(props.detail_click).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding-side-note.spec.tsx b/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding-side-note.spec.tsx
deleted file mode 100644
index a86fb9b09ca1..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding-side-note.spec.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-import React from 'react';
-import { fireEvent, render, screen } from '@testing-library/react';
-import CashierOnboardingSideNote from '../cashier-onboarding-side-note';
-import { mockStore } from '@deriv/stores';
-import CashierProviders from '../../../cashier-providers';
-
-describe('', () => {
- let mockRootStore: ReturnType;
- beforeEach(() => {
- mockRootStore = mockStore({
- client: {
- currency: 'USD',
- },
- ui: {
- openRealAccountSignup: jest.fn(),
- },
- modules: {
- cashier: {
- general_store: {
- setDepositTarget: jest.fn(),
- },
- },
- },
- });
- });
-
- const props = {
- is_crypto: false,
- };
-
- const renderCashierOnboardingSideNote = () =>
- render(, {
- wrapper: ({ children }) => {children},
- });
-
- it('should show the proper messages, with fiat currency and can_change_fiat_currency={false} property', () => {
- if (mockRootStore.client) mockRootStore.client.loginid = 'CR12345678';
- renderCashierOnboardingSideNote();
-
- expect(screen.getByText('This is your USD account CR12345678')).toBeInTheDocument();
- expect(screen.getByTestId('dt_side_note_text')).toHaveTextContent(
- 'If you want to change your account currency, please contact us via live chat.'
- );
- });
-
- it('should trigger onClick callback when the client clicks the "live chat" link', () => {
- window.LC_API = {
- on_chat_ended: jest.fn(),
- open_chat_window: jest.fn(),
- };
- renderCashierOnboardingSideNote();
-
- const live_chat_link = screen.getByText('live chat');
- fireEvent.click(live_chat_link);
- expect(window.LC_API.open_chat_window).toHaveBeenCalledTimes(1);
- });
-
- it('should show the proper messages when is_crypto is true', () => {
- if (mockRootStore.client) mockRootStore.client.currency = 'BTC';
- if (mockRootStore.client) mockRootStore.client.loginid = 'CR12345678';
- props.is_crypto = true;
-
- renderCashierOnboardingSideNote();
-
- expect(screen.getByText('This is your BTC account CR12345678')).toBeInTheDocument();
- expect(
- screen.getByText("Don't want to trade in BTC? You can open another cryptocurrency account.")
- ).toBeInTheDocument();
- expect(screen.getByText('Manage your accounts')).toBeInTheDocument();
- });
-
- it('should trigger onClick callbacks when the client clicks on "Manage your accounts" link', () => {
- if (mockRootStore.client) mockRootStore.client.currency = 'BTC';
- props.is_crypto = true;
-
- renderCashierOnboardingSideNote();
-
- fireEvent.click(screen.getByTestId('dt_cashier_onboarding_side_note_link'));
- expect(mockRootStore.ui?.openRealAccountSignup).toHaveBeenCalledTimes(1);
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding.spec.tsx b/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding.spec.tsx
deleted file mode 100644
index 6bdf53a8a90c..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/__tests__/cashier-onboarding.spec.tsx
+++ /dev/null
@@ -1,400 +0,0 @@
-import React from 'react';
-import { createBrowserHistory } from 'history';
-import { fireEvent, render, screen } from '@testing-library/react';
-import CashierOnboarding from '../cashier-onboarding';
-import { Router } from 'react-router';
-import { routes } from '@deriv/shared';
-import { mockStore } from '@deriv/stores';
-import CashierProviders from '../../../cashier-providers';
-
-jest.mock('@deriv/hooks', () => {
- return {
- ...jest.requireActual('@deriv/hooks'),
- usePaymentAgentList: jest.fn(() => ({ data: ['PA1', 'PA2'], isLoading: false })),
- useIsP2PEnabled: jest.fn(() => ({ data: true, isLoading: false, isSuccess: true })),
- useHasUSDCurrency: jest.fn(() => true),
- };
-});
-
-describe('', () => {
- let mockRootStore: ReturnType;
- beforeEach(() => {
- mockRootStore = mockStore({
- client: {
- accounts: { CR90000001: { is_virtual: 0, currency: 'USD' } },
- account_status: {
- cashier_validation: [],
- },
- loginid: undefined,
- current_currency_type: 'crypto',
- is_deposit_lock: false,
- is_withdrawal_lock: true,
- is_identity_verification_needed: false,
- is_switching: false,
- is_landing_company_loaded: true,
- currency: 'USD',
- available_crypto_currencies: ['BTC', 'ETH'],
- account_list: [],
- is_crypto: jest.fn(),
- },
- common: {
- is_from_derivgo: false,
- },
- ui: {
- openRealAccountSignup: jest.fn(),
- shouldNavigateAfterChooseCrypto: jest.fn(),
- toggleSetCurrencyModal: jest.fn(),
- is_mobile: false,
- },
- modules: {
- cashier: {
- general_store: {
- onMountCashierOnboarding: jest.fn(),
- setDepositTarget: jest.fn(),
- setIsCashierOnboarding: jest.fn(),
- setIsDeposit: jest.fn(),
- setShouldShowAllAvailableCurrencies: jest.fn(),
- has_set_currency: true,
- },
- account_prompt_dialog: {
- shouldNavigateAfterPrompt: jest.fn(),
- },
- payment_agent: {
- is_payment_agent_visible_in_onboarding: true,
- },
- },
- },
- });
- });
-
- const props = () => ({
- setSideNotes: jest.fn(),
- });
-
- const history = createBrowserHistory();
-
- const renderCashierOnboarding = () =>
- render(, {
- wrapper: ({ children }) => {children},
- });
-
- const renderCashierOnboardingWithRouter = () =>
- render(
-
-
- ,
- {
- wrapper: ({ children }) => {children},
- }
- );
-
- it('should show the proper messages when is rendered with fiat account', () => {
- renderCashierOnboarding();
-
- expect(screen.getByText('Choose a way to fund your account')).toBeInTheDocument();
- expect(
- screen.getByText('Please note that some payment methods might not be available in your country.')
- ).toBeInTheDocument();
- expect(screen.getByText('Deposit via bank wire, credit card, and e-wallet')).toBeInTheDocument();
- expect(screen.getByText('Deposit via the following payment methods:')).toBeInTheDocument();
- expect(screen.getByText('Deposit cryptocurrencies')).toBeInTheDocument();
- expect(screen.getByText('We accept the following cryptocurrencies:')).toBeInTheDocument();
- expect(screen.getByText('Buy cryptocurrencies via fiat onramp')).toBeInTheDocument();
- expect(screen.getByText('Choose any of these exchanges to buy cryptocurrencies:')).toBeInTheDocument();
- expect(screen.getByText('Deposit via payment agents')).toBeInTheDocument();
- expect(
- screen.getByText(
- 'Deposit in your local currency via an authorised, independent payment agent in your country.'
- )
- ).toBeInTheDocument();
- expect(screen.getByText('Deposit with Deriv P2P')).toBeInTheDocument();
- expect(
- screen.getByText(
- 'Deposit with your local currency via peer-to-peer exchange with fellow traders in your country.'
- )
- ).toBeInTheDocument();
- });
-
- it('should show the proper message when is rendered with crypto account', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000002: { is_virtual: 0, currency: 'BTC' } };
- if (mockRootStore.client) mockRootStore.client.currency = 'BTC';
- renderCashierOnboarding();
-
- expect(screen.getByText('Buy cryptocurrencies')).toBeInTheDocument();
- expect(screen.queryByText('Buy cryptocurrencies via fiat onramp')).not.toBeInTheDocument();
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit via bank wire, credit card, and e-wallet" section from his fiat account', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000001: { is_virtual: 0, currency: 'USD' } };
- if (mockRootStore.client) mockRootStore.client.currency = 'USD';
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_bank_card_ewallet_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes('Deposit via the following payment methods:')
- );
- if (deposit_bank_card_ewallet_detail_div) fireEvent.click(deposit_bank_card_ewallet_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.modules?.cashier?.general_store?.setIsDeposit).toHaveBeenCalledTimes(1);
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit via bank wire, credit card, and e-wallet" section from his crypto account, not having the fiat account', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000002: { is_virtual: 0, currency: 'BTC' } };
- if (mockRootStore.client) mockRootStore.client.currency = 'BTC';
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_bank_card_ewallet_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes('Deposit via the following payment methods:')
- );
- if (deposit_bank_card_ewallet_detail_div) fireEvent.click(deposit_bank_card_ewallet_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.openRealAccountSignup).toHaveBeenCalledTimes(1);
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit via bank wire, credit card, and e-wallet" section from his crypto account, having the fiat account', () => {
- if (mockRootStore.client) {
- mockRootStore.client.accounts = {
- CR90000001: { is_virtual: 0, currency: 'USD' },
- CR90000002: { is_virtual: 0, currency: 'BTC' },
- };
- mockRootStore.client.currency = 'BTC';
- }
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_bank_card_ewallet_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes('Deposit via the following payment methods:')
- );
- if (deposit_bank_card_ewallet_detail_div) fireEvent.click(deposit_bank_card_ewallet_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.modules?.cashier?.account_prompt_dialog?.shouldNavigateAfterPrompt).toHaveBeenCalledTimes(
- 1
- );
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit cryptocurrencies" section from his fiat account, not having the crypto account', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000001: { is_virtual: 0, currency: 'USD' } };
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_crypto_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes('We accept the following cryptocurrencies:')
- );
- if (deposit_crypto_detail_div) fireEvent.click(deposit_crypto_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.openRealAccountSignup).toHaveBeenCalledTimes(1);
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit cryptocurrencies" section from his crypto account', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000002: { is_virtual: 0, currency: 'BTC' } };
- if (mockRootStore.client) mockRootStore.client.currency = 'BTC';
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_crypto_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes('We accept the following cryptocurrencies:')
- );
- if (deposit_crypto_detail_div) fireEvent.click(deposit_crypto_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.openRealAccountSignup).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.shouldNavigateAfterChooseCrypto).toHaveBeenCalledTimes(1);
- });
-
- it('should trigger proper callbacks when the client chooses "Buy cryptocurrencies via fiat onramp" section from his fiat account, not having the crypto account', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000001: { is_virtual: 0, currency: 'USD' } };
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const buy_crypto_onramp_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes('Choose any of these exchanges to buy cryptocurrencies:')
- );
- if (buy_crypto_onramp_detail_div) fireEvent.click(buy_crypto_onramp_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.openRealAccountSignup).toHaveBeenCalledTimes(1);
- });
-
- it('should trigger proper callbacks when the client chooses "Buy cryptocurrencies" section from his crypto account', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000002: { is_virtual: 0, currency: 'BTC' } };
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const buy_crypto_onramp_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes('Choose any of these exchanges to buy cryptocurrencies:')
- );
- if (buy_crypto_onramp_detail_div) fireEvent.click(buy_crypto_onramp_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.openRealAccountSignup).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.shouldNavigateAfterChooseCrypto).toHaveBeenCalledTimes(1);
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit via payment agents" section', () => {
- if (mockRootStore.client) {
- mockRootStore.client.accounts = {
- CR90000001: { is_virtual: 0, currency: 'USD' },
- CR90000002: { is_virtual: 0, currency: 'BTC' },
- };
- }
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_via_pa_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes(
- 'Deposit in your local currency via an authorised, independent payment agent in your country.'
- )
- );
- if (deposit_via_pa_detail_div) fireEvent.click(deposit_via_pa_detail_div);
-
- expect(
- mockRootStore.modules?.cashier?.general_store?.setShouldShowAllAvailableCurrencies
- ).toHaveBeenCalledTimes(1);
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.openRealAccountSignup).toHaveBeenCalledTimes(1);
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit with Deriv P2P" section from his fiat account', () => {
- if (mockRootStore.client) {
- mockRootStore.client.accounts = {
- CR90000001: { is_virtual: 0, currency: 'USD' },
- CR90000002: { is_virtual: 0, currency: 'BTC' },
- };
- }
-
- renderCashierOnboardingWithRouter();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_with_dp2p_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes(
- 'Deposit with your local currency via peer-to-peer exchange with fellow traders in your country.'
- )
- );
- if (deposit_with_dp2p_detail_div) fireEvent.click(deposit_with_dp2p_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(history.location.pathname).toBe(routes.cashier_p2p);
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit with Deriv P2P" section from his crypto account, already having the fiat account', () => {
- if (mockRootStore.client) {
- mockRootStore.client.accounts = {
- CR90000001: { is_virtual: 0, currency: 'USD' },
- CR90000002: { is_virtual: 0, currency: 'BTC' },
- };
- mockRootStore.client.currency = 'BTC';
- }
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_with_dp2p_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes(
- 'Deposit with your local currency via peer-to-peer exchange with fellow traders in your country.'
- )
- );
- if (deposit_with_dp2p_detail_div) fireEvent.click(deposit_with_dp2p_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.modules?.cashier?.account_prompt_dialog?.shouldNavigateAfterPrompt).toHaveBeenCalledTimes(
- 1
- );
- });
-
- it('should trigger proper callbacks when the client chooses "Deposit with Deriv P2P" section from his crypto account, not having the fiat account', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000002: { is_virtual: 0, currency: 'BTC' } };
- if (mockRootStore.client) mockRootStore.client.currency = 'BTC';
-
- renderCashierOnboarding();
-
- const node_list = screen.getAllByTestId('dt_cashier_onboarding_detail_div');
- const deposit_with_dp2p_detail_div = Array.from(node_list).find(node =>
- node.textContent?.includes(
- 'Deposit with your local currency via peer-to-peer exchange with fellow traders in your country.'
- )
- );
- if (deposit_with_dp2p_detail_div) fireEvent.click(deposit_with_dp2p_detail_div);
-
- expect(mockRootStore.modules?.cashier?.general_store?.setDepositTarget).toHaveBeenCalledTimes(1);
- expect(mockRootStore.ui?.openRealAccountSignup).toHaveBeenCalledTimes(1);
- });
-
- it('should show the "Learn more about payment methods" message in Mobile mode', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000001: { is_virtual: 0, currency: 'USD' } };
- if (mockRootStore.ui) mockRootStore.ui.is_mobile = true;
-
- renderCashierOnboarding();
-
- expect(screen.getByText('Learn more about payment methods')).toBeInTheDocument();
- });
-
- it('should trigger onClick callback when the user clicks "Learn more about payment methods" message in Mobile mode', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000001: { is_virtual: 0, currency: 'USD' } };
- if (mockRootStore.ui) mockRootStore.ui.is_mobile = true;
- window.open = jest.fn();
-
- renderCashierOnboarding();
-
- const link = screen.getByTestId('dt_cashier_onboarding_header_learn_more');
- fireEvent.click(link);
-
- expect(window.open).toHaveBeenCalledTimes(1);
- });
-
- it('should not show "Choose a way to fund your account" message if is_switching is true', () => {
- if (mockRootStore.client) mockRootStore.client.is_switching = true;
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000001: { is_virtual: 0, currency: 'USD' } };
-
- renderCashierOnboarding();
-
- expect(screen.queryByText('Choose a way to fund your account')).not.toBeInTheDocument();
- });
-
- it('should not show "Choose a way to fund your account" message if accounts_list is an empty array', () => {
- if (mockRootStore.client?.accounts) mockRootStore.client.accounts = {};
-
- renderCashierOnboarding();
-
- expect(screen.queryByText('Choose a way to fund your account')).not.toBeInTheDocument();
- });
-
- it('should not show "Choose a way to fund your account" message if is_landing_company_loaded is false', () => {
- if (mockRootStore.client) mockRootStore.client.accounts = { CR90000001: { is_virtual: 0, currency: 'USD' } };
- if (mockRootStore.client) mockRootStore.client.is_landing_company_loaded = false;
-
- renderCashierOnboarding();
-
- expect(screen.queryByText('Choose a way to fund your account')).not.toBeInTheDocument();
- });
-
- it('should redirect to "routes.trade" when the component will unmount', () => {
- if (mockRootStore.client) {
- mockRootStore.client.accounts = {
- CR90000001: { is_virtual: 0, currency: 'USD' },
- CR90000002: { is_virtual: 0, currency: 'BTC' },
- };
- }
- if (mockRootStore.modules?.cashier?.general_store) {
- mockRootStore.modules.cashier.general_store.has_set_currency = false;
- }
-
- const { unmount } = renderCashierOnboardingWithRouter();
- unmount();
-
- expect(history.location.pathname).toBe(routes.trade);
- expect(mockRootStore.ui?.toggleSetCurrencyModal).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-details.tsx b/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-details.tsx
deleted file mode 100644
index 9a120641f620..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-details.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import classNames from 'classnames';
-import React from 'react';
-import { Icon, NewsTicker, Text } from '@deriv/components';
-import type { TCashierOnboardingProvider } from './cashier-onboarding-providers';
-import './cashier-onboarding.scss';
-
-const CashierOnboardingDetails = ({
- detail_click,
- detail_contents,
- detail_description,
- detail_header,
- is_dark_mode_on,
- is_mobile,
-}: TCashierOnboardingProvider) => {
- return (
-
-
- {detail_header}
-
-
-
-
- {detail_description}
-
-
-
- {detail_contents?.map((content, id) => (
-
-
-
-
- {content.icons?.map((icon, index) => {
- return (
-
-
-
- );
- })}
-
-
-
-
- ))}
-
-
- );
-};
-
-export default CashierOnboardingDetails;
diff --git a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-providers.ts b/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-providers.ts
deleted file mode 100644
index 5885c1ba9b16..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-providers.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import { localize } from '@deriv/translations';
-
-export type TCashierOnboardingProvider = {
- detail_click: VoidFunction;
- detail_contents?: {
- icons: { light: string; dark: string }[];
- }[];
- detail_description: string;
- detail_header: string;
- is_dark_mode_on?: boolean;
- is_mobile?: boolean;
-};
-
-const cash_contents = [
- {
- icons: [
- { light: 'IcWalletCreditDebitLight', dark: 'IcWalletCreditDebitDark' },
- { light: 'IcCashierInstantBankTransferLight', dark: 'IcCashierInstantBankTransferDark' },
- { light: 'IcCashierEwalletLight', dark: 'IcCashierEwalletDark' },
- { light: 'IcCashierLocalPaymentMethodsLight', dark: 'IcCashierLocalPaymentMethodsDark' },
- ],
- },
-];
-const crypto_contents = [
- {
- icons: [
- { light: 'IcCashierBitcoinLight', dark: 'IcCashierBitcoinDark' },
- { light: 'IcCashierEthereumLight', dark: 'IcCashierEthereumDark' },
- { light: 'IcCashierLiteCoinLight', dark: 'IcCashierLiteCoinDark' },
- { light: 'IcCashierUsdCoinLight', dark: 'IcCashierUsdCoinDark' },
- { light: 'IcCashierTetherLight', dark: 'IcCashierTetherDark' },
- ],
- },
-];
-const onramp_contents = [
- {
- icons: [{ light: 'IcCashierBanxaLight', dark: 'IcCashierBanxaDark' }],
- },
-];
-
-const createCashProvider = (onClick: VoidFunction) => {
- return {
- detail_click: onClick,
- detail_description: localize('Deposit via the following payment methods:'),
- detail_header: localize('Deposit via bank wire, credit card, and e-wallet'),
- detail_contents: cash_contents,
- };
-};
-
-const createCryptoProvider = (onClick: VoidFunction) => {
- return {
- detail_click: onClick,
- detail_description: localize('We accept the following cryptocurrencies:'),
- detail_header: localize('Deposit cryptocurrencies'),
- detail_contents: crypto_contents,
- };
-};
-
-const createOnrampProvider = (onClick: VoidFunction, is_crypto: boolean) => {
- return {
- detail_click: onClick,
- detail_description: localize('Choose any of these exchanges to buy cryptocurrencies:'),
- detail_header: is_crypto ? localize('Buy cryptocurrencies') : localize('Buy cryptocurrencies via fiat onramp'),
- detail_contents: onramp_contents,
- };
-};
-
-const createPaymentAgentProvider = (onClick: VoidFunction) => {
- return {
- detail_click: onClick,
- detail_description: localize(
- 'Deposit in your local currency via an authorised, independent payment agent in your country.'
- ),
- detail_header: localize('Deposit via payment agents'),
- };
-};
-
-const createDp2pProvider = (onClick: VoidFunction) => {
- return {
- detail_click: onClick,
- detail_description: localize(
- 'Deposit with your local currency via peer-to-peer exchange with fellow traders in your country.'
- ),
- detail_header: localize('Deposit with Deriv P2P'),
- };
-};
-
-export default {
- createCashProvider,
- createCryptoProvider,
- createDp2pProvider,
- createOnrampProvider,
- createPaymentAgentProvider,
-};
diff --git a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-side-note.tsx b/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-side-note.tsx
deleted file mode 100644
index 6a167d72ae5a..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding-side-note.tsx
+++ /dev/null
@@ -1,98 +0,0 @@
-import React from 'react';
-import { Localize } from '@deriv/translations';
-import { Icon, Text } from '@deriv/components';
-import { getCurrencyDisplayCode, getPlatformSettings, routes, isMobile } from '@deriv/shared';
-import { useStore, observer } from '@deriv/stores';
-import { useCashierStore } from '../../stores/useCashierStores';
-import './cashier-onboarding.scss';
-
-type TCashierOnboardingSideNoteProps = {
- is_crypto?: boolean;
-};
-
-const CashierOnboardingSideNote = observer(({ is_crypto }: TCashierOnboardingSideNoteProps) => {
- const { client, ui } = useStore();
- const { general_store } = useCashierStore();
- const { currency, is_eu, loginid, is_low_risk } = client;
- const { openRealAccountSignup } = ui;
- const { setDepositTarget } = general_store;
-
- const currency_code = getCurrencyDisplayCode(currency);
-
- const getSideNoteDescription = () => {
- if (is_crypto) {
- return (
-
- );
- }
-
- return (
- window.LC_API.open_chat_window()}
- />,
- ]}
- values={{ platform_name_dxtrade: getPlatformSettings('dxtrade').name }}
- />
- );
- };
-
- const getHeaderTitle = () => {
- if (is_low_risk && !is_crypto) {
- const regulation_text = is_eu ? 'EU' : 'non-EU';
- return (
-
- );
- }
- return (
-
- );
- };
-
- return (
-
-
- {getHeaderTitle()}
-
-
- {getSideNoteDescription()}
-
- {is_crypto && (
-
{
- setDepositTarget(routes.cashier_deposit);
- openRealAccountSignup('add_crypto');
- }}
- >
-
-
-
-
-
- )}
-
- );
-});
-
-export default CashierOnboardingSideNote;
diff --git a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding.scss b/packages/cashier/src/components/cashier-onboarding/cashier-onboarding.scss
deleted file mode 100644
index fb50d42cdb4e..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding.scss
+++ /dev/null
@@ -1,137 +0,0 @@
-.cashier-onboarding {
- height: calc(100vh - 20rem);
-
- @include mobile {
- height: unset;
- margin-top: 2.4rem;
- }
-
- &__loader {
- position: relative;
- left: 0;
- }
-
- &-header {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin-bottom: 2rem;
-
- @include mobile {
- margin-right: 4rem;
- margin-left: 4rem;
- }
-
- &-learn-more {
- text-align: center;
- }
- }
-
- &-content {
- &::-webkit-scrollbar {
- display: none;
- }
-
- &__description {
- margin-bottom: 5rem;
- }
- }
-
- &-detail {
- margin: 2.4rem;
- width: 62.4rem;
-
- // TODO: Replace the media query with Mobile/Tablet mixin after syncing the responsive.js and devices.scss
- @media (max-width: 926px) {
- width: unset;
- }
-
- &__icons {
- position: relative;
- margin-top: auto;
- overflow: hidden;
- width: 100%;
- }
-
- &__div {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: flex-start;
- padding: 1.6rem;
- position: static;
- border: 2px solid var(--border-normal-1);
- border-radius: $BORDER_RADIUS * 2;
- margin: 0.8rem 0rem;
- cursor: pointer;
- }
-
- &__content {
- display: flex;
- flex-direction: row;
- align-items: center;
- width: 100%;
- }
-
- &__text {
- position: static;
- width: 100%;
- }
-
- &__array {
- display: flex;
- flex-direction: row;
- align-items: center;
- position: static;
- margin-top: 1.6rem;
- gap: 1.2rem;
- width: 100%;
- white-space: nowrap;
-
- @include mobile {
- flex-direction: column;
- align-items: flex-start;
- width: 100%;
- }
- }
-
- &__icons-array {
- display: flex;
- flex-direction: row;
- align-items: center;
- margin-right: 1.2rem;
- }
-
- &__icon {
- margin-right: 1.2rem;
-
- @include mobile {
- display: inline-block;
- }
- }
- }
-
- &-side-note {
- &__link {
- cursor: pointer;
- display: flex;
- align-items: center;
-
- &:hover {
- text-decoration: underline var(--brand-red-coral);
- }
-
- .dc-text {
- margin-right: 0.4rem;
- }
- }
-
- &__text {
- margin-bottom: 0.8rem;
-
- &-nowrap {
- white-space: nowrap;
- }
- }
- }
-}
diff --git a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding.tsx b/packages/cashier/src/components/cashier-onboarding/cashier-onboarding.tsx
deleted file mode 100644
index 35bb9845d97e..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/cashier-onboarding.tsx
+++ /dev/null
@@ -1,232 +0,0 @@
-import React from 'react';
-import { useHistory } from 'react-router-dom';
-import { usePaymentAgentList, useHasUSDCurrency, useIsP2PEnabled } from '@deriv/hooks';
-import { getStaticUrl, isCryptocurrency, routes } from '@deriv/shared';
-import { Localize } from '@deriv/translations';
-import { Loading, ThemedScrollbars, Text } from '@deriv/components';
-import { useStore, observer } from '@deriv/stores';
-import Providers from './cashier-onboarding-providers';
-import CashierOnboardingDetails from './cashier-onboarding-details';
-import CashierOnboardingSideNote from './cashier-onboarding-side-note';
-import SideNote from 'Components/side-note';
-import type { TCashierOnboardingProvider } from './cashier-onboarding-providers';
-import { useCashierStore } from '../../stores/useCashierStores';
-
-type TCashierOnboardingProps = {
- setSideNotes?: (component: React.ReactElement[]) => void;
-};
-
-const CashierOnboarding = observer(({ setSideNotes }: TCashierOnboardingProps) => {
- const { client, ui, common } = useStore();
- const { general_store, account_prompt_dialog } = useCashierStore();
- const {
- accounts,
- available_crypto_currencies,
- can_change_fiat_currency,
- currency,
- is_landing_company_loaded,
- is_switching,
- } = client;
- const { is_from_derivgo } = common;
- const {
- has_set_currency,
- onMountCashierOnboarding,
- is_cashier_onboarding,
- setIsCashierOnboarding,
- setIsDeposit,
- setDepositTarget,
- setShouldShowAllAvailableCurrencies,
- } = general_store;
- const {
- app_contents_scroll_ref,
- is_dark_mode_on,
- is_mobile,
- openRealAccountSignup,
- shouldNavigateAfterChooseCrypto,
- toggleSetCurrencyModal,
- } = ui;
- const { shouldNavigateAfterPrompt } = account_prompt_dialog;
- const { data: is_p2p_enabled, isLoading: is_p2p_enabled_loading } = useIsP2PEnabled();
-
- const has_usd_currency = useHasUSDCurrency();
-
- const history = useHistory();
- const is_crypto = !!currency && isCryptocurrency(currency);
- const has_crypto_account = React.useMemo(
- () => Object.values(accounts).some(acc_settings => isCryptocurrency(acc_settings.currency || '')),
- [accounts]
- );
- const has_fiat_account = React.useMemo(
- () =>
- Object.values(accounts).some(
- acc_settings => !acc_settings.is_virtual && !isCryptocurrency(acc_settings.currency || '')
- ),
- [accounts]
- );
-
- const is_currency_banner_visible =
- (!is_crypto && !can_change_fiat_currency) || (is_crypto && available_crypto_currencies.length > 0);
-
- const { data: all_payment_agent_list, isLoading: is_loading } = usePaymentAgentList();
-
- const is_payment_agent_visible_in_onboarding = Boolean(all_payment_agent_list?.length);
-
- React.useEffect(() => {
- onMountCashierOnboarding();
- return () => {
- setIsCashierOnboarding(false);
- if (!has_set_currency && window.location.pathname.includes(routes.cashier)) {
- history.push(routes.trade);
- toggleSetCurrencyModal();
- }
- };
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
- React.useEffect(() => {
- return () => {
- if (app_contents_scroll_ref.current) app_contents_scroll_ref.current.scrollTop = 0;
- };
- }, [app_contents_scroll_ref]);
-
- React.useEffect(() => {
- if (
- typeof setSideNotes === 'function' &&
- !is_switching &&
- Object.keys(accounts).length > 0 &&
- is_landing_company_loaded &&
- is_currency_banner_visible
- ) {
- setSideNotes([]);
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [is_switching, accounts, is_landing_company_loaded, is_cashier_onboarding]);
-
- const openRealAccount = (target: string) => {
- openRealAccountSignup('choose');
- shouldNavigateAfterChooseCrypto(target);
- };
-
- const openTarget = (target: string) => {
- setDepositTarget(target);
- if (is_crypto || has_crypto_account) {
- openRealAccount(target);
- } else {
- openRealAccountSignup('add_crypto');
- }
- };
-
- const fiatAccountConditions = (next_location: string, current_location: string) => {
- if (has_fiat_account) {
- shouldNavigateAfterPrompt(next_location, current_location);
- } else {
- openRealAccountSignup('add_fiat');
- }
- };
-
- const onClickDepositCash = () => {
- setDepositTarget(routes.cashier_deposit);
-
- if (is_crypto) {
- fiatAccountConditions(routes.cashier_deposit, 'deposit');
- } else {
- setIsDeposit(true);
- }
- };
-
- const onClickDepositCrypto = () => {
- openTarget(routes.cashier_deposit);
- };
-
- const onClickOnramp = () => {
- openTarget(routes.cashier_onramp);
- };
-
- const onClickPaymentAgent = () => {
- setShouldShowAllAvailableCurrencies(true);
- setDepositTarget(routes.cashier_pa);
- openRealAccount(routes.cashier_pa);
- };
-
- const onClickDp2p = () => {
- setDepositTarget(routes.cashier_p2p);
-
- if (is_crypto) {
- fiatAccountConditions(routes.cashier_p2p, 'DP2P');
- } else {
- history.push(routes.cashier_p2p);
- }
- };
-
- const getDepositOptions = () => {
- const options: TCashierOnboardingProvider[] = [];
- options.push(Providers.createCashProvider(onClickDepositCash));
- options.push(Providers.createCryptoProvider(onClickDepositCrypto));
- options.push(Providers.createOnrampProvider(onClickOnramp, is_crypto));
- if (is_payment_agent_visible_in_onboarding) {
- options.push(Providers.createPaymentAgentProvider(onClickPaymentAgent));
- }
-
- if (is_p2p_enabled && has_usd_currency) {
- options.push(Providers.createDp2pProvider(onClickDp2p));
- }
- return options;
- };
-
- if (
- is_switching ||
- Object.keys(accounts).length === 0 ||
- !is_landing_company_loaded ||
- is_loading ||
- is_p2p_enabled_loading
- )
- return ;
-
- return (
-
- {is_currency_banner_visible && (
-
-
-
- )}
-
-
-
-
-
-
-
-
-
- {is_mobile && !is_from_derivgo && (
-
window.open(getStaticUrl('/payment-methods'))}
- >
-
-
-
-
- )}
-
-
- {getDepositOptions()?.map((deposit, idx) => (
-
- ))}
-
-
-
-
- );
-});
-
-export default CashierOnboarding;
diff --git a/packages/cashier/src/components/cashier-onboarding/index.tsx b/packages/cashier/src/components/cashier-onboarding/index.tsx
deleted file mode 100644
index a0d9f9e2ce2f..000000000000
--- a/packages/cashier/src/components/cashier-onboarding/index.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-import CashierOnboarding from './cashier-onboarding';
-import CashierOnboardingSideNote from './cashier-onboarding-side-note';
-
-export { CashierOnboarding, CashierOnboardingSideNote };
diff --git a/packages/cashier/src/components/page-container/__test__/page-container.test.tsx b/packages/cashier/src/components/page-container/__test__/page-container.test.tsx
new file mode 100644
index 000000000000..ed4b8dca8ffa
--- /dev/null
+++ b/packages/cashier/src/components/page-container/__test__/page-container.test.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { mockStore } from '@deriv/stores';
+import { render, screen } from '@testing-library/react';
+import CashierProviders from '../../../cashier-providers';
+import PageContainer from '../page-container';
+
+describe('PageContainer', () => {
+ test('should show loading if is_authorize is false', () => {
+ const mock = mockStore({ client: { is_authorize: false } });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ render(
+
+ children
+ ,
+ { wrapper }
+ );
+
+ expect(screen.getByTestId('dt_initial_loader')).toBeInTheDocument();
+ });
+
+ test('should show children if is_authorize is true', () => {
+ const mock = mockStore({
+ client: { is_authorize: true },
+ modules: { cashier: { general_store: { setIsDeposit: jest.fn() } } },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ render(
+
+ children
+ ,
+ { wrapper }
+ );
+
+ expect(screen.getByText('children')).toBeInTheDocument();
+ });
+});
diff --git a/packages/cashier/src/components/page-container/index.ts b/packages/cashier/src/components/page-container/index.ts
new file mode 100644
index 000000000000..211a01ed4a01
--- /dev/null
+++ b/packages/cashier/src/components/page-container/index.ts
@@ -0,0 +1,3 @@
+import PageContainer from './page-container';
+
+export { PageContainer };
diff --git a/packages/cashier/src/components/page-container/page-container.scss b/packages/cashier/src/components/page-container/page-container.scss
new file mode 100644
index 000000000000..d450a607ae40
--- /dev/null
+++ b/packages/cashier/src/components/page-container/page-container.scss
@@ -0,0 +1,24 @@
+.page-container {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ gap: 1.6rem;
+ background-color: var(--general-main-1);
+ height: calc(100vh - 17rem);
+
+ @include mobile {
+ height: calc(100vh - 8rem);
+ }
+
+ &__content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 0 2.4rem 2.4rem;
+ gap: 2.4rem;
+
+ @include mobile {
+ padding: 1.6rem;
+ }
+ }
+}
diff --git a/packages/cashier/src/components/page-container/page-container.tsx b/packages/cashier/src/components/page-container/page-container.tsx
new file mode 100644
index 000000000000..30acb767827c
--- /dev/null
+++ b/packages/cashier/src/components/page-container/page-container.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { Loading, ThemedScrollbars } from '@deriv/components';
+import { observer, useStore } from '@deriv/stores';
+import CashierBreadcrumb from '../cashier-breadcrumb';
+import './page-container.scss';
+
+type TProps = {
+ hide_breadcrumb?: boolean;
+};
+
+const PageContainer: React.FC> = observer(({ hide_breadcrumb = false, children }) => {
+ const { client } = useStore();
+ const { is_authorize } = client;
+ const is_loading = !is_authorize;
+
+ return (
+
+ {is_loading && }
+ {!is_loading && (
+
+ {!hide_breadcrumb && }
+ {children}
+
+ )}
+
+ );
+});
+
+export default PageContainer;
diff --git a/packages/cashier/src/components/side-note-card/__test__/side-note-card.test.tsx b/packages/cashier/src/components/side-note-card/__test__/side-note-card.test.tsx
new file mode 100644
index 000000000000..4038bb0fd346
--- /dev/null
+++ b/packages/cashier/src/components/side-note-card/__test__/side-note-card.test.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { StoreProvider, mockStore } from '@deriv/stores';
+import { render, screen } from '@testing-library/react';
+import SideNoteCard from '../side-note-card';
+
+describe('SideNoteCard', () => {
+ test('should render the given title and description', async () => {
+ const props: React.ComponentProps = {
+ title: 'foo',
+ description: 'bar',
+ };
+ const mock = mockStore({});
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ expect(screen.getByText(props.title)).toBeInTheDocument();
+ expect(screen.getByText(props.description)).toBeInTheDocument();
+ });
+
+ test('should render the given children', async () => {
+ const props: React.ComponentProps = {
+ title: 'foo',
+ description: 'bar',
+ };
+ const mock = mockStore({});
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(
+
+ children
+ ,
+ { wrapper }
+ );
+
+ expect(screen.getByText(props.title)).toBeInTheDocument();
+ expect(screen.getByText(props.description)).toBeInTheDocument();
+ expect(screen.getByText('children')).toBeInTheDocument();
+ });
+});
diff --git a/packages/cashier/src/components/side-note-card/index.ts b/packages/cashier/src/components/side-note-card/index.ts
new file mode 100644
index 000000000000..84ea9c830519
--- /dev/null
+++ b/packages/cashier/src/components/side-note-card/index.ts
@@ -0,0 +1,3 @@
+import SideNoteCard from './side-note-card';
+
+export { SideNoteCard };
diff --git a/packages/cashier/src/components/side-note-card/side-note-card.scss b/packages/cashier/src/components/side-note-card/side-note-card.scss
new file mode 100644
index 000000000000..30b50a23d6e1
--- /dev/null
+++ b/packages/cashier/src/components/side-note-card/side-note-card.scss
@@ -0,0 +1,16 @@
+.side-note-card {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 1.6rem;
+ background-color: var(--general-section-1);
+ border-radius: $BORDER_RADIUS * 2;
+ padding: 1.6rem 2.4rem;
+
+ &__content {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 8px;
+ }
+}
diff --git a/packages/cashier/src/components/side-note-card/side-note-card.tsx b/packages/cashier/src/components/side-note-card/side-note-card.tsx
new file mode 100644
index 000000000000..a4d0b40a7742
--- /dev/null
+++ b/packages/cashier/src/components/side-note-card/side-note-card.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Text } from '@deriv/components';
+import { observer, useStore } from '@deriv/stores';
+import './side-note-card.scss';
+
+type TProps = {
+ title: string;
+ description: JSX.Element | string;
+ hide_paddings?: boolean; // Todo: remove this prop when page layout is refactored
+};
+
+const SideNoteCard: React.FC> = observer(
+ ({ title, description, hide_paddings = false, children }) => {
+ const { ui } = useStore();
+ const { is_mobile } = ui;
+
+ return (
+
+
+
+ {title}
+
+ {description}
+
+ {children}
+
+ );
+ }
+);
+
+export default SideNoteCard;
diff --git a/packages/cashier/src/containers/cashier/__tests__/cashier.spec.tsx b/packages/cashier/src/containers/cashier/__tests__/cashier.spec.tsx
index 2ca61ef54d9a..5bc2e97c102a 100644
--- a/packages/cashier/src/containers/cashier/__tests__/cashier.spec.tsx
+++ b/packages/cashier/src/containers/cashier/__tests__/cashier.spec.tsx
@@ -43,7 +43,6 @@ jest.mock('@deriv/shared', () => {
};
});
-jest.mock('Components/account-prompt-dialog', () => jest.fn(() => 'mockedAccountPromptDialog'));
jest.mock('Components/error-dialog', () => jest.fn(() => 'mockedErrorDialog'));
jest.mock('Pages/deposit', () => jest.fn(() => 'mockedDeposit'));
jest.mock('Pages/withdrawal', () => jest.fn(() => 'mockedWithdrawal'));
@@ -98,9 +97,6 @@ describe('', () => {
payment_agent: {
is_payment_agent_visible: false,
},
- account_prompt_dialog: {
- resetLastLocation: jest.fn(),
- },
},
},
});
@@ -150,9 +146,6 @@ describe('', () => {
payment_agent: {
is_payment_agent_visible: true,
},
- account_prompt_dialog: {
- resetLastLocation: jest.fn(),
- },
},
},
});
@@ -210,9 +203,6 @@ describe('', () => {
payment_agent: {
is_payment_agent_visible: true,
},
- account_prompt_dialog: {
- resetLastLocation: jest.fn(),
- },
},
},
});
@@ -262,9 +252,6 @@ describe('', () => {
// payment_agent: {
// is_payment_agent_visible: true,
// },
- // account_prompt_dialog: {
- // resetLastLocation: jest.fn(),
- // },
// },
// },
// });
@@ -317,9 +304,6 @@ describe('', () => {
payment_agent: {
is_payment_agent_visible: true,
},
- account_prompt_dialog: {
- resetLastLocation: jest.fn(),
- },
},
},
});
@@ -371,9 +355,6 @@ describe('', () => {
payment_agent: {
is_payment_agent_visible: true,
},
- account_prompt_dialog: {
- resetLastLocation: jest.fn(),
- },
},
},
});
@@ -424,9 +405,6 @@ describe('', () => {
payment_agent: {
is_payment_agent_visible: true,
},
- account_prompt_dialog: {
- resetLastLocation: jest.fn(),
- },
},
},
});
diff --git a/packages/cashier/src/containers/cashier/cashier.scss b/packages/cashier/src/containers/cashier/cashier.scss
index 512e37bea77b..7c16530a54d8 100644
--- a/packages/cashier/src/containers/cashier/cashier.scss
+++ b/packages/cashier/src/containers/cashier/cashier.scss
@@ -286,9 +286,6 @@
min-width: 25.6rem;
padding: 0.6rem 0.8rem;
}
- .acc-prompt-dialog {
- padding: 0 1rem;
- }
}
&-locked {
width: 100%;
diff --git a/packages/cashier/src/containers/cashier/cashier.tsx b/packages/cashier/src/containers/cashier/cashier.tsx
index c5eb722550d7..baad47f16897 100644
--- a/packages/cashier/src/containers/cashier/cashier.tsx
+++ b/packages/cashier/src/containers/cashier/cashier.tsx
@@ -19,13 +19,12 @@ import {
useP2PNotificationCount,
} from '@deriv/hooks';
import { getSelectedRoute, getStaticUrl, isMobile, routes, WS } from '@deriv/shared';
-import AccountPromptDialog from '../../components/account-prompt-dialog';
import ErrorDialog from '../../components/error-dialog';
import { TRoute } from '../../types';
import { localize } from '@deriv/translations';
import { observer, useStore } from '@deriv/stores';
import { useCashierStore } from '../../stores/useCashierStores';
-import { TStores } from '@deriv/stores/types';
+import type { TCoreStores } from '@deriv/stores/types';
import './cashier.scss';
type TCashierProps = RouteComponentProps & {
@@ -34,8 +33,8 @@ type TCashierProps = RouteComponentProps & {
onMount: (should_remount?: boolean) => void;
setAccountSwitchListener: () => void;
setTabIndex: (index: number) => void;
- routeBackInApp: TStores['common']['routeBackInApp'];
- toggleCashier: TStores['ui']['toggleCashier'];
+ routeBackInApp: TCoreStores['common']['routeBackInApp'];
+ toggleCashier: TCoreStores['ui']['toggleCashier'];
resetLastLocation: () => void;
};
@@ -51,7 +50,7 @@ type TCashierOptions = {
const Cashier = observer(({ history, location, routes: routes_config }: TCashierProps) => {
const { common, ui, client } = useStore();
- const { withdraw, general_store, transaction_history, payment_agent, account_prompt_dialog } = useCashierStore();
+ const { withdraw, general_store, transaction_history, payment_agent } = useCashierStore();
const { error } = withdraw;
const {
is_cashier_onboarding,
@@ -68,7 +67,6 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
isSuccess: is_payment_agent_transfer_visible_is_success,
} = usePaymentAgentTransferVisible();
const { is_payment_agent_visible } = payment_agent;
- const { resetLastLocation } = account_prompt_dialog;
const { is_from_derivgo } = common;
const { is_cashier_visible: is_visible, toggleCashier } = ui;
const { is_account_setting_loaded, is_logged_in, is_logging_in } = client;
@@ -86,9 +84,7 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
// we still need to populate the tabs shown on cashier
return () => {
toggleCashier();
- resetLastLocation();
};
- // eslint-disable-next-line react-hooks/exhaustive-deps
}, [toggleCashier]);
React.useEffect(() => {
@@ -170,7 +166,6 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
return (
-
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/__test__/cashier-onboarding-card.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/__test__/cashier-onboarding-card.test.tsx
new file mode 100644
index 000000000000..4aadbf5bd591
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/__test__/cashier-onboarding-card.test.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { mockStore, StoreProvider } from '@deriv/stores';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import CashierOnboardingCard from '../cashier-onboarding-card';
+
+describe('CashierOnboardingCard', () => {
+ test('should call the onClick callback when clicked', async () => {
+ const mock = mockStore({});
+ const props: React.ComponentProps = {
+ title: 'foo',
+ description: 'bar',
+ onClick: jest.fn(),
+ };
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const container = screen.getByTestId('dt_cashier_onboarding_card');
+
+ userEvent.click(container);
+
+ expect(props.onClick).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/cashier-onboarding-card.scss b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/cashier-onboarding-card.scss
new file mode 100644
index 000000000000..90715c318ea4
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/cashier-onboarding-card.scss
@@ -0,0 +1,29 @@
+.cashier-onboarding-card {
+ align-self: stretch;
+
+ &__content {
+ display: flex;
+ align-items: center;
+ gap: 1.2rem;
+ }
+
+ &__description {
+ flex: 1;
+ }
+
+ &__container {
+ display: flex;
+ flex-direction: column;
+ padding: 1.6rem;
+ border: 2px solid var(--border-normal-1);
+ border-radius: $BORDER_RADIUS * 2;
+ margin-top: 0.8rem;
+ cursor: pointer;
+ gap: 1.6rem;
+ transition: all 0.25s ease;
+
+ &:hover {
+ transform: scale(0.99);
+ }
+ }
+}
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/cashier-onboarding-card.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/cashier-onboarding-card.tsx
new file mode 100644
index 000000000000..08f8b0d2dbd4
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/cashier-onboarding-card.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { Icon, Text } from '@deriv/components';
+import { observer, useStore } from '@deriv/stores';
+import './cashier-onboarding-card.scss';
+
+type TProps = {
+ title: string;
+ description: string;
+ onClick?: VoidFunction;
+};
+
+const CashierOnboardingCard: React.FC> = observer(
+ ({ title, description, onClick, children }) => {
+ const { ui } = useStore();
+ const { is_dark_mode_on, is_mobile } = ui;
+
+ return (
+
+
+ {title}
+
+
+
+
+ {description}
+
+
+
+ {children}
+
+
+ );
+ }
+);
+
+export default CashierOnboardingCard;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/index.ts
new file mode 100644
index 000000000000..5271e2b80851
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-card/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingCard from './cashier-onboarding-card';
+
+export { CashierOnboardingCard };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/__test__/cashier-onboarding-crypto-card.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/__test__/cashier-onboarding-crypto-card.test.tsx
new file mode 100644
index 000000000000..68d0bb75a8fb
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/__test__/cashier-onboarding-crypto-card.test.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { mockStore } from '@deriv/stores';
+import { fireEvent, render, screen } from '@testing-library/react';
+import CashierProviders from '../../../../../cashier-providers';
+import CashierOnboardingCryptoCard from '../cashier-onboarding-crypto-card';
+
+describe('CashierOnboardingCryptoCard', () => {
+ test('should call the onClick callback when clicked', async () => {
+ const mock = mockStore({
+ client: {
+ is_crypto: () => false,
+ },
+ modules: {
+ cashier: {
+ general_store: {
+ setDepositTarget: jest.fn(),
+ },
+ },
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const container = screen.getByTestId('dt_cashier_onboarding_card');
+
+ fireEvent.click(container);
+
+ expect(mock.modules.cashier.general_store.setDepositTarget).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/cashier-onboarding-crypto-card.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/cashier-onboarding-crypto-card.tsx
new file mode 100644
index 000000000000..5b66ba9372f8
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/cashier-onboarding-crypto-card.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { useHasCryptoCurrency } from '@deriv/hooks';
+import { routes } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { localize } from '@deriv/translations';
+import { useCashierStore } from '../../../../stores/useCashierStores';
+import { CashierOnboardingCard } from '../cashier-onboarding-card';
+import { CashierOnboardingIconMarquee } from '../cashier-onboarding-icon-marquee';
+
+const icons: React.ComponentProps['icons'] = [
+ { light: 'IcCashierBitcoinLight', dark: 'IcCashierBitcoinDark' },
+ { light: 'IcCashierEthereumLight', dark: 'IcCashierEthereumDark' },
+ { light: 'IcCashierLiteCoinLight', dark: 'IcCashierLiteCoinDark' },
+ { light: 'IcCashierUsdCoinLight', dark: 'IcCashierUsdCoinDark' },
+ { light: 'IcCashierTetherLight', dark: 'IcCashierTetherDark' },
+];
+
+const CashierOnboardingCryptoCard: React.FC = observer(() => {
+ const { client, ui } = useStore();
+ const { general_store } = useCashierStore();
+ const { is_crypto } = client;
+ const { openRealAccountSignup, shouldNavigateAfterChooseCrypto } = ui;
+ const { setDepositTarget } = general_store;
+ const has_crypto_account = useHasCryptoCurrency();
+
+ const onClick = () => {
+ setDepositTarget(routes.cashier_deposit);
+ if (is_crypto() || has_crypto_account) {
+ openRealAccountSignup('choose');
+ shouldNavigateAfterChooseCrypto(routes.cashier_deposit);
+ } else {
+ openRealAccountSignup('add_crypto');
+ }
+ };
+
+ return (
+
+
+
+ );
+});
+
+export default CashierOnboardingCryptoCard;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/index.ts
new file mode 100644
index 000000000000..44573bcaa49a
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-crypto-card/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingCryptoCard from './cashier-onboarding-crypto-card';
+
+export { CashierOnboardingCryptoCard };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/__test__/cashier-onboarding-fiat-card.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/__test__/cashier-onboarding-fiat-card.test.tsx
new file mode 100644
index 000000000000..0a112c019cbe
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/__test__/cashier-onboarding-fiat-card.test.tsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import { mockStore } from '@deriv/stores';
+import { fireEvent, render, screen } from '@testing-library/react';
+import CashierProviders from '../../../../../cashier-providers';
+import CashierOnboardingFiatCard from '../cashier-onboarding-fiat-card';
+
+describe('CashierOnboardingFiatCard', () => {
+ test('should call the onClick callback when clicked', async () => {
+ const mock = mockStore({
+ client: {
+ is_crypto: () => false,
+ },
+ modules: {
+ cashier: {
+ general_store: {
+ setDepositTarget: jest.fn(),
+ setIsDeposit: jest.fn(),
+ },
+ },
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const container = screen.getByTestId('dt_cashier_onboarding_card');
+
+ fireEvent.click(container);
+
+ expect(mock.modules.cashier.general_store.setDepositTarget).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/cashier-onboarding-fiat-card.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/cashier-onboarding-fiat-card.tsx
new file mode 100644
index 000000000000..00405fae512e
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/cashier-onboarding-fiat-card.tsx
@@ -0,0 +1,63 @@
+import React, { useState } from 'react';
+import { useHasFiatCurrency } from '@deriv/hooks';
+import { routes } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { localize } from '@deriv/translations';
+import { useCashierStore } from '../../../../stores/useCashierStores';
+import { CashierOnboardingCard } from '../cashier-onboarding-card';
+import { CashierOnboardingIconMarquee } from '../cashier-onboarding-icon-marquee';
+import { SwitchToFiatAccountDialog } from '../switch-to-fiat-account-dialog';
+
+const icons: React.ComponentProps['icons'] = [
+ { light: 'IcWalletCreditDebitLight', dark: 'IcWalletCreditDebitDark' },
+ { light: 'IcCashierInstantBankTransferLight', dark: 'IcCashierInstantBankTransferDark' },
+ { light: 'IcCashierEwalletLight', dark: 'IcCashierEwalletDark' },
+ { light: 'IcCashierLocalPaymentMethodsLight', dark: 'IcCashierLocalPaymentMethodsDark' },
+];
+
+const CashierOnboardingFiatCard: React.FC = observer(() => {
+ const { client, ui } = useStore();
+ const { general_store } = useCashierStore();
+ const { is_crypto } = client;
+ const { openRealAccountSignup } = ui;
+ const { setDepositTarget, setIsDeposit } = general_store;
+ const has_fiat_currency = useHasFiatCurrency();
+ const can_switch_to_fiat_account = is_crypto() && has_fiat_currency;
+ const [is_dialog_visible, setIsDialogVisible] = useState(false);
+
+ const onClick = () => {
+ setDepositTarget(routes.cashier_deposit);
+
+ if (can_switch_to_fiat_account) {
+ setIsDialogVisible(true);
+ } else if (is_crypto()) {
+ openRealAccountSignup('add_fiat');
+ } else {
+ setIsDeposit(true);
+ }
+ };
+
+ const onSwitchDone = () => {
+ setIsDialogVisible(false);
+ setIsDeposit(true);
+ };
+
+ return (
+
+
+ {can_switch_to_fiat_account && (
+ setIsDialogVisible(false)}
+ onSwitchDone={onSwitchDone}
+ />
+ )}
+
+ );
+});
+
+export default CashierOnboardingFiatCard;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/index.ts
new file mode 100644
index 000000000000..acb3772f794f
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-fiat-card/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingFiatCard from './cashier-onboarding-fiat-card';
+
+export { CashierOnboardingFiatCard };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/__test__/cashier-onboarding-icon-marquee.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/__test__/cashier-onboarding-icon-marquee.test.tsx
new file mode 100644
index 000000000000..8a5d83c57ef1
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/__test__/cashier-onboarding-icon-marquee.test.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { mockStore, StoreProvider } from '@deriv/stores';
+import { render, screen } from '@testing-library/react';
+import CashierOnboardingIconMarquee from '../cashier-onboarding-icon-marquee';
+
+describe('CashierOnboardingIconMarquee', () => {
+ test('should render cashier onboarding icon marquee', async () => {
+ const mock = mockStore({});
+ const props: React.ComponentProps = {
+ icons: [{ light: 'light', dark: 'dark' }],
+ };
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const container = screen.getByTestId('dt_cashier_onboarding_icon-marquee');
+
+ expect(container).toBeInTheDocument();
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/cashier-onboarding-icon-marquee.scss b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/cashier-onboarding-icon-marquee.scss
new file mode 100644
index 000000000000..d1869b88e33c
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/cashier-onboarding-icon-marquee.scss
@@ -0,0 +1,4 @@
+.cashier-onboarding-icon-marquee {
+ display: flex;
+ gap: 0.8rem;
+}
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/cashier-onboarding-icon-marquee.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/cashier-onboarding-icon-marquee.tsx
new file mode 100644
index 000000000000..48095a7a28c2
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/cashier-onboarding-icon-marquee.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { Icon, NewsTicker } from '@deriv/components';
+import { observer, useStore } from '@deriv/stores';
+import './cashier-onboarding-icon-marquee.scss';
+
+type TIcon = {
+ dark: string;
+ light: string;
+};
+
+type TProps = {
+ icons: TIcon[];
+};
+
+const CashierOnboardingIconMarquee: React.FC = observer(({ icons }) => {
+ const { ui } = useStore();
+ const { is_dark_mode_on } = ui;
+
+ return (
+
+
+
+ {icons.map((icon, index) => (
+
+ ))}
+
+
+
+ );
+});
+
+export default CashierOnboardingIconMarquee;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/index.ts
new file mode 100644
index 000000000000..bf3c4dda41c2
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-icon-marquee/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingIconMarquee from './cashier-onboarding-icon-marquee';
+
+export { CashierOnboardingIconMarquee };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/__test__/cashier-onboarding-onramp-card.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/__test__/cashier-onboarding-onramp-card.test.tsx
new file mode 100644
index 000000000000..2914fdac29e5
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/__test__/cashier-onboarding-onramp-card.test.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { mockStore } from '@deriv/stores';
+import { fireEvent, render, screen } from '@testing-library/react';
+import CashierProviders from '../../../../../cashier-providers';
+import CashierOnboardingOnrampCard from '../cashier-onboarding-onramp-card';
+
+describe('CashierOnboardingOnrampCard', () => {
+ test('should call the onClick callback when clicked', async () => {
+ const mock = mockStore({
+ client: {
+ is_crypto: () => false,
+ },
+ modules: {
+ cashier: {
+ general_store: {
+ setDepositTarget: jest.fn(),
+ },
+ },
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const container = screen.getByTestId('dt_cashier_onboarding_card');
+
+ fireEvent.click(container);
+
+ expect(mock.modules.cashier.general_store.setDepositTarget).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/cashier-onboarding-onramp-card.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/cashier-onboarding-onramp-card.tsx
new file mode 100644
index 000000000000..563ca1791a1c
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/cashier-onboarding-onramp-card.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { useHasCryptoCurrency } from '@deriv/hooks';
+import { routes } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { localize } from '@deriv/translations';
+import { useCashierStore } from '../../../../stores/useCashierStores';
+import { CashierOnboardingCard } from '../cashier-onboarding-card';
+import { CashierOnboardingIconMarquee } from '../cashier-onboarding-icon-marquee';
+
+const icons: React.ComponentProps['icons'] = [
+ { light: 'IcCashierBanxaLight', dark: 'IcCashierBanxaDark' },
+];
+
+const CashierOnboardingOnrampCard: React.FC = observer(() => {
+ const { client, ui } = useStore();
+ const { general_store } = useCashierStore();
+ const { is_crypto } = client;
+ const { openRealAccountSignup, shouldNavigateAfterChooseCrypto } = ui;
+ const { setDepositTarget } = general_store;
+ const has_crypto_account = useHasCryptoCurrency();
+
+ const onClick = () => {
+ setDepositTarget(routes.cashier_onramp);
+ if (is_crypto() || has_crypto_account) {
+ openRealAccountSignup('choose');
+ shouldNavigateAfterChooseCrypto(routes.cashier_onramp);
+ } else {
+ openRealAccountSignup('add_crypto');
+ }
+ };
+
+ return (
+
+
+
+ );
+});
+
+export default CashierOnboardingOnrampCard;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/index.ts
new file mode 100644
index 000000000000..833c8dffdee8
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-onramp-card/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingOnrampCard from './cashier-onboarding-onramp-card';
+
+export { CashierOnboardingOnrampCard };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/__test__/cashier-onboarding-p2p-card.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/__test__/cashier-onboarding-p2p-card.test.tsx
new file mode 100644
index 000000000000..43083201222d
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/__test__/cashier-onboarding-p2p-card.test.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { mockStore } from '@deriv/stores';
+import { fireEvent, render, screen } from '@testing-library/react';
+import CashierProviders from '../../../../../cashier-providers';
+import CashierOnboardingP2PCard from '../cashier-onboarding-p2p-card';
+
+jest.mock('react-router', () => ({
+ ...jest.requireActual('react-router'),
+ useHistory: () => ({ push: jest.fn() }),
+}));
+
+jest.mock('@deriv/hooks', () => ({
+ ...jest.requireActual('@deriv/hooks'),
+ useHasUSDCurrency: () => true,
+ useIsP2PEnabled: () => ({ data: true }),
+}));
+
+describe('CashierOnboardingP2PCard', () => {
+ test('should call the onClick callback when clicked', async () => {
+ const mock = mockStore({
+ client: {
+ is_crypto: () => false,
+ },
+ modules: {
+ cashier: {
+ general_store: {
+ setDepositTarget: jest.fn(),
+ },
+ },
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const container = screen.getByTestId('dt_cashier_onboarding_card');
+
+ fireEvent.click(container);
+
+ expect(mock.modules.cashier.general_store.setDepositTarget).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/cashier-onboarding-p2p-card.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/cashier-onboarding-p2p-card.tsx
new file mode 100644
index 000000000000..9a51a46bb822
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/cashier-onboarding-p2p-card.tsx
@@ -0,0 +1,63 @@
+import React, { useState } from 'react';
+import { useHasFiatCurrency, useHasUSDCurrency, useIsP2PEnabled } from '@deriv/hooks';
+import { routes } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { localize } from '@deriv/translations';
+import { useHistory } from 'react-router';
+import { useCashierStore } from '../../../../stores/useCashierStores';
+import { CashierOnboardingCard } from '../cashier-onboarding-card';
+import { SwitchToFiatAccountDialog } from '../switch-to-fiat-account-dialog';
+
+const CashierOnboardingP2PCard: React.FC = observer(() => {
+ const { client, ui } = useStore();
+ const { general_store } = useCashierStore();
+ const { is_crypto } = client;
+ const { openRealAccountSignup } = ui;
+ const { setDepositTarget } = general_store;
+ const history = useHistory();
+ const { data: is_p2p_enabled } = useIsP2PEnabled();
+ const has_usd_currency = useHasUSDCurrency();
+ const has_fiat_currency = useHasFiatCurrency();
+ const should_show_p2p_card = is_p2p_enabled || has_usd_currency;
+ const can_switch_to_fiat_account = is_crypto() && has_fiat_currency;
+ const [is_dialog_visible, setIsDialogVisible] = useState(false);
+
+ const onClick = () => {
+ setDepositTarget(routes.cashier_p2p);
+
+ if (can_switch_to_fiat_account) {
+ setIsDialogVisible(true);
+ } else if (is_crypto()) {
+ openRealAccountSignup('add_fiat');
+ } else {
+ history.push(routes.cashier_p2p);
+ }
+ };
+
+ const onSwitchDone = () => {
+ setIsDialogVisible(false);
+ history.push(routes.cashier_p2p);
+ };
+
+ if (!should_show_p2p_card) return null;
+
+ return (
+
+ {can_switch_to_fiat_account && (
+ setIsDialogVisible(false)}
+ onSwitchDone={onSwitchDone}
+ />
+ )}
+
+ );
+});
+
+export default CashierOnboardingP2PCard;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/index.ts
new file mode 100644
index 000000000000..4a26e4ab3894
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-p2p-card/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingP2PCard from './cashier-onboarding-p2p-card';
+
+export { CashierOnboardingP2PCard };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/__test__/cashier-onboarding-payment-agent-card.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/__test__/cashier-onboarding-payment-agent-card.test.tsx
new file mode 100644
index 000000000000..1ba55a08934c
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/__test__/cashier-onboarding-payment-agent-card.test.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { mockStore } from '@deriv/stores';
+import { fireEvent, render, screen } from '@testing-library/react';
+import CashierProviders from '../../../../../cashier-providers';
+import CashierOnboardingPaymentAgentCard from '../cashier-onboarding-payment-agent-card';
+
+jest.mock('@deriv/hooks', () => ({
+ ...jest.requireActual('@deriv/hooks'),
+ usePaymentAgentList: () => ({ data: ['PA1', 'PA2'] }),
+}));
+
+describe('CashierOnboardingPaymentAgentCard', () => {
+ test('should call the onClick callback when clicked', async () => {
+ const mock = mockStore({
+ modules: {
+ cashier: {
+ general_store: {
+ setDepositTarget: jest.fn(),
+ setShouldShowAllAvailableCurrencies: jest.fn(),
+ },
+ },
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const container = screen.getByTestId('dt_cashier_onboarding_card');
+
+ fireEvent.click(container);
+
+ expect(mock.modules.cashier.general_store.setDepositTarget).toBeCalledTimes(1);
+ expect(mock.modules.cashier.general_store.setShouldShowAllAvailableCurrencies).toBeCalledTimes(1);
+ expect(mock.ui.openRealAccountSignup).toBeCalledTimes(1);
+ expect(mock.ui.shouldNavigateAfterChooseCrypto).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/cashier-onboarding-payment-agent-card.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/cashier-onboarding-payment-agent-card.tsx
new file mode 100644
index 000000000000..bb74642739d4
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/cashier-onboarding-payment-agent-card.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { usePaymentAgentList } from '@deriv/hooks';
+import { routes } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { localize } from '@deriv/translations';
+import { useCashierStore } from '../../../../stores/useCashierStores';
+import { CashierOnboardingCard } from '../cashier-onboarding-card';
+
+const CashierOnboardingPaymentAgentCard: React.FC = observer(() => {
+ const { ui } = useStore();
+ const { general_store } = useCashierStore();
+ const { openRealAccountSignup, shouldNavigateAfterChooseCrypto } = ui;
+ const { setDepositTarget, setShouldShowAllAvailableCurrencies } = general_store;
+ const { data: all_payment_agent_list } = usePaymentAgentList();
+ const is_payment_agent_visible_in_onboarding = Boolean(all_payment_agent_list?.length);
+
+ const onClick = () => {
+ setShouldShowAllAvailableCurrencies(true);
+ setDepositTarget(routes.cashier_pa);
+ openRealAccountSignup('choose');
+ shouldNavigateAfterChooseCrypto(routes.cashier_pa);
+ };
+
+ if (!is_payment_agent_visible_in_onboarding) return null;
+
+ return (
+
+ );
+});
+
+export default CashierOnboardingPaymentAgentCard;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/index.ts
new file mode 100644
index 000000000000..345e02d33f04
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-payment-agent-card/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingPaymentAgentCard from './cashier-onboarding-payment-agent-card';
+
+export { CashierOnboardingPaymentAgentCard };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/__test__/cashier-onboarding-side-notes.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/__test__/cashier-onboarding-side-notes.test.tsx
new file mode 100644
index 000000000000..70a9fd9e213b
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/__test__/cashier-onboarding-side-notes.test.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { mockStore } from '@deriv/stores';
+import { render, screen } from '@testing-library/react';
+import CashierProviders from '../../../../../cashier-providers';
+import CashierOnboardingSideNotes from '../cashier-onboarding-side-notes';
+
+describe('CashierOnboardingSideNotes', () => {
+ test('should render CashierOnboardingSideNoteFiat on mobile if is_crypto is false', async () => {
+ const setSideNotes = jest.fn();
+ const mock = mockStore({ ui: { is_mobile: true } });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ expect(screen.getByText(/If you want to change your account currency/i)).toBeInTheDocument();
+ });
+
+ test('should render CashierOnboardingSideNoteCrypto on mobile on mobile if is_crypto is true', async () => {
+ const setSideNotes = jest.fn();
+ const mock = mockStore({
+ ui: { is_mobile: true },
+ client: { is_crypto: () => true },
+ modules: {
+ cashier: {
+ general_store: {
+ setDepositTarget: jest.fn(),
+ },
+ },
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ expect(screen.getByText(/You can open another cryptocurrency account/i)).toBeInTheDocument();
+ });
+
+ test('should call setSideNotes on desktop', async () => {
+ const setSideNotes = jest.fn();
+ const mock = mockStore({});
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ expect(setSideNotes).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-note-crypto.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-note-crypto.tsx
new file mode 100644
index 000000000000..eef70e81168b
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-note-crypto.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { Icon, Text } from '@deriv/components';
+import { getCurrencyDisplayCode, routes } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { localize } from '@deriv/translations';
+import { SideNoteCard } from '../../../../components/side-note-card';
+import { useCashierStore } from '../../../../stores/useCashierStores';
+
+const CashierOnboardingSideNoteCrypto: React.FC = observer(() => {
+ const { client, ui } = useStore();
+ const { general_store } = useCashierStore();
+ const { currency, loginid } = client;
+ const { openRealAccountSignup, is_mobile } = ui;
+ const { setDepositTarget } = general_store;
+ const currency_code = getCurrencyDisplayCode(currency);
+
+ const onClick = () => {
+ setDepositTarget(routes.cashier_deposit);
+ openRealAccountSignup('add_crypto');
+ };
+
+ return (
+
+
+
+ {localize('Manage your accounts')}
+
+
+
+
+ );
+});
+
+export default CashierOnboardingSideNoteCrypto;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-note-fiat.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-note-fiat.tsx
new file mode 100644
index 000000000000..4b5d68af2d36
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-note-fiat.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { Text } from '@deriv/components';
+import { getCurrencyDisplayCode } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { Localize, localize } from '@deriv/translations';
+import { SideNoteCard } from '../../../../components/side-note-card';
+
+const CashierOnboardingSideNoteFiat: React.FC = observer(() => {
+ const { client, ui } = useStore();
+ const { currency, loginid, is_eu, is_low_risk } = client;
+ const { is_mobile } = ui;
+ const currency_code = getCurrencyDisplayCode(currency);
+ const regulation_text = is_eu ? 'EU' : 'non-EU';
+
+ return (
+ window.LC_API.open_chat_window()}
+ />,
+ ]}
+ />
+ }
+ />
+ );
+});
+
+export default CashierOnboardingSideNoteFiat;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-notes.scss b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-notes.scss
new file mode 100644
index 000000000000..32cdf8624d31
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-notes.scss
@@ -0,0 +1,15 @@
+.cashier-onboarding-side-notes {
+ &__link-container {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ }
+
+ &__link {
+ cursor: pointer;
+
+ &:hover {
+ text-decoration: underline var(--brand-red-coral);
+ }
+ }
+}
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-notes.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-notes.tsx
new file mode 100644
index 000000000000..0dee91a39ff7
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/cashier-onboarding-side-notes.tsx
@@ -0,0 +1,33 @@
+import React, { useEffect } from 'react';
+import { observer, useStore } from '@deriv/stores';
+import CashierOnboardingSideNoteCrypto from './cashier-onboarding-side-note-crypto';
+import CashierOnboardingSideNoteFiat from './cashier-onboarding-side-note-fiat';
+import './cashier-onboarding-side-notes.scss';
+
+type TProps = {
+ setSideNotes: React.Dispatch>;
+};
+
+const CashierOnboardingSideNotes: React.FC = observer(({ setSideNotes }) => {
+ const { client, ui } = useStore();
+ const { is_crypto } = client;
+ const { is_mobile } = ui;
+
+ useEffect(() => {
+ if (!is_mobile) {
+ if (is_crypto()) {
+ setSideNotes([]);
+ } else {
+ setSideNotes([]);
+ }
+ }
+ }, [setSideNotes, is_crypto, is_mobile]);
+
+ if (!is_mobile) return null;
+
+ if (is_crypto()) return ;
+
+ return ;
+});
+
+export default CashierOnboardingSideNotes;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/index.ts
new file mode 100644
index 000000000000..4a1b30cd0249
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-side-notes/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingSideNotes from './cashier-onboarding-side-notes';
+
+export { CashierOnboardingSideNotes };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/__test__/cashier-onboarding-title.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/__test__/cashier-onboarding-title.test.tsx
new file mode 100644
index 000000000000..13eda240baad
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/__test__/cashier-onboarding-title.test.tsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { mockStore, StoreProvider } from '@deriv/stores';
+import { render, screen } from '@testing-library/react';
+import CashierOnboardingTitle from '../cashier-onboarding-title';
+
+describe('CashierOnboardingTitle', () => {
+ test('should render cashier onboarding title', async () => {
+ const mock = mockStore({});
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const title = screen.queryByTestId('dt_cashier_onboarding_title');
+
+ expect(title).toBeInTheDocument();
+ });
+
+ test('should not render learn more link on desktop', async () => {
+ const mock = mockStore({});
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const learn_more = screen.queryByTestId('dt_cashier_onboarding_title_learn_more');
+
+ expect(learn_more).not.toBeInTheDocument();
+ });
+
+ test('should render cashier onboarding title with learn more link when on mobile', async () => {
+ const mock = mockStore({ ui: { is_mobile: true } });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const learn_more = screen.queryByTestId('dt_cashier_onboarding_title_learn_more');
+
+ expect(learn_more).toBeInTheDocument();
+ });
+
+ test('should not learn more link when on mobile and is from DerivGO', async () => {
+ const mock = mockStore({ ui: { is_mobile: true }, common: { is_from_derivgo: true } });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const learn_more = screen.queryByTestId('dt_cashier_onboarding_title_learn_more');
+
+ expect(learn_more).not.toBeInTheDocument();
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/cashier-onboarding-title.scss b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/cashier-onboarding-title.scss
new file mode 100644
index 000000000000..389d0d601201
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/cashier-onboarding-title.scss
@@ -0,0 +1,10 @@
+.cashier-onboarding-title {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1.6rem;
+
+ @include mobile {
+ gap: 2.4rem;
+ }
+}
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/cashier-onboarding-title.tsx b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/cashier-onboarding-title.tsx
new file mode 100644
index 000000000000..378f8728c56b
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/cashier-onboarding-title.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { Text } from '@deriv/components';
+import { getStaticUrl } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { localize } from '@deriv/translations';
+import './cashier-onboarding-title.scss';
+
+const CashierOnboardingTitle: React.FC = observer(() => {
+ const { ui, common } = useStore();
+ const { is_mobile } = ui;
+ const { is_from_derivgo } = common;
+ const should_show_learn_more = is_mobile && !is_from_derivgo;
+
+ return (
+
+
+ {localize('Choose a way to fund your account')}
+
+
+ {localize('Please note that some payment methods might not be available in your country.')}
+
+ {should_show_learn_more && (
+ window.open(getStaticUrl('/payment-methods'))}
+ size='xs'
+ color='red'
+ align='center'
+ >
+ {localize('Learn more about payment methods')}
+
+ )}
+
+ );
+});
+
+export default CashierOnboardingTitle;
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/index.ts
new file mode 100644
index 000000000000..460f66fc231b
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/cashier-onboarding-title/index.ts
@@ -0,0 +1,3 @@
+import CashierOnboardingTitle from './cashier-onboarding-title';
+
+export { CashierOnboardingTitle };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/index.ts
new file mode 100644
index 000000000000..18f3ac99b9e9
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/index.ts
@@ -0,0 +1,10 @@
+export * from './cashier-onboarding-card';
+export * from './cashier-onboarding-crypto-card';
+export * from './cashier-onboarding-fiat-card';
+export * from './cashier-onboarding-icon-marquee';
+export * from './cashier-onboarding-onramp-card';
+export * from './cashier-onboarding-p2p-card';
+export * from './cashier-onboarding-payment-agent-card';
+export * from './cashier-onboarding-side-notes';
+export * from './cashier-onboarding-title';
+export * from './switch-to-fiat-account-dialog';
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/__test__/switch-to-fiat-account-dialog.test.tsx b/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/__test__/switch-to-fiat-account-dialog.test.tsx
new file mode 100644
index 000000000000..b3036e67b745
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/__test__/switch-to-fiat-account-dialog.test.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { mockStore } from '@deriv/stores';
+import { fireEvent, render, screen, waitFor } from '@testing-library/react';
+import CashierProviders from '../../../../../cashier-providers';
+import SwitchToFiatAccountDialog from '../switch-to-fiat-account-dialog';
+
+describe('SwitchToFiatAccountDialog', () => {
+ test('should call the onSwitchDone callback when clicked on confirm button', async () => {
+ const mock = mockStore({
+ client: {
+ account_list: [
+ { title: 'BTC', is_virtual: false, loginid: 'CR123' },
+ { title: 'USD', is_virtual: false, loginid: 'CR123' },
+ ],
+ is_crypto: (currency: string) => currency === 'BTC',
+ },
+ });
+ const onSwitchDone = jest.fn();
+ const onCancel = jest.fn();
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+ render(, { wrapper });
+
+ const confirm = screen.getByText('Switch account');
+
+ fireEvent.click(confirm);
+
+ await waitFor(() => expect(onSwitchDone).toBeCalledTimes(1));
+ expect(onSwitchDone).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/index.ts b/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/index.ts
new file mode 100644
index 000000000000..e68b0ddad7af
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/index.ts
@@ -0,0 +1,3 @@
+import SwitchToFiatAccountDialog from './switch-to-fiat-account-dialog';
+
+export { SwitchToFiatAccountDialog };
diff --git a/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/switch-to-fiat-account-dialog.tsx b/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/switch-to-fiat-account-dialog.tsx
new file mode 100644
index 000000000000..e84b28dd2b09
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/components/switch-to-fiat-account-dialog/switch-to-fiat-account-dialog.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { Dialog } from '@deriv/components';
+import { useFiatAccountList } from '@deriv/hooks';
+import { observer, useStore } from '@deriv/stores';
+import { localize } from '@deriv/translations';
+
+type TProps = {
+ is_visible: boolean;
+ onCancel: VoidFunction;
+ onSwitchDone: VoidFunction;
+};
+
+const SwitchToFiatAccountDialog: React.FC = observer(({ is_visible = false, onCancel, onSwitchDone }) => {
+ const { client } = useStore();
+ const { switchAccount } = client;
+ const fiat_account_list = useFiatAccountList();
+ const fiat_account_loginid = fiat_account_list?.[0].loginid;
+ const fiat_account_currency = fiat_account_list?.[0].title;
+
+ const onConfirm = async () => {
+ await switchAccount(fiat_account_loginid);
+
+ onSwitchDone();
+ };
+
+ return (
+
+ );
+});
+
+export default SwitchToFiatAccountDialog;
diff --git a/packages/cashier/src/modules/cashier-onboarding/index.tsx b/packages/cashier/src/modules/cashier-onboarding/index.tsx
new file mode 100644
index 000000000000..69ea0a9dbf57
--- /dev/null
+++ b/packages/cashier/src/modules/cashier-onboarding/index.tsx
@@ -0,0 +1,59 @@
+import React, { useEffect } from 'react';
+import { useHasSetCurrency } from '@deriv/hooks';
+import { routes } from '@deriv/shared';
+import { observer, useStore } from '@deriv/stores';
+import { useHistory } from 'react-router';
+import { PageContainer } from '../../components/page-container';
+import { useCashierStore } from '../../stores/useCashierStores';
+import {
+ CashierOnboardingCryptoCard,
+ CashierOnboardingFiatCard,
+ CashierOnboardingOnrampCard,
+ CashierOnboardingP2PCard,
+ CashierOnboardingPaymentAgentCard,
+ CashierOnboardingSideNotes,
+ CashierOnboardingTitle,
+} from './components';
+
+type TProps = {
+ setSideNotes: React.Dispatch>;
+};
+
+const CashierOnboarding: React.FC = observer(({ setSideNotes }) => {
+ const history = useHistory();
+ const { client, ui } = useStore();
+ const { general_store } = useCashierStore();
+ const { setIsCashierOnboarding } = general_store;
+ const { toggleSetCurrencyModal } = ui;
+ const { can_change_fiat_currency, available_crypto_currencies, is_crypto } = client;
+ const is_fiat_user = !is_crypto() && !can_change_fiat_currency;
+ const is_crypto_user = is_crypto() && available_crypto_currencies.length > 0;
+ const should_show_side_notes = is_fiat_user || is_crypto_user;
+ const has_set_currency = useHasSetCurrency();
+
+ useEffect(() => {
+ setIsCashierOnboarding(true);
+
+ return () => {
+ setIsCashierOnboarding(false);
+ if (!has_set_currency && window.location.pathname.includes(routes.cashier)) {
+ history.push(routes.trade);
+ toggleSetCurrencyModal();
+ }
+ };
+ }, [has_set_currency, history, setIsCashierOnboarding, toggleSetCurrencyModal]);
+
+ return (
+
+
+
+
+
+
+
+ {should_show_side_notes && }
+
+ );
+});
+
+export default CashierOnboarding;
diff --git a/packages/cashier/src/modules/index.ts b/packages/cashier/src/modules/index.ts
new file mode 100644
index 000000000000..d44bb6bc53cf
--- /dev/null
+++ b/packages/cashier/src/modules/index.ts
@@ -0,0 +1 @@
+export { default as CashierOnboardingModule } from './cashier-onboarding';
diff --git a/packages/cashier/src/pages/deposit/__tests__/deposit.spec.tsx b/packages/cashier/src/pages/deposit/__tests__/deposit.spec.tsx
index 0040c833821f..e344fe62db7f 100644
--- a/packages/cashier/src/pages/deposit/__tests__/deposit.spec.tsx
+++ b/packages/cashier/src/pages/deposit/__tests__/deposit.spec.tsx
@@ -53,11 +53,6 @@ jest.mock('Components/cashier-container/real', () => {
return CashierContainerReal;
});
-jest.mock('Components/cashier-onboarding/cashier-onboarding', () => {
- const CashierOnboarding = () => CashierOnboarding
;
- return CashierOnboarding;
-});
-
jest.mock('../deposit-locked', () => {
const DepositLocked = () => DepositLocked
;
return DepositLocked;
@@ -484,50 +479,6 @@ describe('', () => {
expect(screen.getByText('Real')).toBeInTheDocument();
});
- it('should render component', () => {
- const mock_root_store = mockStore({
- client: {
- mt5_login_list: [
- {
- account_type: 'demo',
- sub_account_type: 'financial_stp',
- },
- ],
- currency: 'USD',
- can_change_fiat_currency: false,
- current_currency_type: 'fiat',
- is_switching: false,
- is_virtual: false,
- },
- modules: {
- cashier: {
- iframe: {},
- transaction_history: {
- is_crypto_transactions_visible: false,
- onMount: jest.fn(),
- },
- deposit: {
- error: { is_ask_uk_funds_protection: false, message: '', setErrorMessage: jest.fn() },
- onMountDeposit: jest.fn(),
- },
- general_store: {
- is_deposit: false,
- is_loading: false,
- setActiveTab: jest.fn(),
- setIsDeposit: jest.fn(),
- },
- },
- },
- traders_hub: { content_flag: ContentFlag.CR_DEMO },
- });
-
- render(, {
- wrapper: ({ children }) => {children},
- });
-
- expect(screen.getByText('CashierOnboarding')).toBeInTheDocument();
- });
-
it('should trigger "setSideNotes" callback', () => {
const mock_root_store = mockStore({
client: {
diff --git a/packages/cashier/src/pages/deposit/crypto-deposit/__tests__/crypto-deposit.spec.tsx b/packages/cashier/src/pages/deposit/crypto-deposit/__tests__/crypto-deposit.spec.tsx
index e7f8be0bcd07..e442d4b56d9c 100644
--- a/packages/cashier/src/pages/deposit/crypto-deposit/__tests__/crypto-deposit.spec.tsx
+++ b/packages/cashier/src/pages/deposit/crypto-deposit/__tests__/crypto-deposit.spec.tsx
@@ -32,10 +32,12 @@ jest.mock('@deriv/api', () => {
...jest.requireActual('@deriv/api'),
useFetch: jest.fn(() => ({
data: {
- currencies_config: {
- tUSDT: {
- minimum_deposit: 2,
- minimum_withdrawal: 4.54,
+ crypto_config: {
+ currencies_config: {
+ tUSDT: {
+ minimum_deposit: 2,
+ minimum_withdrawal: 4.54,
+ },
},
},
},
diff --git a/packages/cashier/src/pages/deposit/deposit.tsx b/packages/cashier/src/pages/deposit/deposit.tsx
index 6b44b6350f8e..b5c80c5c7b51 100644
--- a/packages/cashier/src/pages/deposit/deposit.tsx
+++ b/packages/cashier/src/pages/deposit/deposit.tsx
@@ -3,7 +3,6 @@ import { Loading } from '@deriv/components';
import { useCashierLocked, useDepositLocked, useIsSystemMaintenance } from '@deriv/hooks';
import { useStore, observer } from '@deriv/stores';
import { Real, Virtual } from '../../components/cashier-container';
-import { CashierOnboarding, CashierOnboardingSideNote } from '../../components/cashier-onboarding';
import CashierLocked from '../../components/cashier-locked';
import CryptoTransactionsHistory from '../../components/crypto-transactions-history';
import Error from '../../components/error';
@@ -14,6 +13,8 @@ import CryptoDeposit from './crypto-deposit';
import DepositLocked from './deposit-locked';
import SideNote from '../../components/side-note';
import { useCashierStore } from '../../stores/useCashierStores';
+import { CashierOnboardingModule } from '../../modules';
+import { CashierOnboardingSideNotes } from '../../modules/cashier-onboarding/components';
type TDeposit = {
setSideNotes: (notes: object | null) => void;
@@ -88,18 +89,11 @@ const Deposit = observer(({ setSideNotes }: TDeposit) => {
]);
}
}
- if (is_fiat_currency_banner_visible_for_MF_clients) {
- setSideNotes([
-
-
- ,
- ]);
- }
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currency, tab_index, crypto_transactions, crypto_transactions?.length, is_cashier_onboarding, iframe_height]);
- if ((is_switching || (is_loading && !iframe_url)) && !is_crypto_transactions_visible) {
+ if (!is_cashier_onboarding && (is_switching || (is_loading && !iframe_url)) && !is_crypto_transactions_visible) {
return ;
}
if (is_virtual) {
@@ -134,15 +128,13 @@ const Deposit = observer(({ setSideNotes }: TDeposit) => {
return (
<>
{is_fiat_currency_banner_visible_for_MF_clients && (
-
-
-
+
)}
>
);
}
- return ;
+ return ;
});
export default Deposit;
diff --git a/packages/cashier/src/stores/__tests__/account-prompt-dialog-store.spec.ts b/packages/cashier/src/stores/__tests__/account-prompt-dialog-store.spec.ts
deleted file mode 100644
index 2c51116cc907..000000000000
--- a/packages/cashier/src/stores/__tests__/account-prompt-dialog-store.spec.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { routes } from '@deriv/shared';
-import { mockStore } from '@deriv/stores';
-import AccountPromptDialogStore from '../account-prompt-dialog-store';
-import { TRootStore } from '../../types';
-
-describe('AccountPromptDialogStore', () => {
- let account_prompt_dialog_store: AccountPromptDialogStore;
- const root_store = mockStore({
- common: {
- routeTo: jest.fn(),
- },
- client: {
- accounts: {
- CR90000001: {
- is_virtual: 0,
- currency: 'USD',
- },
- CR90000002: {
- is_virtual: 0,
- currency: 'BTC',
- },
- },
- currency: 'BTC',
- switchAccount: jest.fn(),
- },
- modules: {
- cashier: {
- general_store: {
- setIsDeposit: jest.fn(),
- },
- },
- },
- });
-
- beforeEach(() => {
- account_prompt_dialog_store = new AccountPromptDialogStore(root_store as TRootStore);
- });
-
- it('should show the dialog', () => {
- account_prompt_dialog_store.shouldNavigateAfterPrompt(routes.cashier_deposit, 'deposit');
-
- expect(account_prompt_dialog_store.last_location).toBe(routes.cashier_deposit);
- expect(account_prompt_dialog_store.should_show).toBeTruthy();
- expect(account_prompt_dialog_store.current_location).toBe('deposit');
- });
-
- it('should reset last_location', () => {
- account_prompt_dialog_store.resetLastLocation();
-
- expect(account_prompt_dialog_store.last_location).toBeNull();
- });
-
- it('should reset is_confirmed', () => {
- account_prompt_dialog_store.resetIsConfirmed();
-
- expect(account_prompt_dialog_store.is_confirmed).toBeFalsy();
- });
-
- it('should hide the dialog then switch to fiat account if the client is on crypto account upon confirm', async () => {
- account_prompt_dialog_store.shouldNavigateAfterPrompt(routes.cashier_deposit, 'deposit');
- await account_prompt_dialog_store.onConfirm();
-
- expect(account_prompt_dialog_store.should_show).toBeFalsy();
- expect(account_prompt_dialog_store.is_confirmed).toBeTruthy();
- expect(account_prompt_dialog_store.root_store.client.switchAccount).toHaveBeenCalledWith('CR90000001');
- expect(account_prompt_dialog_store.root_store.modules.cashier.general_store.setIsDeposit).toHaveBeenCalledWith(
- true
- );
-
- account_prompt_dialog_store.continueRoute();
- expect(account_prompt_dialog_store.root_store.common.routeTo).toHaveBeenCalledWith(routes.cashier_deposit);
- });
-
- it('should hide the dialog then stay on page if the client is on fiat account upon confirm', async () => {
- account_prompt_dialog_store.root_store.client.currency = 'USD';
-
- account_prompt_dialog_store.shouldNavigateAfterPrompt(routes.cashier_deposit, 'deposit');
- await account_prompt_dialog_store.onConfirm();
-
- expect(account_prompt_dialog_store.should_show).toBeFalsy();
- expect(account_prompt_dialog_store.is_confirmed).toBeTruthy();
- expect(account_prompt_dialog_store.root_store.client.switchAccount).not.toHaveBeenCalled();
- });
-
- it('should hide the dialog on cancel', () => {
- account_prompt_dialog_store.onCancel();
-
- expect(account_prompt_dialog_store.should_show).toBeFalsy();
- });
-});
diff --git a/packages/cashier/src/stores/__tests__/general-store.spec.ts b/packages/cashier/src/stores/__tests__/general-store.spec.ts
index d08c1691e2bb..f40f4155b2e4 100644
--- a/packages/cashier/src/stores/__tests__/general-store.spec.ts
+++ b/packages/cashier/src/stores/__tests__/general-store.spec.ts
@@ -34,10 +34,6 @@ beforeEach(() => {
},
modules: {
cashier: {
- account_prompt_dialog: {
- last_location: null,
- resetIsConfirmed: jest.fn(),
- },
account_transfer: {
accounts_list: [],
container: 'account_transfer',
@@ -99,32 +95,6 @@ describe('GeneralStore', () => {
expect(general_store.is_crypto).toBeTruthy();
});
- it('should set has_set_currency equal to true if the client has real USD account', () => {
- general_store.setHasSetCurrency();
-
- expect(general_store.has_set_currency).toBeTruthy();
- });
-
- it('should set has_set_currency equal to false if the client has real account with account.title = "Real"', () => {
- general_store.root_store.client.account_list = [{ is_virtual: 1, title: 'Real' }];
- general_store.root_store.client.has_active_real_account = true;
- general_store.setHasSetCurrency();
-
- expect(general_store.has_set_currency).toBeFalsy();
- });
-
- it('should perform proper cashier onboarding mounting', async () => {
- general_store.has_set_currency = false;
- const spySetHasSetCurrency = jest.spyOn(general_store, 'setHasSetCurrency');
- const spySetIsCashierOnboarding = jest.spyOn(general_store, 'setIsCashierOnboarding');
- const { account_prompt_dialog } = general_store.root_store.modules.cashier;
- await general_store.onMountCashierOnboarding();
-
- expect(spySetHasSetCurrency).toHaveBeenCalledTimes(1);
- expect(spySetIsCashierOnboarding).toHaveBeenCalledWith(true);
- expect(account_prompt_dialog.resetIsConfirmed).toHaveBeenCalledTimes(1);
- });
-
it('should calculate proper percentage for account transfer container', () => {
general_store.root_store.modules.cashier.crypto_fiat_converter.converter_from_amount = '500';
general_store.root_store.modules.cashier.account_transfer.selected_from.balance = 10000;
@@ -169,12 +139,6 @@ describe('GeneralStore', () => {
expect(general_store.should_show_all_available_currencies).toBeTruthy();
});
- it('should change value of the variable is_cashier_onboarding', () => {
- general_store.setIsCashierOnboarding(true);
-
- expect(general_store.is_cashier_onboarding).toBeTruthy();
- });
-
it('should set deposit target', () => {
general_store.setDepositTarget('/cashier/payment-agent');
diff --git a/packages/cashier/src/stores/account-prompt-dialog-store.ts b/packages/cashier/src/stores/account-prompt-dialog-store.ts
deleted file mode 100644
index b18da9808383..000000000000
--- a/packages/cashier/src/stores/account-prompt-dialog-store.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import { observable, action, makeObservable } from 'mobx';
-import { isCryptocurrency } from '@deriv/shared';
-import { TRootStore } from '../types';
-
-export default class AccountPromptDialogStore {
- constructor(public root_store: TRootStore) {
- makeObservable(this, {
- should_show: observable,
- is_confirmed: observable,
- last_location: observable,
- current_location: observable,
- shouldNavigateAfterPrompt: action.bound,
- resetLastLocation: action.bound,
- resetIsConfirmed: action.bound,
- onConfirm: action.bound,
- onCancel: action.bound,
- continueRoute: action.bound,
- });
- }
-
- should_show = false;
- is_confirmed = false;
- last_location: string | null = null;
- current_location: string | null = null;
-
- shouldNavigateAfterPrompt(next_location: string, current_location: string) {
- if (!this.is_confirmed) {
- this.last_location = next_location;
- this.should_show = true;
- this.current_location = current_location;
- }
- }
-
- resetLastLocation() {
- this.last_location = null;
- }
-
- resetIsConfirmed() {
- this.is_confirmed = false;
- }
-
- async onConfirm() {
- const { client } = this.root_store;
-
- this.should_show = false;
- this.is_confirmed = true;
-
- const has_fiat_account = Object.values(client.accounts).some(
- acc_settings => !acc_settings.is_virtual && !isCryptocurrency(acc_settings.currency || '')
- );
- if (isCryptocurrency(client?.currency) && has_fiat_account) await this.doSwitch();
- }
-
- async doSwitch() {
- const { client, modules } = this.root_store;
- const { general_store } = modules.cashier;
-
- const non_crypto_account_loginid = Object.entries(client.accounts).reduce(
- (initial_value, [loginid, settings]) => {
- return !settings.is_virtual && !isCryptocurrency(settings.currency || '') && loginid.startsWith('CR')
- ? loginid
- : initial_value;
- },
- ''
- );
- await client.switchAccount(non_crypto_account_loginid);
-
- if (this.current_location === 'deposit') {
- general_store.setIsDeposit(true);
- }
- }
-
- onCancel() {
- this.should_show = false;
- }
-
- continueRoute() {
- if (this.is_confirmed && this.last_location) {
- this.root_store.common.routeTo(this.last_location);
- }
- }
-}
diff --git a/packages/cashier/src/stores/cashier-store.ts b/packages/cashier/src/stores/cashier-store.ts
index 988356a65784..babe286b5ea3 100644
--- a/packages/cashier/src/stores/cashier-store.ts
+++ b/packages/cashier/src/stores/cashier-store.ts
@@ -1,4 +1,3 @@
-import AccountPromptDialogStore from './account-prompt-dialog-store';
import AccountTransferStore from './account-transfer-store';
import CryptoFiatConverterStore from './crypto-fiat-converter-store';
import DepositStore from './deposit-store';
@@ -14,7 +13,6 @@ import WithdrawStore from './withdraw-store';
import type { TRootStore, TWebSocket } from '../types';
export default class CashierStore {
- account_prompt_dialog: AccountPromptDialogStore;
account_transfer: AccountTransferStore;
crypto_fiat_converter: CryptoFiatConverterStore;
deposit: DepositStore;
@@ -29,7 +27,6 @@ export default class CashierStore {
withdraw: WithdrawStore;
constructor(public root_store: TRootStore, public WS: TWebSocket) {
- this.account_prompt_dialog = new AccountPromptDialogStore(root_store);
this.account_transfer = new AccountTransferStore(WS, root_store);
this.crypto_fiat_converter = new CryptoFiatConverterStore(WS, root_store);
this.deposit = new DepositStore(WS, root_store);
diff --git a/packages/cashier/src/stores/general-store.ts b/packages/cashier/src/stores/general-store.ts
index d8b9bd7ef8b5..a48b341fc38b 100644
--- a/packages/cashier/src/stores/general-store.ts
+++ b/packages/cashier/src/stores/general-store.ts
@@ -1,4 +1,4 @@
-import { action, computed, observable, reaction, when, makeObservable } from 'mobx';
+import { action, computed, observable, reaction, makeObservable } from 'mobx';
import { isCryptocurrency, routes } from '@deriv/shared';
import Constants from 'Constants/constants';
import BaseStore from './base-store';
@@ -13,13 +13,11 @@ export default class GeneralStore extends BaseStore {
calculatePercentage: action.bound,
cashier_route_tab_index: observable,
deposit_target: observable,
- has_set_currency: observable,
init: action.bound,
is_cashier_onboarding: observable,
is_crypto: computed,
is_deposit: observable,
is_loading: observable,
- onMountCashierOnboarding: action.bound,
onMountCommon: action.bound,
onRemount: observable,
percentage: observable,
@@ -29,7 +27,6 @@ export default class GeneralStore extends BaseStore {
setActiveTab: action.bound,
setCashierTabIndex: action.bound,
setDepositTarget: action.bound,
- setHasSetCurrency: action.bound,
setIsCashierOnboarding: action.bound,
setIsDeposit: action.bound,
setLoading: action.bound,
@@ -39,13 +36,6 @@ export default class GeneralStore extends BaseStore {
should_show_all_available_currencies: observable,
});
- when(
- () => this.root_store.client.is_logged_in,
- () => {
- this.setHasSetCurrency();
- }
- );
-
reaction(
() => [
this.root_store.client.switched,
@@ -61,7 +51,6 @@ export default class GeneralStore extends BaseStore {
active_container: keyof typeof Constants.containers = Constants.containers.deposit;
cashier_route_tab_index = 0;
deposit_target = '';
- has_set_currency = false;
is_cashier_onboarding = true;
is_deposit = false;
is_loading = false;
@@ -81,24 +70,6 @@ export default class GeneralStore extends BaseStore {
return !!currency && isCryptocurrency(currency);
}
- setHasSetCurrency(): void {
- const { account_list, has_active_real_account } = this.root_store.client;
-
- this.has_set_currency =
- account_list.filter(account => !account.is_virtual).some(account => account.title !== 'Real') ||
- !has_active_real_account;
- }
-
- async onMountCashierOnboarding() {
- const { account_prompt_dialog } = this.root_store.modules.cashier;
-
- if (!this.has_set_currency) {
- this.setHasSetCurrency();
- }
- this.setIsCashierOnboarding(true);
- account_prompt_dialog.resetIsConfirmed();
- }
-
calculatePercentage(amount = this.root_store.modules.cashier.crypto_fiat_converter.converter_from_amount): void {
const { client, modules } = this.root_store;
const { account_transfer } = modules.cashier;
diff --git a/packages/core/src/App/Containers/SetAccountCurrencyModal/set-currency-modal.jsx b/packages/core/src/App/Containers/SetAccountCurrencyModal/set-currency-modal.jsx
index 636875d8de33..7fcf33702e8b 100644
--- a/packages/core/src/App/Containers/SetAccountCurrencyModal/set-currency-modal.jsx
+++ b/packages/core/src/App/Containers/SetAccountCurrencyModal/set-currency-modal.jsx
@@ -1,13 +1,18 @@
-import PropTypes from 'prop-types';
import React from 'react';
import { Button, Modal } from '@deriv/components';
import { useHasSetCurrency } from '@deriv/hooks';
import { localize } from '@deriv/translations';
-import { connect } from 'Stores/connect';
-
+import { observer, useStore } from '@deriv/stores';
import 'Sass/set-currency-modal.scss';
-const SetAccountCurrencyModal = ({ is_visible, is_virtual, setCurrency, toggleModal }) => {
+const SetAccountCurrencyModal = observer(() => {
+ const { client, ui } = useStore();
+ const { is_virtual } = client;
+ const {
+ is_set_currency_modal_visible: is_visible,
+ openRealAccountSignup: setCurrency,
+ toggleSetCurrencyModal: toggleModal,
+ } = ui;
const has_set_currency = useHasSetCurrency();
return (
@@ -49,18 +54,6 @@ const SetAccountCurrencyModal = ({ is_visible, is_virtual, setCurrency, toggleMo
);
-};
-
-SetAccountCurrencyModal.propTypes = {
- is_virtual: PropTypes.bool,
- is_visible: PropTypes.bool,
- setCurrency: PropTypes.func,
- toggleModal: PropTypes.func,
-};
+});
-export default connect(({ client, ui }) => ({
- is_virtual: client.is_virtual,
- is_visible: ui.is_set_currency_modal_visible,
- setCurrency: ui.openRealAccountSignup,
- toggleModal: ui.toggleSetCurrencyModal,
-}))(SetAccountCurrencyModal);
+export default SetAccountCurrencyModal;
diff --git a/packages/hooks/jest.config.js b/packages/hooks/jest.config.js
index f53d37480f70..207910d7e732 100644
--- a/packages/hooks/jest.config.js
+++ b/packages/hooks/jest.config.js
@@ -1 +1,5 @@
-module.exports = require('../../jest.config.base');
+const baseConfigForPackages = require('../../jest.config.base');
+
+module.exports = {
+ ...baseConfigForPackages,
+};
diff --git a/packages/hooks/src/__tests__/useCountdown.spec.tsx b/packages/hooks/src/__tests__/useCountdown.spec.tsx
index 90998c35f546..d7957d7aa15d 100644
--- a/packages/hooks/src/__tests__/useCountdown.spec.tsx
+++ b/packages/hooks/src/__tests__/useCountdown.spec.tsx
@@ -1,4 +1,4 @@
-import { renderHook, act } from '@testing-library/react-hooks';
+import { act, renderHook } from '@testing-library/react-hooks';
import useCountdown from '../useCountdown';
jest.setTimeout(30000);
diff --git a/packages/hooks/src/__tests__/useFiatAccountList.spec.tsx b/packages/hooks/src/__tests__/useFiatAccountList.spec.tsx
new file mode 100644
index 000000000000..e35bc2d7676e
--- /dev/null
+++ b/packages/hooks/src/__tests__/useFiatAccountList.spec.tsx
@@ -0,0 +1,55 @@
+import * as React from 'react';
+import { StoreProvider, mockStore } from '@deriv/stores';
+import { renderHook } from '@testing-library/react-hooks';
+import useFiatAccountList from '../useFiatAccountList';
+
+describe('useFiatAccountList', () => {
+ test('should return an empty list if client has no account', async () => {
+ const mock = mockStore({});
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ const { result } = renderHook(() => useFiatAccountList(), { wrapper });
+
+ expect(result.current).toStrictEqual([]);
+ });
+
+ test('should return an empty list if client has no fiat account', async () => {
+ const mock = mockStore({
+ client: {
+ account_list: [{ title: 'BTC', is_virtual: false, loginid: 'CR123' }],
+ is_crypto: (currency: string) => currency === 'BTC',
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ const { result } = renderHook(() => useFiatAccountList(), { wrapper });
+
+ expect(result.current).toStrictEqual([]);
+ });
+
+ test('should return list of fiat accounts if client any fiat account', async () => {
+ const mock = mockStore({
+ client: {
+ account_list: [
+ { title: 'BTC', is_virtual: false, loginid: 'CR123' },
+ { title: 'USD', is_virtual: false, loginid: 'CR123' },
+ ],
+ is_crypto: (currency: string) => currency === 'BTC',
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ const { result } = renderHook(() => useFiatAccountList(), { wrapper });
+
+ expect(result.current).toStrictEqual([{ title: 'USD', is_virtual: false, loginid: 'CR123' }]);
+ });
+});
diff --git a/packages/hooks/src/__tests__/useHasCryptoCurrency.spec.tsx b/packages/hooks/src/__tests__/useHasCryptoCurrency.spec.tsx
new file mode 100644
index 000000000000..91c2230b9a48
--- /dev/null
+++ b/packages/hooks/src/__tests__/useHasCryptoCurrency.spec.tsx
@@ -0,0 +1,69 @@
+import * as React from 'react';
+import { StoreProvider, mockStore } from '@deriv/stores';
+import { renderHook } from '@testing-library/react-hooks';
+import useHasCryptoCurrency from '../useHasCryptoCurrency';
+
+describe('useHasCryptoCurrency', () => {
+ test('should return false if client has no account', async () => {
+ const mock = mockStore({});
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ const { result } = renderHook(() => useHasCryptoCurrency(), { wrapper });
+
+ expect(result.current).toBe(false);
+ });
+
+ test('should return false if client has no crypto account', async () => {
+ const mock = mockStore({
+ client: {
+ account_list: [{ title: 'USD' }],
+ is_crypto: (currency: string) => currency === 'BTC',
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ const { result } = renderHook(() => useHasCryptoCurrency(), { wrapper });
+
+ expect(result.current).toBe(false);
+ });
+
+ test('should return true if client has crypto account', async () => {
+ const mock = mockStore({
+ client: {
+ account_list: [{ title: 'BTC' }],
+ is_crypto: (currency: string) => currency === 'BTC',
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ const { result } = renderHook(() => useHasCryptoCurrency(), { wrapper });
+
+ expect(result.current).toBe(true);
+ });
+
+ test('should return true if client has at least one crypto account', async () => {
+ const mock = mockStore({
+ client: {
+ account_list: [{ title: 'BTC' }, { title: 'USD' }],
+ is_crypto: (currency: string) => currency === 'BTC',
+ },
+ });
+
+ const wrapper = ({ children }: { children: JSX.Element }) => (
+ {children}
+ );
+
+ const { result } = renderHook(() => useHasCryptoCurrency(), { wrapper });
+
+ expect(result.current).toBe(true);
+ });
+});
diff --git a/packages/hooks/src/__tests__/useIsP2PEnabled.spec.tsx b/packages/hooks/src/__tests__/useIsP2PEnabled.spec.tsx
index 68ed68ea2796..861279dc30b0 100644
--- a/packages/hooks/src/__tests__/useIsP2PEnabled.spec.tsx
+++ b/packages/hooks/src/__tests__/useIsP2PEnabled.spec.tsx
@@ -16,7 +16,7 @@ describe('useIsP2PEnabled', () => {
const mock = mockStore({ client: { currency: 'AUD' } });
// @ts-expect-error need to come up with a way to mock the return type of useFetch
- mockUseFetch.mockReturnValue({ data: { p2p_config: { supported_currencies: ['usd'] } } });
+ mockUseFetch.mockReturnValue({ data: { website_status: { p2p_config: { supported_currencies: ['usd'] } } } });
const wrapper = ({ children }: { children: JSX.Element }) => (
@@ -38,7 +38,7 @@ describe('useIsP2PEnabled', () => {
});
// @ts-expect-error need to come up with a way to mock the return type of useFetch
- mockUseFetch.mockReturnValue({ data: { p2p_config: { supported_currencies: ['usd'] } } });
+ mockUseFetch.mockReturnValue({ data: { website_status: { p2p_config: { supported_currencies: ['usd'] } } } });
const wrapper = ({ children }: { children: JSX.Element }) => (
@@ -59,7 +59,7 @@ describe('useIsP2PEnabled', () => {
});
// @ts-expect-error need to come up with a way to mock the return type of useFetch
- mockUseFetch.mockReturnValue({ data: { p2p_config: { supported_currencies: ['usd'] } } });
+ mockUseFetch.mockReturnValue({ data: { website_status: { p2p_config: { supported_currencies: ['usd'] } } } });
const wrapper = ({ children }: { children: JSX.Element }) => (
@@ -83,7 +83,7 @@ describe('useIsP2PEnabled', () => {
});
// @ts-expect-error need to come up with a way to mock the return type of useFetch
- mockUseFetch.mockReturnValue({ data: { p2p_config: { supported_currencies: ['usd'] } } });
+ mockUseFetch.mockReturnValue({ data: { website_status: { p2p_config: { supported_currencies: ['usd'] } } } });
const wrapper = ({ children }: { children: JSX.Element }) => (
diff --git a/packages/hooks/src/__tests__/usePaymentAgentList.spec.tsx b/packages/hooks/src/__tests__/usePaymentAgentList.spec.tsx
index c842ca388693..9bd2ac0609d3 100644
--- a/packages/hooks/src/__tests__/usePaymentAgentList.spec.tsx
+++ b/packages/hooks/src/__tests__/usePaymentAgentList.spec.tsx
@@ -33,7 +33,7 @@ describe('usePaymentAgentList', () => {
const mock = mockStore({});
// @ts-expect-error need to come up with a way to mock the return type of useFetch
- mockUseFetch.mockReturnValue({ data: { list: [] } });
+ mockUseFetch.mockReturnValue({ data: { paymentagent_list: { list: [] } } });
const wrapper = ({ children }: { children: JSX.Element }) => (
@@ -50,7 +50,7 @@ describe('usePaymentAgentList', () => {
const mock = mockStore({});
// @ts-expect-error need to come up with a way to mock the return type of useFetch
- mockUseFetch.mockReturnValue({ data: { list: ['PAYMENT AGENT 1', 'PAYMENT AGENT 2'] } });
+ mockUseFetch.mockReturnValue({ data: { paymentagent_list: { list: ['PAYMENT AGENT 1', 'PAYMENT AGENT 2'] } } });
const wrapper = ({ children }: { children: JSX.Element }) => (
diff --git a/packages/hooks/src/__tests__/usePaymentAgentTransferVisible.spec.tsx b/packages/hooks/src/__tests__/usePaymentAgentTransferVisible.spec.tsx
index 00c2f347c20c..5e21191f69de 100644
--- a/packages/hooks/src/__tests__/usePaymentAgentTransferVisible.spec.tsx
+++ b/packages/hooks/src/__tests__/usePaymentAgentTransferVisible.spec.tsx
@@ -16,7 +16,7 @@ describe('usePaymentAgentTransferVisible', () => {
const mock = mockStore({});
// @ts-expect-error need to come up with a way to mock the return type of useFetch
- mockUseFetch.mockReturnValue({ data: { is_authenticated_payment_agent: 0 } });
+ mockUseFetch.mockReturnValue({ data: { get_settings: { is_authenticated_payment_agent: 0 } } });
const wrapper = ({ children }: { children: JSX.Element }) => (
@@ -33,7 +33,7 @@ describe('usePaymentAgentTransferVisible', () => {
const mock = mockStore({});
// @ts-expect-error need to come up with a way to mock the return type of useFetch
- mockUseFetch.mockReturnValue({ data: { is_authenticated_payment_agent: 1 } });
+ mockUseFetch.mockReturnValue({ data: { get_settings: { is_authenticated_payment_agent: 1 } } });
const wrapper = ({ children }: { children: JSX.Element }) => (
diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts
index d60373811cbb..d114601b9ad6 100644
--- a/packages/hooks/src/index.ts
+++ b/packages/hooks/src/index.ts
@@ -7,7 +7,9 @@ export { default as useCashierLocked } from './useCashierLocked';
export { default as useCountdown } from './useCountdown';
export { default as useDepositLocked } from './useDepositLocked';
export { default as useExchangeRate } from './useExchangeRate';
+export { default as useFiatAccountList } from './useFiatAccountList';
export { default as useHasActiveRealAccount } from './useHasActiveRealAccount';
+export { default as useHasCryptoCurrency } from './useHasCryptoCurrency';
export { default as useHasFiatCurrency } from './useHasFiatCurrency';
export { default as useHasMaltaInvestAccount } from './useHasMaltaInvestAccount';
export { default as useHasSetCurrency } from './useHasSetCurrency';
diff --git a/packages/hooks/src/useFiatAccountList.ts b/packages/hooks/src/useFiatAccountList.ts
new file mode 100644
index 000000000000..07f623e3c62d
--- /dev/null
+++ b/packages/hooks/src/useFiatAccountList.ts
@@ -0,0 +1,14 @@
+import { useStore } from '@deriv/stores';
+
+const useFiatAccountList = () => {
+ const { client } = useStore();
+ const { account_list, is_crypto } = client;
+
+ const fiat_account_list = account_list.filter(
+ account => !account.is_virtual && !is_crypto(account.title || '') && account.loginid?.startsWith('CR')
+ );
+
+ return fiat_account_list;
+};
+
+export default useFiatAccountList;
diff --git a/packages/hooks/src/useHasCryptoCurrency.ts b/packages/hooks/src/useHasCryptoCurrency.ts
new file mode 100644
index 000000000000..b7c824814cca
--- /dev/null
+++ b/packages/hooks/src/useHasCryptoCurrency.ts
@@ -0,0 +1,12 @@
+import { useStore } from '@deriv/stores';
+
+const useHasCryptoCurrency = () => {
+ const { client } = useStore();
+ const { account_list, is_crypto } = client;
+
+ const has_crypto_currency = account_list.some(account => is_crypto(account.title || 'USD'));
+
+ return has_crypto_currency;
+};
+
+export default useHasCryptoCurrency;
diff --git a/packages/hooks/src/useIsRealAccountNeededForCashier.ts b/packages/hooks/src/useIsRealAccountNeededForCashier.ts
index 493ec7d5f38f..468eddf6bdcf 100644
--- a/packages/hooks/src/useIsRealAccountNeededForCashier.ts
+++ b/packages/hooks/src/useIsRealAccountNeededForCashier.ts
@@ -1,6 +1,6 @@
import { useStore } from '@deriv/stores';
-import useHasSvgAccount from './useHasSvgAccount';
import useHasMaltaInvestAccount from './useHasMaltaInvestAccount';
+import useHasSvgAccount from './useHasSvgAccount';
const useIsRealAccountNeededForCashier = () => {
const { traders_hub } = useStore();
diff --git a/packages/stores/jest.config.js b/packages/stores/jest.config.js
index f53d37480f70..207910d7e732 100644
--- a/packages/stores/jest.config.js
+++ b/packages/stores/jest.config.js
@@ -1 +1,5 @@
-module.exports = require('../../jest.config.base');
+const baseConfigForPackages = require('../../jest.config.base');
+
+module.exports = {
+ ...baseConfigForPackages,
+};