diff --git a/packages/appstore/src/components/app.tsx b/packages/appstore/src/components/app.tsx index 100033c32965..1a9c0e436dfb 100644 --- a/packages/appstore/src/components/app.tsx +++ b/packages/appstore/src/components/app.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import { setWebsocket, routes } from '@deriv/shared'; import { StoreProvider, observer } from '@deriv/stores'; import CashierStoreProvider from '@deriv/cashier/src/cashier-providers'; +import CFDStoreProvider from '@deriv/cfd/src/cfd-providers'; import Routes from 'Components/routes/routes'; import { useStores, initContext } from 'Stores'; import { TRootStore } from 'Types'; @@ -21,20 +22,22 @@ const App = ({ passthrough: { WS, root_store } }: TAppProps) => { const { ui }: TRootStore = useStores(); return ( - - -
-
- -
-
-
+ + + +
+
+ +
+
+
+
); }; diff --git a/packages/appstore/src/components/modals/modal-manager.tsx b/packages/appstore/src/components/modals/modal-manager.tsx index f630834a6127..a80d73360f20 100644 --- a/packages/appstore/src/components/modals/modal-manager.tsx +++ b/packages/appstore/src/components/modals/modal-manager.tsx @@ -1,21 +1,19 @@ import React from 'react'; import { observer } from 'mobx-react-lite'; import { ResetTradingPasswordModal } from '@deriv/account'; -import { - JurisdictionModal, - CFDPasswordModal, - CFDDbviOnBoarding, - CFDResetPasswordModal, - CFDTopUpDemoModal, - MT5TradeModal, - CFDPasswordManagerModal, - CompareAccountsModal, -} from '@deriv/cfd'; import { TTradingPlatformAvailableAccount } from './account-type-modal/types'; import MT5AccountTypeModal from './account-type-modal'; import RegulatorsCompareModal from './regulators-compare-modal'; import { useStores } from 'Stores'; import CFDServerErrorDialog from '@deriv/cfd/src/Containers/cfd-server-error-dialog'; +import JurisdictionModal from '@deriv/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal'; +import CFDPasswordModal from '@deriv/cfd/src/Containers/cfd-password-modal'; +import CFDDbviOnBoarding from '@deriv/cfd/src/Containers/cfd-dbvi-onboarding'; +import CFDResetPasswordModal from '@deriv/cfd/src/Containers/cfd-reset-password-modal'; +import CFDTopUpDemoModal from '@deriv/cfd/src/Containers/cfd-top-up-demo-modal'; +import MT5TradeModal from '@deriv/cfd/src/Containers/mt5-trade-modal'; +import CFDPasswordManagerModal from '@deriv/cfd/src/Containers/cfd-password-manager-modal'; +import CompareAccountsModal from '@deriv/cfd/src/Containers/compare-accounts-modal'; import { TOpenAccountTransferMeta } from 'Types'; import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; import FailedVerificationModal from './failed-veriification-modal'; @@ -47,20 +45,10 @@ const ModalManager = () => { getRealSyntheticAccountsExistingData, getRealFinancialAccountsExistingData, getRealSwapfreeAccountsExistingData, - current_account, - dxtrade_companies, - derivez_companies, - mt5_companies, - topUpVirtual, } = modules.cfd; const { enableApp, disableApp, - is_top_up_virtual_open, - is_top_up_virtual_in_progress, - is_top_up_virtual_success, - closeTopUpModal, - closeSuccessTopUpModal, setShouldShowCooldownModal, is_reset_trading_password_modal_visible, setResetTradingPasswordModalOpen, @@ -71,9 +59,9 @@ const ModalManager = () => { is_visible: boolean; selected_login: string; selected_account: string; - selected_account_type?: string; - selected_account_group?: string; - selected_server?: string; + selected_account_type: string; + selected_account_group: '' | 'demo' | 'real'; + selected_server: string; }>({ is_visible: false, selected_login: '', @@ -86,7 +74,7 @@ const ModalManager = () => { const togglePasswordManagerModal = ( login?: string, title?: string, - group?: string, + group?: 'demo' | 'real' | '', type?: string, server?: string ) => { @@ -94,9 +82,9 @@ const ModalManager = () => { is_visible: !prev_state.is_visible, selected_login: typeof login === 'string' ? login : '', selected_account: typeof title === 'string' ? title : '', - selected_account_group: group, - selected_account_type: type, - selected_server: server, + selected_account_group: group || '', + selected_account_type: type || '', + selected_server: server || '', })); }; @@ -130,28 +118,13 @@ const ModalManager = () => { return ( - - - - + + + + - + { @@ -182,12 +153,13 @@ const ModalManager = () => { true), + isEligibleForMoreRealMt5: jest.fn(() => true), }, }; -jest.mock('Stores/connect.js', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => props => Component({ ...props, ...mock_connect_props }), -})); +const renderOptions = { + wrapper: ({ children }: { children: JSX.Element }) => ( + {children} + ), +}; jest.mock('@deriv/components', () => { const original_module = jest.requireActual('@deriv/components'); @@ -80,22 +95,15 @@ describe('CFDAccountCard', () => { button_label: 'Top up', commission_message: 'No commission', descriptor: '', - dxtrade_tokens: { - demo: '', - real: '', - }, - is_hovered: false, existing_accounts_data: [], has_banner: true, has_cfd_account_error: false, - is_eu: true, has_real_account: true, is_accounts_switcher_on: false, is_button_primary: true, is_disabled: false, is_logged_in: true, is_virtual: true, - onHover: jest.fn(), specs: {}, type: { category: '', type: '', platform: '' }, title: '', @@ -105,11 +113,6 @@ describe('CFDAccountCard', () => { onPasswordManager: jest.fn(), toggleAccountsDialog: jest.fn(), toggleShouldShowRealAccountsList: jest.fn(), - isEligibleForMoreDemoMt5Svg: jest.fn(() => true), - isEligibleForMoreRealMt5: jest.fn(() => true), - setMT5TradeAccount: jest.fn(), - trading_platform_available_accounts: [], - show_eu_related_content: false, }; }); @@ -126,7 +129,8 @@ describe('CFDAccountCard', () => { descriptor={synthetic_descriptor} title='Derived' existing_accounts_data={[mt5_acc]} - /> + />, + renderOptions ); expect(screen.getByText(/most popular/i)).toBeInTheDocument(); expect(screen.getByText(/demo/i)).toBeInTheDocument(); @@ -154,7 +158,8 @@ describe('CFDAccountCard', () => { descriptor={financial_descriptor} title='Financial' existing_accounts_data={[mt5_acc]} - /> + />, + renderOptions ); expect(screen.getByText(/demo/i)).toBeInTheDocument(); expect(screen.getByText(/IcMt5FinancialPlatform/i)).toBeInTheDocument(); @@ -183,8 +188,8 @@ describe('CFDAccountCard', () => { descriptor={synthetic_descriptor} title='Derived' existing_accounts_data={[mt5_acc]} - is_eu={false} - /> + />, + renderOptions ); expect(screen.getByText(/most popular/i)).toBeInTheDocument(); expect(screen.getByText(/IcMt5SyntheticPlatform/i)).toBeInTheDocument(); @@ -212,8 +217,8 @@ describe('CFDAccountCard', () => { descriptor={financial_descriptor} title='Financial' existing_accounts_data={[mt5_acc]} - is_eu={false} - /> + />, + renderOptions ); expect(screen.getByText(/svg/i)).toBeInTheDocument(); expect(screen.getByText(/IcMt5FinancialPlatform/i)).toBeInTheDocument(); @@ -242,7 +247,8 @@ describe('CFDAccountCard', () => { descriptor={financial_descriptor} title='Financial' existing_accounts_data={[mt5_acc]} - /> + />, + renderOptions ); fireEvent.click(screen.getByRole('button', { name: /top up/i })); expect(props.onClickFund).toHaveBeenCalledWith(mt5_acc); @@ -262,8 +268,8 @@ describe('CFDAccountCard', () => { title='Derived' existing_accounts_data={[]} platform='mt5' - is_eu={false} - /> + />, + renderOptions ); expect(screen.getByText(/add account/i)).toBeInTheDocument(); }); @@ -282,8 +288,8 @@ describe('CFDAccountCard', () => { title='Derived' existing_accounts_data={[]} platform='mt5' - is_eu={false} - /> + />, + renderOptions ); expect(screen.getByText(/add account/i)).toBeInTheDocument(); }); @@ -302,8 +308,8 @@ describe('CFDAccountCard', () => { title='Derived' existing_accounts_data={[]} platform='mt5' - is_eu={false} - /> + />, + renderOptions ); fireEvent.click(screen.getByText(/add account/i)); expect(props.onSelectAccount).toHaveBeenCalled(); @@ -324,7 +330,8 @@ describe('CFDAccountCard', () => { platform='mt5' button_label='Add real account' existing_accounts_data={null} - /> + />, + renderOptions ); fireEvent.click(screen.getByText(/add real account/i)); expect(props.onSelectAccount).toHaveBeenCalled(); @@ -345,7 +352,8 @@ describe('CFDAccountCard', () => { platform='mt5' button_label='Add demo account' existing_accounts_data={null} - /> + />, + renderOptions ); fireEvent.click(screen.getByText(/add demo account/i)); expect(props.onSelectAccount).toHaveBeenCalled(); @@ -365,7 +373,8 @@ describe('CFDAccountCard', () => { title='Derived' platform='mt5' existing_accounts_data={[mt5_labuan_acc]} - /> + />, + renderOptions ); expect(screen.getByText(/labuan/i)).toBeInTheDocument(); }); @@ -383,7 +392,8 @@ describe('CFDAccountCard', () => { descriptor={synthetic_descriptor} title='Derived' platform='dxtrade' - /> + />, + renderOptions ); fireEvent.click(screen.getByText(/fund transfer/i)); expect(props.onClickFund).toHaveBeenCalled(); @@ -403,7 +413,8 @@ describe('CFDAccountCard', () => { title='Derived' existing_accounts_data={[derivx_acc]} platform='dxtrade' - /> + />, + renderOptions ); expect(screen.getByText(/icedit/i)).toBeInTheDocument(); fireEvent.click(screen.getByText(/icedit/i)); @@ -424,8 +435,8 @@ describe('CFDAccountCard', () => { title='Derived' existing_accounts_data={[derivx_acc]} platform='dxtrade' - is_eu={false} - /> + />, + renderOptions ); expect(screen.getByText(/most popular/i)).toBeInTheDocument(); expect(screen.getByText(/demo/i)).toBeInTheDocument(); @@ -453,9 +464,9 @@ describe('CFDAccountCard', () => { title='Derived' existing_accounts_data={null} platform='dxtrade' - is_eu={false} is_logged_in={false} - /> + />, + renderOptions ); expect(screen.getByText(/most popular/i)).toBeInTheDocument(); expect( diff --git a/packages/cfd/src/Components/__tests__/cfd-demo-account-display.spec.js b/packages/cfd/src/Components/__tests__/cfd-demo-account-display.spec.js index df99caa38f01..ea294b0c7737 100644 --- a/packages/cfd/src/Components/__tests__/cfd-demo-account-display.spec.js +++ b/packages/cfd/src/Components/__tests__/cfd-demo-account-display.spec.js @@ -1,22 +1,24 @@ -import { fireEvent, render, screen, within } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { CFDDemoAccountDisplay } from '../cfd-demo-account-display'; +import CFDProviders from '../../cfd-providers'; +import { mockStore } from '@deriv/stores'; const mock_connect_props = { - dxtrade_tokens: { - demo: '', - real: '', + modules: { + cfd: { + dxtrade_tokens: { + demo: '', + real: '', + }, + setMT5TradeAccount: jest.fn(), + }, + }, + client: { + isEligibleForMoreDemoMt5Svg: () => true, }, - setMT5TradeAccount: jest.fn(), - isEligibleForMoreDemoMt5Svg: () => true, }; -jest.mock('Stores/connect.js', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => props => Component({ ...props, ...mock_connect_props }), -})); - describe('', () => { const TESTED_CASES = { EU: 'eu', @@ -125,7 +127,9 @@ describe('', () => { }; it('should render Derived & Financial cards with enabled buttons on Deriv MT5 when non-EU, non-IoM, is_logged_in=true & has_maltainvest_account=false', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DMT5); const add_demo_account_buttons = screen.getAllByRole('button', { name: /add demo account/i }); @@ -139,7 +143,9 @@ describe('', () => { }); it('should render Derived & Financial cards without "Add demo account" buttons on Deriv MT5 when is_logged_in=false & is_eu_country=false', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DMT5); expect(screen.queryAllByRole('button', { name: /add demo account/i }).length).toBe(0); @@ -148,7 +154,9 @@ describe('', () => { it('should render a CFDs card only with enabled "Add demo account" button on Deriv MT5 when EU, is_logged_in=true, standpoint.iom=true & has_maltainvest_account=false', () => { props.standpoint.iom = true; props.isSyntheticCardVisible = jest.fn(() => false); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.EU); const add_demo_account_button = screen.getByRole('button', { name: /add demo account/i }); @@ -160,14 +168,18 @@ describe('', () => { it('should render a CFDs card only without "Add demo account" button on Deriv MT5 when is_logged_in=false & is_eu_country=true (also when redirected from Deriv X platform)', () => { props.isSyntheticCardVisible = jest.fn(() => false); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.EU); expect(screen.queryAllByRole('button', { name: /add demo account/i }).length).toBe(0); }); it('should render Derived & Financial cards with enabled buttons on Deriv X when is_logged_in=true & is_eu=false', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DXTRADE); const add_demo_account_buttons = screen.getAllByRole('button', { name: /add demo account/i }); @@ -189,14 +201,18 @@ describe('', () => { }); it('should render Derived & Financial cards without "Add demo account" buttons on Deriv X when is_logged_in=false & is_eu_country=false', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DXTRADE); expect(screen.queryAllByRole('button', { name: /add demo account/i }).length).toBe(0); }); it('should disable all "Add demo account" buttons when has_cfd_account_error=true', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DMT5); const add_demo_account_buttons = screen.getAllByRole('button', { name: /add demo account/i }); @@ -205,7 +221,9 @@ describe('', () => { }); it('should show loading when is_loading=true', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByTestId('dt_barspinner')).toBeInTheDocument(); checkAccountCardsRendering(TESTED_CASES.LOADING); diff --git a/packages/cfd/src/Components/__tests__/cfd-poi.spec.js b/packages/cfd/src/Components/__tests__/cfd-poi.spec.js index 5bdde8ab24cc..5e52132653c7 100644 --- a/packages/cfd/src/Components/__tests__/cfd-poi.spec.js +++ b/packages/cfd/src/Components/__tests__/cfd-poi.spec.js @@ -1,13 +1,8 @@ -import { fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import React from 'react'; -import { isMobile } from '@deriv/shared'; import CFDPOI from '../cfd-poi'; - -jest.mock('Stores/connect', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => Component, -})); +import CFDProviders from '../../cfd-providers'; +import { mockStore } from '@deriv/stores'; jest.mock('@deriv/account', () => ({ ...jest.requireActual('@deriv/account'), @@ -16,57 +11,73 @@ jest.mock('@deriv/account', () => ({ describe('', () => { let props; + let mockRootStore; const ProofOfIdentityContainerForMt5 = 'ProofOfIdentityContainerForMt5'; beforeEach(() => { - props = { - account_status: { - authentication: { - attempts: { count: 0, history: {}, latest: null }, - identity: { - services: { idv: {}, manual: {}, onfido: {} }, - status: 'none', + mockRootStore = { + client: { + account_status: { + authentication: { + attempts: { count: 0, history: {}, latest: null }, + identity: { + services: { idv: {}, manual: {}, onfido: {} }, + status: 'none', + }, + document: { + status: 'none', + }, + needs_verification: [], + ownership: { requests: [], status: 'none' }, }, - document: { - status: 'none', + currency_config: { + USD: { + is_deposit_suspended: 0, + is_withdrawal_suspended: 0, + }, }, - needs_verification: [], - ownership: { requests: [], status: 'none' }, + prompt_client_to_authenticate: 0, + risk_classification: 'low', + status: [ + 'allow_document_upload', + 'crs_tin_information', + 'deposit_attempt', + 'financial_information_not_complete', + 'trading_experience_not_complete', + ], }, - currency_config: { - USD: { - is_deposit_suspended: 0, - is_withdrawal_suspended: 0, + is_switching: false, + is_virtual: false, + should_allow_authentication: true, + fetchResidenceList: jest.fn(), + }, + common: { + routeBackInApp: jest.fn(), + app_routing_history: [ + { + action: 'POP', + hash: '#real', + pathname: '/mt5', + search: '', + state: undefined, + }, + { + action: 'PUSH', + hash: '', + pathname: '/', + search: '', + state: undefined, }, - }, - prompt_client_to_authenticate: 0, - risk_classification: 'low', - status: [ - 'allow_document_upload', - 'crs_tin_information', - 'deposit_attempt', - 'financial_information_not_complete', - 'trading_experience_not_complete', ], }, + notifications: { + refreshNotifications: jest.fn(), + }, + }; + + props = { addNotificationByKey: jest.fn(), - app_routing_history: [ - { - action: 'POP', - hash: '#real', - pathname: '/mt5', - search: '', - state: undefined, - }, - { - action: 'PUSH', - hash: '', - pathname: '/', - search: '', - state: undefined, - }, - ], authentication_status: { document_status: '', identity_status: '', @@ -74,18 +85,11 @@ describe('', () => { form_error: undefined, height: 'auto', index: 1, - is_loading: false, - is_switching: false, - is_virtual: false, onCancel: jest.fn(), onSave: jest.fn(), onSubmit: jest.fn(), - fetchResidenceList: jest.fn(), - refreshNotifications: jest.fn(), removeNotificationByKey: jest.fn(), removeNotificationMessage: jest.fn(), - routeBackInApp: jest.fn(), - should_allow_authentication: true, value: { poi_state: 'unknown', }, @@ -93,7 +97,9 @@ describe('', () => { }); it('should render ProofOfIdentityContainerForMt5', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText(ProofOfIdentityContainerForMt5)).toBeInTheDocument(); }); }); diff --git a/packages/cfd/src/Components/__tests__/cfd-real-account-display.spec.js b/packages/cfd/src/Components/__tests__/cfd-real-account-display.spec.js index b59eda6699ea..f29524d32fe8 100644 --- a/packages/cfd/src/Components/__tests__/cfd-real-account-display.spec.js +++ b/packages/cfd/src/Components/__tests__/cfd-real-account-display.spec.js @@ -1,6 +1,8 @@ -import { fireEvent, render, screen, within } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { CFDRealAccountDisplay } from '../cfd-real-account-display'; +import { mockStore } from '@deriv/stores'; +import CFDProviders from '../../cfd-providers'; const mock_connect_props = { dxtrade_tokens: { @@ -11,12 +13,6 @@ const mock_connect_props = { isEligibleForMoreRealMt5: () => true, }; -jest.mock('Stores/connect.js', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => props => Component({ ...props, ...mock_connect_props }), -})); - describe('', () => { const TESTED_CASES = { EU: 'eu', @@ -213,7 +209,9 @@ describe('', () => { }; it('should render Derived & Financial cards with enabled buttons on Deriv MT5 when is_logged_in=true & is_eu=false', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DMT5); const add_real_account_buttons = screen.getAllByRole('button', { name: /add real account/i }); @@ -227,7 +225,9 @@ describe('', () => { }); it('should render Derived & Financial cards without "Add real account" buttons on Deriv MT5 when is_logged_in=false & is_eu_country=false', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DMT5); expect(screen.queryAllByRole('button', { name: /add real account/i }).length).toBe(0); @@ -241,7 +241,10 @@ describe('', () => { show_eu_related_content should_enable_add_button account_settings={account_settings_eu} - /> + />, + { + wrapper: ({ children }) => {children}, + } ); checkAccountCardsRendering(TESTED_CASES.EU); @@ -254,14 +257,18 @@ describe('', () => { it('should render a CFDs card only without "Add real account" button on Deriv MT5 when is_logged_in=false & is_eu_country=true (also when redirected from Deriv X platform)', () => { props.isSyntheticCardVisible = jest.fn(() => false); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.EU); expect(screen.queryAllByRole('button', { name: /add real account/i }).length).toBe(0); }); it('should render Derived & Financial cards with enabled buttons on Deriv X when is_logged_in=true & is_eu=false', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DXTRADE); const add_real_account_buttons = screen.getAllByRole('button', { name: /add real account/i }); @@ -283,14 +290,18 @@ describe('', () => { }); it('should render Derived & Financial cards without "Add real account" buttons on Deriv X when is_logged_in=false & is_eu_country=false', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DXTRADE); expect(screen.queryAllByRole('button', { name: /add real account/i }).length).toBe(0); }); it('should show "Switch to your real account", which opens Account Switcher, on Deriv X cards when has_real_account=true & is_virtual=true', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DMT5); expect(screen.queryAllByRole('button', { name: /add real account/i }).length).toBe(0); @@ -303,7 +314,9 @@ describe('', () => { }); it('should disable all "Add real account" buttons when has_cfd_account_error=true', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); checkAccountCardsRendering(TESTED_CASES.NON_EU_DMT5); const add_real_account_buttons = screen.getAllByRole('button', { name: /add real account/i }); diff --git a/packages/cfd/src/Components/cfd-account-card.tsx b/packages/cfd/src/Components/cfd-account-card.tsx index 588d9761547b..a2dd535b06b8 100644 --- a/packages/cfd/src/Components/cfd-account-card.tsx +++ b/packages/cfd/src/Components/cfd-account-card.tsx @@ -4,8 +4,6 @@ import { CSSTransition } from 'react-transition-group'; import { Icon, Money, Button, Text, DesktopWrapper, MobileWrapper, Popover } from '@deriv/components'; import { isMobile, mobileOSDetect, getCFDPlatformLabel, CFD_PLATFORMS, isDesktop } from '@deriv/shared'; import { localize, Localize } from '@deriv/translations'; -import { connect } from '../Stores/connect'; -import RootStore from '../Stores/index'; import { CFDAccountCopy } from './cfd-account-copy'; import { getDXTradeWebTerminalLink, @@ -22,6 +20,8 @@ import { TTradingPlatformAvailableAccount, } from './props.types'; import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; +import { useStore, observer } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; import { FormikValues } from 'formik'; const account_icons: { [key: string]: TAccountIconValues } = { @@ -173,631 +173,638 @@ const CFDAccountCardAction = ({ ); }; -const CFDAccountCardComponent = ({ - button_label, - commission_message, - descriptor, - dxtrade_tokens, - derivez_tokens, - existing_accounts_data, - has_banner, - has_cfd_account_error, - has_real_account, - is_accounts_switcher_on, - is_button_primary, - is_disabled, - is_logged_in, - is_virtual, - isEligibleForMoreDemoMt5Svg, - isEligibleForMoreRealMt5, - onClickFund, - onPasswordManager, - onSelectAccount, - platform, - setAccountType, - setJurisdictionSelectedShortcode, - setIsAcuityModalOpen, - setMT5TradeAccount, - specs, - title, - toggleAccountsDialog, - toggleCFDVerificationModal, - toggleMT5TradeModal, - toggleShouldShowRealAccountsList, - type, - updateAccountStatus, - real_account_creation_unlock_date, - setShouldShowCooldownModal, - setAppstorePlatform, - show_eu_related_content, -}: TCFDAccountCard) => { - const existing_data = existing_accounts_data?.length ? existing_accounts_data?.[0] : existing_accounts_data; +const CFDAccountCardComponent = observer( + ({ + button_label, + commission_message, + descriptor, + existing_accounts_data, + has_banner, + has_cfd_account_error, + has_real_account, + is_accounts_switcher_on, + is_button_primary, + is_disabled, + is_logged_in, + is_virtual, + onClickFund, + onPasswordManager, + onSelectAccount, + platform, + specs, + title, + toggleAccountsDialog, + toggleShouldShowRealAccountsList, + type, + }: TCFDAccountCard) => { + const { ui, common, traders_hub, client } = useStore(); - const should_show_extra_add_account_button = - is_logged_in && - !show_eu_related_content && - platform === CFD_PLATFORMS.MT5 && - (type.category === 'demo' - ? isEligibleForMoreDemoMt5Svg(type.type as TTradingPlatformAvailableAccount['market_type'] | 'synthetic') && - !!existing_data - : isEligibleForMoreRealMt5(type.type as TTradingPlatformAvailableAccount['market_type'] | 'synthetic') && - !!existing_data); + const { setIsAcuityModalOpen, setShouldShowCooldownModal } = ui; + const { setAppstorePlatform } = common; + const { show_eu_related_content } = traders_hub; + const { + updateAccountStatus, + isEligibleForMoreRealMt5, + isEligibleForMoreDemoMt5Svg, + real_account_creation_unlock_date, + } = client; - const platform_icon = show_eu_related_content && platform === CFD_PLATFORMS.MT5 ? 'cfd' : type.type; + const { + dxtrade_tokens, + derivez_tokens, + setAccountType, + setJurisdictionSelectedShortcode, + setMT5TradeAccount, + toggleCFDVerificationModal, + toggleMT5TradeModal, + } = useCfdStore(); - const icon: React.ReactNode | null = type.type ? ( - - ) : null; - const has_popular_banner: boolean = type.type === 'synthetic'; - const has_demo_banner: boolean = type.category === 'demo'; - const has_server_banner = - is_logged_in && - existing_data && - type.category === 'real' && - type.type === 'synthetic' && - (existing_data as DetailsOfEachMT5Loginid)?.server_info; + const existing_data = existing_accounts_data?.length ? existing_accounts_data?.[0] : existing_accounts_data; - const ref = React.useRef(null); - const wrapper_ref = React.useRef(null); - const button_ref = React.useRef(null); + const should_show_extra_add_account_button = + is_logged_in && + !show_eu_related_content && + platform === CFD_PLATFORMS.MT5 && + (type.category === 'demo' + ? isEligibleForMoreDemoMt5Svg( + type.type as TTradingPlatformAvailableAccount['market_type'] | 'synthetic' + ) && !!existing_data + : isEligibleForMoreRealMt5( + type.type as TTradingPlatformAvailableAccount['market_type'] | 'synthetic' + ) && !!existing_data); - const handleClickSwitchAccount: () => void = () => { - toggleShouldShowRealAccountsList?.(true); - toggleAccountsDialog?.(true); - }; + const platform_icon = show_eu_related_content && platform === CFD_PLATFORMS.MT5 ? 'cfd' : type.type; - const getDxtradeDownloadLink: () => string = () => { - const os = mobileOSDetect(); - if (os === 'iOS') { - return getPlatformDXTradeDownloadLink('ios'); - } - return getPlatformDXTradeDownloadLink('android'); - }; + const icon: React.ReactNode | null = type.type ? ( + + ) : null; + const has_popular_banner: boolean = type.type === 'synthetic'; + const has_demo_banner: boolean = type.category === 'demo'; + const has_server_banner = + is_logged_in && + existing_data && + type.category === 'real' && + type.type === 'synthetic' && + (existing_data as DetailsOfEachMT5Loginid)?.server_info; - const checkMultipleSvgAcc = () => { - const all_svg_acc: DetailsOfEachMT5Loginid[] = []; - existing_accounts_data?.map(acc => { - if (acc.landing_company_short === 'svg') { - if (all_svg_acc.length) { - all_svg_acc.forEach(svg_acc => { - if (svg_acc.server !== acc.server) all_svg_acc.push(acc); - return all_svg_acc; - }); - } else { - all_svg_acc.push(acc); - } - } - }); - return all_svg_acc; - }; + const ref = React.useRef(null); + const wrapper_ref = React.useRef(null); + const button_ref = React.useRef(null); + + const handleClickSwitchAccount: () => void = () => { + toggleShouldShowRealAccountsList?.(true); + toggleAccountsDialog?.(true); + }; - const getServerName: (value: DetailsOfEachMT5Loginid) => string = React.useCallback(server => { - if (server) { - const server_region = (server as DetailsOfEachMT5Loginid).server_info?.geolocation?.region; - if (server_region) { - return `${server_region} ${ - (server as DetailsOfEachMT5Loginid)?.server_info?.geolocation?.sequence === 1 - ? '' - : (server as DetailsOfEachMT5Loginid)?.server_info?.geolocation?.sequence - }`; + const getDxtradeDownloadLink: () => string = () => { + const os = mobileOSDetect(); + if (os === 'iOS') { + return getPlatformDXTradeDownloadLink('ios'); } - } - return ''; - }, []); + return getPlatformDXTradeDownloadLink('android'); + }; - const getBannerStatus = (account: DetailsOfEachMT5Loginid) => { - const { landing_company_short, status } = account; - if (landing_company_short && status && ['proof_failed', 'verification_pending'].includes(status)) { - const should_show_pending_button = status === 'verification_pending'; - return ( - - ); - } - return null; - }; + } else { + all_svg_acc.push(acc); + } + } + }); + return all_svg_acc; + }; - const is_web_terminal_unsupported = isMobile() && platform === CFD_PLATFORMS.DXTRADE; - const tbody_content = platform === CFD_PLATFORMS.DXTRADE && ( - - - -
{localize('Username')}
- - -
- -
- - -
- ); + const getServerName: (value: DetailsOfEachMT5Loginid) => string = React.useCallback(server => { + if (server) { + const server_region = (server as DetailsOfEachMT5Loginid).server_info?.geolocation?.region; + if (server_region) { + return `${server_region} ${ + (server as DetailsOfEachMT5Loginid)?.server_info?.geolocation?.sequence === 1 + ? '' + : (server as DetailsOfEachMT5Loginid)?.server_info?.geolocation?.sequence + }`; + } + } + return ''; + }, []); - return ( -
-
- {has_popular_banner && ( -
- -
- )} - {has_demo_banner && ( -
- -
- )} -
- {icon} -
- - {title} - - {platform === CFD_PLATFORMS.DXTRADE ? ( - (!existing_data || !is_logged_in) && ( -

{descriptor}

- ) + const getBannerStatus = (account: DetailsOfEachMT5Loginid) => { + const { landing_company_short, status } = account; + if (landing_company_short && status && ['proof_failed', 'verification_pending'].includes(status)) { + const should_show_pending_button = status === 'verification_pending'; + return ( + + ); + } + return null; + }; + + const is_web_terminal_unsupported = isMobile() && platform === CFD_PLATFORMS.DXTRADE; + const tbody_content = platform === CFD_PLATFORMS.DXTRADE && ( + + + +
{localize('Username')}
+ + +
+ +
+ + +
+ ); + + return ( +
+
+ {has_popular_banner && ( +
+ +
+ )} + {has_demo_banner && ( +
+ +
+ )} +
+ {icon} +
+ + {title} - )} - {(existing_data as TTradingPlatformAccounts)?.display_login && - is_logged_in && - platform === CFD_PLATFORMS.DXTRADE && ( - - {(existing_data as TTradingPlatformAccounts)?.display_login} + {platform === CFD_PLATFORMS.DXTRADE ? ( + (!existing_data || !is_logged_in) && ( +

{descriptor}

+ ) + ) : ( +

{descriptor}

+ )} + {existing_data?.display_balance && is_logged_in && platform === CFD_PLATFORMS.DXTRADE && ( + + )} -
-
- {platform === CFD_PLATFORMS.MT5 && isDesktop() && is_logged_in && ( -
- {type.type === 'financial' && ( - - )} + )} +
- )} - {existing_data &&
} + {platform === CFD_PLATFORMS.MT5 && isDesktop() && is_logged_in && ( +
+ {type.type === 'financial' && ( + + )} +
+ )} + {existing_data &&
} -
-
- {platform === CFD_PLATFORMS.DXTRADE && (!existing_data?.login || !is_logged_in) && ( -
- - - {typeof specs !== 'undefined' && - Object.keys(specs).map((spec_attribute, idx) => ( - - - - - ))} - -
-

- {specs[spec_attribute].key()} -

-
-

- {specs[spec_attribute].value()} -

-
-
- )} - {existing_data?.login && - is_logged_in && - platform === CFD_PLATFORMS.MT5 && - type.category === 'demo' && - existing_accounts_data?.length && - existing_accounts_data?.map((acc: FormikValues, index: number) => ( -
- {acc?.display_balance && is_logged_in && acc.landing_company_short === 'labuan' && ( -
- -
- )} - {(acc as TTradingPlatformAccounts)?.display_login && ( -
- - {(acc as TTradingPlatformAccounts)?.display_login} - -
- )} - {acc?.display_balance && is_logged_in && ( -
- - - -
- )} -
- {acc && is_logged_in && ( - - )} - {acc && is_logged_in && !is_web_terminal_unsupported && ( - + + {(acc as TTradingPlatformAccounts)?.display_login} + +
)} -
-
- ))} - {existing_data?.login && - is_logged_in && - platform === CFD_PLATFORMS.MT5 && - !existing_accounts_data?.length && - type.category === 'demo' && ( -
- {(existing_data as TTradingPlatformAccounts)?.display_login && ( -
- - {(existing_data as TTradingPlatformAccounts)?.display_login} - -
- )} - {existing_data?.display_balance && is_logged_in && ( -
- - - + {acc?.display_balance && is_logged_in && ( +
+ + + +
+ )} +
+ {acc && is_logged_in && ( + + )} + {acc && is_logged_in && !is_web_terminal_unsupported && ( + + )}
- )} -
- {existing_data && is_logged_in && ( - +
+ ))} + {existing_data?.login && + is_logged_in && + platform === CFD_PLATFORMS.MT5 && + !existing_accounts_data?.length && + type.category === 'demo' && ( +
+ {(existing_data as TTradingPlatformAccounts)?.display_login && ( +
+ + {(existing_data as TTradingPlatformAccounts)?.display_login} + +
)} - {existing_data && is_logged_in && !is_web_terminal_unsupported && ( - + {existing_data?.display_balance && is_logged_in && ( +
+ + + +
)} -
-
- )} - {existing_data?.login && - is_logged_in && - platform === CFD_PLATFORMS.MT5 && - type.category === 'real' && - existing_accounts_data?.map((acc: FormikValues, index: number) => ( -
- {existing_data?.display_balance && is_logged_in && !show_eu_related_content && ( -
- +
+ {existing_data && is_logged_in && ( + + )} + {existing_data && is_logged_in && !is_web_terminal_unsupported && ( + + )}
- )} - {(acc as TTradingPlatformAccounts)?.display_login && ( -
- - {(acc as TTradingPlatformAccounts)?.display_login} - -
- )} - {existing_data?.display_balance && is_logged_in && ( -
- - + )} + {existing_data?.login && + is_logged_in && + platform === CFD_PLATFORMS.MT5 && + type.category === 'real' && + existing_accounts_data?.map((acc: FormikValues, index: number) => ( +
+ {existing_data?.display_balance && is_logged_in && !show_eu_related_content && ( +
+ - - {checkMultipleSvgAcc()?.length > 1 && - acc.landing_company_short === 'svg' && ( - - {getServerName(acc)} - - )} -
- )} -
- {getBannerStatus(acc) ?? ( - - {existing_data && is_logged_in && ( - - )} - {existing_data && is_logged_in && !is_web_terminal_unsupported && ( - - )} - +
)} -
-
- ))} - {existing_data?.login && is_logged_in && platform === CFD_PLATFORMS.DXTRADE && ( - -
- - - {tbody_content} - - - - - -
-
- {localize('Password')} -
-
-
- + + {(acc as TTradingPlatformAccounts)?.display_login} + +
+ )} + {existing_data?.display_balance && is_logged_in && ( +
+ + + + {checkMultipleSvgAcc()?.length > 1 && + acc.landing_company_short === 'svg' && ( + + {getServerName(acc)} + + )} +
+ )} +
+ {getBannerStatus(acc) ?? ( + + {existing_data && is_logged_in && ( +
-
-
-
- )} - {((!existing_data && commission_message) || !is_logged_in) && - platform === CFD_PLATFORMS.DXTRADE && ( -
- - {commission_message} - + type='button' + secondary + > + + + )} + {existing_data && is_logged_in && !is_web_terminal_unsupported && ( + + )} + + )} +
+
+ ))} + {existing_data?.login && is_logged_in && platform === CFD_PLATFORMS.DXTRADE && ( + +
+ + + {tbody_content} + + + + + +
+
+ {localize('Password')} +
+
+
+ { + onPasswordManager( + existing_data?.login, + title, + type.category, + type.type, + (existing_data as DetailsOfEachMT5Loginid) + ?.server + ); + }} + /> +
+
+
+
+ )} + {((!existing_data && commission_message) || !is_logged_in) && + platform === CFD_PLATFORMS.DXTRADE && ( +
+ + {commission_message} + +
+ )} + {existing_data && is_logged_in && platform === CFD_PLATFORMS.DXTRADE && ( +
+
)} - {existing_data && is_logged_in && platform === CFD_PLATFORMS.DXTRADE && ( -
- -
- )} - {existing_data && - is_logged_in && - !is_web_terminal_unsupported && - platform === CFD_PLATFORMS.DXTRADE && ( + {existing_data && + is_logged_in && + !is_web_terminal_unsupported && + platform === CFD_PLATFORMS.DXTRADE && ( + + + + )} + {existing_data && is_logged_in && is_web_terminal_unsupported && ( - + )} - {existing_data && is_logged_in && is_web_terminal_unsupported && ( - - - - )} - {existing_data && - is_logged_in && - !is_web_terminal_unsupported && - platform === CFD_PLATFORMS.DERIVEZ && ( - - - + {existing_data && + is_logged_in && + !is_web_terminal_unsupported && + platform === CFD_PLATFORMS.DERIVEZ && ( + + + + )} + {!existing_data && is_logged_in && ( + )} - {!existing_data && is_logged_in && ( - - )} +
+ + {should_show_extra_add_account_button && ( + + + + )} +
- - {should_show_extra_add_account_button && ( - - - - )} - + + + + +
- - - - - -
- ); -}; + ); + } +); -const CFDAccountCard = connect(({ modules: { cfd }, client, ui, common, traders_hub }: RootStore) => ({ - dxtrade_tokens: cfd.dxtrade_tokens, - derivez_tokens: cfd.derivez_tokens, - isEligibleForMoreDemoMt5Svg: client.isEligibleForMoreDemoMt5Svg, - isEligibleForMoreRealMt5: client.isEligibleForMoreRealMt5, - setAccountType: cfd.setAccountType, - setJurisdictionSelectedShortcode: cfd.setJurisdictionSelectedShortcode, - setIsAcuityModalOpen: ui.setIsAcuityModalOpen, - setMT5TradeAccount: cfd.setMT5TradeAccount, - setAppstorePlatform: common.setAppstorePlatform, - toggleCFDVerificationModal: cfd.toggleCFDVerificationModal, - updateAccountStatus: client.updateAccountStatus, - show_eu_related_content: traders_hub.show_eu_related_content, -}))(CFDAccountCardComponent); +const CFDAccountCard = CFDAccountCardComponent; export { CFDAccountCard }; diff --git a/packages/cfd/src/Components/cfd-demo-account-display.tsx b/packages/cfd/src/Components/cfd-demo-account-display.tsx index 54e2cd0a35f9..63bfb008cf1a 100644 --- a/packages/cfd/src/Components/cfd-demo-account-display.tsx +++ b/packages/cfd/src/Components/cfd-demo-account-display.tsx @@ -39,11 +39,10 @@ type TCFDDemoAccountDisplayProps = { meta: TOpenAccountTransferMeta ) => void; platform: TCFDPlatform; - current_list: Record; + current_list: Record; openPasswordManager: (login?: string, title?: string, group?: string, type?: string, server?: string) => void; residence: string; landing_companies?: LandingCompany; - toggleMT5TradeModal: () => void; }; const CFDDemoAccountDisplay = ({ @@ -63,7 +62,6 @@ const CFDDemoAccountDisplay = ({ current_list, openPasswordManager, residence, - toggleMT5TradeModal, }: TCFDDemoAccountDisplayProps) => { const is_eu_user = (is_logged_in && is_eu) || (!is_logged_in && is_eu_country); @@ -151,7 +149,6 @@ const CFDDemoAccountDisplay = ({ descriptor={localize('Trade CFDs on our synthetics, baskets, and derived FX.')} specs={specifications[platform as keyof TSpecifications].real_synthetic_specs} has_banner - toggleMT5TradeModal={toggleMT5TradeModal} /> )} @@ -160,7 +157,6 @@ const CFDDemoAccountDisplay = ({ title={is_eu_user ? localize('CFDs') : localize('Financial')} is_disabled={has_cfd_account_error} is_logged_in={is_logged_in} - is_eu={is_eu_user} type={{ category: 'demo', type: 'financial', @@ -187,7 +183,6 @@ const CFDDemoAccountDisplay = ({ descriptor={general_messages.getFinancialAccountDescriptor(platform, is_eu_user)} specs={financial_specs} has_banner - toggleMT5TradeModal={toggleMT5TradeModal} /> )}
diff --git a/packages/cfd/src/Components/cfd-dxtrade-demo-account-display.tsx b/packages/cfd/src/Components/cfd-dxtrade-demo-account-display.tsx index 7dae1226dc28..c66d8d00d811 100644 --- a/packages/cfd/src/Components/cfd-dxtrade-demo-account-display.tsx +++ b/packages/cfd/src/Components/cfd-dxtrade-demo-account-display.tsx @@ -6,6 +6,7 @@ import Loading from '../templates/_common/components/loading'; import { LandingCompany, DetailsOfEachMT5Loginid } from '@deriv/api-types'; import { TTradingPlatformAccounts, TCFDPlatform } from './props.types'; import { TObjectCFDAccount } from '../Containers/cfd-dashboard'; +import { TCFDPasswordReset } from '../Containers/props.types'; type TStandPoint = { financial_company: string; @@ -39,7 +40,13 @@ type TCFDDemoAccountDisplayProps = { enabled: number; } >; - openPasswordManager: (login?: string, title?: string, group?: string, type?: string, server?: string) => void; + openPasswordManager: ( + login?: string, + title?: string, + group?: TCFDPasswordReset['account_group'], + type?: string, + server?: string + ) => void; landing_companies?: LandingCompany; }; diff --git a/packages/cfd/src/Components/cfd-mt5-demo-account-display.tsx b/packages/cfd/src/Components/cfd-mt5-demo-account-display.tsx index f9f2aca694ac..9ef58196c9eb 100644 --- a/packages/cfd/src/Components/cfd-mt5-demo-account-display.tsx +++ b/packages/cfd/src/Components/cfd-mt5-demo-account-display.tsx @@ -7,6 +7,7 @@ import Loading from '../templates/_common/components/loading'; import { LandingCompany, DetailsOfEachMT5Loginid } from '@deriv/api-types'; import { TTradingPlatformAccounts, TCFDPlatform } from './props.types'; import { TObjectCFDAccount } from '../Containers/cfd-dashboard'; +import { TCFDPasswordReset } from '../Containers/props.types'; type TStandPoint = { financial_company: string; @@ -40,8 +41,14 @@ type TCFDDemoAccountDisplayProps = { meta: TOpenAccountTransferMeta ) => void; platform: TCFDPlatform; - current_list: Record; - openPasswordManager: (login?: string, title?: string, group?: string, type?: string, server?: string) => void; + current_list: Record; + openPasswordManager: ( + login?: string, + title?: string, + group?: TCFDPasswordReset['account_group'], + type?: string, + server?: string + ) => void; residence: string; landing_companies?: LandingCompany; toggleMT5TradeModal: () => void; @@ -66,11 +73,8 @@ const CFDMT5DemoAccountDisplay = ({ current_list, openPasswordManager, residence, - toggleMT5TradeModal, show_eu_related_content, }: TCFDDemoAccountDisplayProps) => { - const is_eu_user = (is_logged_in && is_eu) || (!is_logged_in && is_eu_country); - const openAccountTransferList = (type: DetailsOfEachMT5Loginid['market_type']) => { return Object.keys(current_list).find((key: string) => key.startsWith(`${platform}.demo.${type}`)) || ''; }; @@ -146,7 +150,6 @@ const CFDMT5DemoAccountDisplay = ({ descriptor={localize('Trade CFDs on our synthetics, baskets, and derived FX.')} specs={specifications[platform as keyof TSpecifications].real_synthetic_specs} has_banner - toggleMT5TradeModal={toggleMT5TradeModal} /> )} @@ -155,7 +158,6 @@ const CFDMT5DemoAccountDisplay = ({ title={show_eu_related_content ? localize('CFDs') : localize('Financial')} is_disabled={has_cfd_account_error} is_logged_in={is_logged_in} - is_eu={is_eu_user} type={{ category: 'demo', type: 'financial', @@ -178,7 +180,6 @@ const CFDMT5DemoAccountDisplay = ({ )} specs={financial_specs} has_banner - toggleMT5TradeModal={toggleMT5TradeModal} /> )} @@ -214,7 +215,6 @@ const CFDMT5DemoAccountDisplay = ({ )} specs={specifications[platform as keyof TSpecifications].real_all_specs} has_banner - toggleMT5TradeModal={toggleMT5TradeModal} /> )}
diff --git a/packages/cfd/src/Components/cfd-personal-details-form.tsx b/packages/cfd/src/Components/cfd-personal-details-form.tsx index 2d26ffc609e0..da1d0300d765 100644 --- a/packages/cfd/src/Components/cfd-personal-details-form.tsx +++ b/packages/cfd/src/Components/cfd-personal-details-form.tsx @@ -19,14 +19,12 @@ import { } from '@deriv/components'; import { isDeepEqual, isDesktop, isMobile } from '@deriv/shared'; import { Localize, localize } from '@deriv/translations'; -import RootStore from '../Stores/index'; type TCFDPersonalDetailsFormProps = { changeable_fields?: string[]; form_error?: string; index: number; is_loading: boolean; - context: RootStore; landing_company: LandingCompany; onSubmit: TOnSubmit; residence_list: ResidenceList; @@ -35,7 +33,6 @@ type TCFDPersonalDetailsFormProps = { type TValidatePersonalDetailsParams = { values: TFormValues; - context: RootStore; residence_list: ResidenceList; account_opening_reason: TAccountOpeningReasonList; is_tin_required: boolean; @@ -126,7 +123,6 @@ export const InputField = ({ maxLength, name, optional = false, ...props }: TCFD const validatePersonalDetails = ({ values, - context, residence_list, account_opening_reason, is_tin_required, @@ -219,7 +215,6 @@ const CFDPersonalDetailsForm = ({ landing_company, residence_list, onSubmit, - context, value, index, form_error, @@ -241,7 +236,6 @@ const CFDPersonalDetailsForm = ({ validate={values => validatePersonalDetails({ values, - context, residence_list, account_opening_reason, is_tin_required, @@ -496,7 +490,6 @@ const CFDPersonalDetailsForm = ({ is_disabled={isSubmitting || !isValid || Object.keys(errors).length > 0} is_absolute={isMobile()} label={localize('Next')} - context={context} /> diff --git a/packages/cfd/src/Components/cfd-poi.tsx b/packages/cfd/src/Components/cfd-poi.tsx index 07f9a5880ba9..e37c56bf4c0b 100644 --- a/packages/cfd/src/Components/cfd-poi.tsx +++ b/packages/cfd/src/Components/cfd-poi.tsx @@ -1,8 +1,6 @@ import { ProofOfIdentityContainerForMt5 } from '@deriv/account'; -import { GetAccountStatus, GetSettings, ResidenceList } from '@deriv/api-types'; import React from 'react'; -import RootStore from '../Stores/index'; -import { connect } from '../Stores/connect'; +import { useStore, observer } from '@deriv/stores'; type TCFDValue = { poi_state: string; @@ -24,30 +22,54 @@ export type TCFDPOIProps = { index: number; onSubmit: (index: number, value: TCFDValue) => void; value: TCFDValue; - account_status?: GetAccountStatus; - addNotificationByKey: (key: string) => void; - fetchResidenceList?: () => void; - getChangeableFields: () => string[]; + addNotificationMessageByKey: (key: string) => void; height: string; - is_switching: boolean; - is_virtual: boolean; - is_high_risk: boolean; - is_withdrawal_lock: boolean; onSave: (index: number, values: TFormValues) => void; - refreshNotifications: () => void; removeNotificationByKey: (key: TCFDNotificationByKey) => void; removeNotificationMessage: (key: TCFDNotificationMessage) => void; - should_allow_authentication: boolean; - account_settings: GetSettings; - residence_list: ResidenceList; jurisdiction_selected_shortcode: string; - updateAccountStatus: () => void; }; -const CFDPOI = ({ index, onSave, onSubmit, height, ...props }: TCFDPOIProps) => { +const CFDPOI = observer(({ index, onSave, onSubmit, height, ...props }: TCFDPOIProps) => { + const { client, common, notifications } = useStore(); + + const { + account_status, + fetchResidenceList, + is_switching, + is_virtual, + is_high_risk, + is_withdrawal_lock, + should_allow_authentication, + account_settings, + residence_list, + getChangeableFields, + updateAccountStatus, + } = client; + const { routeBackInApp, app_routing_history } = common; + const { refreshNotifications } = notifications; + + const poi_props = { + account_status, + fetchResidenceList, + is_switching, + is_virtual, + is_high_risk, + is_withdrawal_lock, + should_allow_authentication, + account_settings, + residence_list, + routeBackInApp, + app_routing_history, + refreshNotifications, + getChangeableFields, + updateAccountStatus, + ...props, + }; + const [poi_state, setPOIState] = React.useState('none'); - const citizen = props.account_settings?.citizen || props.account_settings?.country_code; - const citizen_data = props.residence_list?.find(item => item.value === citizen); + const citizen = account_settings?.citizen || account_settings?.country_code; + const citizen_data = residence_list?.find(item => item.value === citizen); const onStateChange = (status: string) => { setPOIState(status); @@ -56,28 +78,13 @@ const CFDPOI = ({ index, onSave, onSubmit, height, ...props }: TCFDPOIProps) => }; return ( onStateChange(status)} citizen_data={citizen_data} /> ); -}; +}); -export default connect(({ client, common, notifications }: RootStore) => ({ - account_status: client.account_status, - app_routing_history: common.app_routing_history, - fetchResidenceList: client.fetchResidenceList, - is_switching: client.is_switching, - is_virtual: client.is_virtual, - is_high_risk: client.is_high_risk, - is_withdrawal_lock: client.is_withdrawal_lock, - refreshNotifications: notifications.refreshNotifications, - routeBackInApp: common.routeBackInApp, - should_allow_authentication: client.should_allow_authentication, - account_settings: client.account_settings, - residence_list: client.residence_list, - getChangeableFields: client.getChangeableFields, - updateAccountStatus: client.updateAccountStatus, -}))(CFDPOI); +export default CFDPOI; diff --git a/packages/cfd/src/Components/cfd-real-account-display.tsx b/packages/cfd/src/Components/cfd-real-account-display.tsx index 2a3b887abeed..c755014a34c9 100644 --- a/packages/cfd/src/Components/cfd-real-account-display.tsx +++ b/packages/cfd/src/Components/cfd-real-account-display.tsx @@ -9,6 +9,7 @@ import { general_messages } from '../Constants/cfd-shared-strings'; import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; import { TTradingPlatformAccounts, TCFDPlatform } from './props.types'; import { TObjectCFDAccount } from '../Containers/cfd-dashboard'; +import { TCFDPasswordReset } from '../Containers/props.types'; type TStandPoint = { financial_company: string; @@ -54,15 +55,19 @@ type TCFDRealAccountDisplayProps = { ) => boolean; // TODO: update this type (DetailsOfEachMT5Loginid) when BE changed the schema current_list: Record; - openPasswordManager: (login?: string, title?: string, group?: string, type?: string, server?: string) => void; + openPasswordManager: ( + login?: string, + title?: string, + group?: TCFDPasswordReset['account_group'], + type?: string, + server?: string + ) => void; toggleAccountsDialog: (is_accounts_switcher_on?: boolean) => void; - toggleMT5TradeModal: (is_accounts_switcher_on?: boolean) => void; toggleShouldShowRealAccountsList: (is_should_show_real_acc_list?: boolean) => void; residence: string; account_status?: object; openDerivRealAccountNeededModal: () => void; should_enable_add_button?: boolean; - setIsAcuityModalOpen: (value: boolean) => void; real_account_creation_unlock_date: string; setShouldShowCooldownModal: (value: boolean) => void; show_eu_related_content: boolean; @@ -89,18 +94,12 @@ const CFDRealAccountDisplay = ({ standpoint, is_logged_in, toggleAccountsDialog, - toggleMT5TradeModal, toggleShouldShowRealAccountsList, residence, openDerivRealAccountNeededModal, should_enable_add_button, - setIsAcuityModalOpen, - real_account_creation_unlock_date, - setShouldShowCooldownModal, show_eu_related_content, }: TCFDRealAccountDisplayProps) => { - const is_eu_user = (is_logged_in && is_eu) || (!is_logged_in && is_eu_country); - const financial_specs = React.useMemo(() => { const should_show_eu = (is_logged_in && is_eu) || (!is_logged_in && is_eu_country); const is_australian = residence === 'au'; @@ -213,7 +212,6 @@ const CFDRealAccountDisplay = ({ is_virtual={is_virtual} toggleShouldShowRealAccountsList={toggleShouldShowRealAccountsList} toggleAccountsDialog={toggleAccountsDialog} - toggleMT5TradeModal={toggleMT5TradeModal} /> ); @@ -237,15 +235,10 @@ const CFDRealAccountDisplay = ({ descriptor={general_messages.getFinancialAccountDescriptor(platform, show_eu_related_content)} specs={financial_specs} is_accounts_switcher_on={is_accounts_switcher_on} - is_eu={is_eu_user} is_logged_in={is_logged_in} is_virtual={is_virtual} toggleShouldShowRealAccountsList={toggleShouldShowRealAccountsList} toggleAccountsDialog={toggleAccountsDialog} - toggleMT5TradeModal={toggleMT5TradeModal} - setIsAcuityModalOpen={setIsAcuityModalOpen} - real_account_creation_unlock_date={real_account_creation_unlock_date} - setShouldShowCooldownModal={setShouldShowCooldownModal} /> ); @@ -259,7 +252,6 @@ const CFDRealAccountDisplay = ({ has_real_account={has_real_account} is_accounts_switcher_on={is_accounts_switcher_on} is_disabled={has_cfd_account_error || standpoint.malta} - is_eu={is_eu_user} is_logged_in={is_logged_in} is_virtual={is_virtual} key='cfd' diff --git a/packages/cfd/src/Components/props.types.ts b/packages/cfd/src/Components/props.types.ts index 5592f22479fd..c7d89dcfbc42 100644 --- a/packages/cfd/src/Components/props.types.ts +++ b/packages/cfd/src/Components/props.types.ts @@ -1,8 +1,9 @@ import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; +import { TCFDPasswordReset } from '../Containers/props.types'; export type TCFDPlatform = 'dxtrade' | 'mt5'; -export type TCFDsPlatformType = 'dxtrade' | 'derivez' | 'ctrader'; +export type TCFDsPlatformType = 'dxtrade' | 'derivez' | 'mt5' | 'ctrader' | ''; export type TCFDAccountCopy = { text: string | undefined; @@ -27,7 +28,7 @@ export type TPasswordBoxProps = { }; export type TType = { - category: string; + category: TCFDPasswordReset['account_group']; type: string; platform: string; }; @@ -157,21 +158,8 @@ export type TCFDAccountCard = { button_label?: string | JSX.Element; commission_message: string; descriptor: string; - dxtrade_tokens: { - demo: string; - real: string; - }; - derivez_tokens: { - demo: string; - real: string; - }; + existing_accounts_data?: TExistingData | null; is_hovered?: boolean; - isEligibleForMoreDemoMt5Svg: ( - market_type: TTradingPlatformAvailableAccount['market_type'] | 'synthetic' - ) => boolean; - isEligibleForMoreRealMt5: (market_type: TTradingPlatformAvailableAccount['market_type'] | 'synthetic') => boolean; - existing_accounts_data?: TExistingData; - trading_platform_available_accounts: TTradingPlatformAvailableAccount[]; has_banner?: boolean; has_cfd_account_error?: boolean; has_real_account?: boolean; @@ -180,8 +168,6 @@ export type TCFDAccountCard = { is_disabled: boolean; is_logged_in: boolean; is_virtual?: boolean; - is_eu?: boolean; - onHover?: (value: string | undefined) => void; platform: string; specs?: { [key: string]: { key: () => string; value: () => string } }; title: string; @@ -191,23 +177,12 @@ export type TCFDAccountCard = { onPasswordManager: ( arg1: string | undefined, arg2: string, - arg3: string, + group: TCFDPasswordReset['account_group'], arg4: string, arg5: string | undefined ) => void; toggleAccountsDialog?: (arg?: boolean) => void; - toggleMT5TradeModal: (arg?: boolean) => void; toggleShouldShowRealAccountsList?: (arg?: boolean) => void; - setMT5TradeAccount: (arg: any) => void; - toggleCFDVerificationModal: () => void; - setJurisdictionSelectedShortcode: (shortcode: string) => void; - setAccountType: (account_type: { category: string; type?: string }) => void; - setIsAcuityModalOpen: (value: boolean) => void; - updateAccountStatus: () => void; - real_account_creation_unlock_date: string; - setShouldShowCooldownModal: (value: boolean) => void; - setAppstorePlatform: (value: string) => void; - show_eu_related_content: boolean; }; export type TTradingPlatformAccounts = { diff --git a/packages/cfd/src/Containers/__tests__/cfd-financial-stp-real-account-signup.spec.js b/packages/cfd/src/Containers/__tests__/cfd-financial-stp-real-account-signup.spec.js index 44d4ad147087..a5aee93657b1 100644 --- a/packages/cfd/src/Containers/__tests__/cfd-financial-stp-real-account-signup.spec.js +++ b/packages/cfd/src/Containers/__tests__/cfd-financial-stp-real-account-signup.spec.js @@ -1,20 +1,22 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import CFDFinancialStpRealAccountSignup from '../cfd-financial-stp-real-account-signup'; - -jest.mock('Stores/connect.js', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => Component, -})); +import CFDProviders from '../../cfd-providers'; +import { mockStore } from '@deriv/stores'; jest.mock('@deriv/account', () => ({ ...jest.requireActual('@deriv/account'), FormSubHeader: () =>
FormSubHeader
, })); -jest.mock('../../Components/cfd-poa', () => jest.fn(() =>
CFDPOA
)); -jest.mock('../../Components/cfd-poi', () => jest.fn(() =>
CFDPOI
)); +jest.mock('../../Components/cfd-poa', () => jest.fn(() =>
CFDPOA
)); +jest.mock('../../Components/cfd-poi', () => + jest.fn(({ onSubmit }) => ( +
onSubmit(0, {})}> + CFDPOI +
+ )) +); const getByTextFn = (text, should_be) => { if (should_be) { @@ -68,117 +70,132 @@ describe('', () => { jest.clearAllMocks(); }); - const mock_props = { - addNotificationByKey: jest.fn(), - fetchStatesList: jest.fn(), - openPendingDialog: jest.fn(), - refreshNotifications: jest.fn(), - removeNotificationByKey: jest.fn(), - removeNotificationMessage: jest.fn(), - storeProofOfAddress: jest.fn(), - toggleModal: jest.fn(), - authentication_status: { - document_status: 'none', - identity_status: 'none', + let mockRootStore = { + notifications: { + addNotificationByKey: jest.fn(), + refreshNotifications: jest.fn(), + removeNotificationByKey: jest.fn(), + removeNotificationMessage: jest.fn(), }, - client_email: 'mock@gmail.com', - get_settings: { - account_opening_reason: '', - address_city: 'MUDGEERABA', - address_line_1: "29 Ross Street, .'", - address_line_2: ".'", - address_postcode: '111', - address_state: '', - allow_copiers: 0, - citizen: '', - client_tnc_status: 'Version 4.2.0 2020-08-07', - country: 'Singapore', - country_code: 'sg', - date_of_birth: 984960000, - email: 'mock@gmail.com', - email_consent: 1, - feature_flag: { - wallet: 0, + client: { + account_settings: { + account_opening_reason: '', + address_city: 'MUDGEERABA', + address_line_1: "29 Ross Street, .'", + address_line_2: ".'", + address_postcode: '111', + address_state: '', + allow_copiers: 0, + citizen: '', + client_tnc_status: 'Version 4.2.0 2020-08-07', + country: 'Singapore', + country_code: 'sg', + date_of_birth: 984960000, + email: 'mock@gmail.com', + email_consent: 1, + feature_flag: { + wallet: 0, + }, + first_name: 'mahdiyeh', + has_secret_answer: 1, + immutable_fields: ['residence'], + is_authenticated_payment_agent: 0, + last_name: 'am', + non_pep_declaration: 1, + phone: '+651213456', + place_of_birth: null, + preferred_language: 'EN', + request_professional_status: 0, + residence: 'Singapore', + salutation: '', + tax_identification_number: null, + tax_residence: null, + user_hash: '823341c18bfccb391b6bb5d77ab7e6a83991f82669c1ba4e5b01dbd2fd71c7fe', }, - first_name: 'mahdiyeh', - has_secret_answer: 1, - immutable_fields: ['residence'], - is_authenticated_payment_agent: 0, - last_name: 'am', - non_pep_declaration: 1, - phone: '+651213456', - place_of_birth: null, - preferred_language: 'EN', - request_professional_status: 0, - residence: 'Singapore', - salutation: '', - tax_identification_number: null, - tax_residence: null, - user_hash: '823341c18bfccb391b6bb5d77ab7e6a83991f82669c1ba4e5b01dbd2fd71c7fe', - }, - is_fully_authenticated: true, - landing_company: { - config: { - tax_details_required: 1, - tin_format: ['^\\d{15}$'], - tin_format_description: '999999999999999', + authentication_status: { + document_status: 'none', + identity_status: 'none', }, - dxtrade_financial_company: {}, - dxtrade_gaming_company: {}, - financial_company: {}, - gaming_company: {}, - id: 'id', - minimum_age: 18, - mt_financial_company: {}, - mt_gaming_company: {}, - name: 'Indonesia', - virtual_company: 'virtual', - }, - residence_list: [ - { - identity: { - services: { - idv: { - documents_supported: {}, - has_visual_sample: 0, - is_country_supported: 0, - }, - onfido: { - documents_supported: { - passport: { - display_name: 'Passport', + email: 'mock@gmail.com', + is_fully_authenticated: true, + landing_company: { + config: { + tax_details_required: 1, + tin_format: ['^\\d{15}$'], + tin_format_description: '999999999999999', + }, + dxtrade_financial_company: {}, + dxtrade_gaming_company: {}, + financial_company: {}, + gaming_company: {}, + id: 'id', + minimum_age: 18, + mt_financial_company: {}, + mt_gaming_company: {}, + name: 'Indonesia', + virtual_company: 'virtual', + }, + residence_list: [ + { + identity: { + services: { + idv: { + documents_supported: {}, + has_visual_sample: 0, + is_country_supported: 0, + }, + onfido: { + documents_supported: { + passport: { + display_name: 'Passport', + }, }, + is_country_supported: 0, }, - is_country_supported: 0, }, }, + phone_idd: '93', + text: 'Afghanistan', + value: 'af', }, - phone_idd: '93', - text: 'Afghanistan', - value: 'af', + ], + fetchStatesList: jest.fn(), + states_list: { + text: 'Central Singapore', + value: '01', + }, + }, + modules: { + cfd: { + storeProofOfAddress: jest.fn(), }, - ], - states_list: { - text: 'Central Singapore', - value: '01', }, }; it('should render CFDFinancialStpRealAccountSignup component', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByTestId('dt_cfd_financial_stp_modal_body')).toBeInTheDocument(); }); it('should render properly for the first step content', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); testAllStepsFn(steps, 0); }); it('should render properly for the second step content', () => { - jest.spyOn(React, 'useState').mockReturnValueOnce([1, () => {}]); - render(); + const { getByTestId } = render(, { + wrapper: ({ children }) => {children}, + }); + + const div = getByTestId('poa-form'); + + fireEvent.click(div); testAllStepsFn(steps, 1); }); diff --git a/packages/cfd/src/Containers/__tests__/cfd-password-manager-modal.spec.js b/packages/cfd/src/Containers/__tests__/cfd-password-manager-modal.spec.js index c88da28fe9db..39e07dc9598a 100644 --- a/packages/cfd/src/Containers/__tests__/cfd-password-manager-modal.spec.js +++ b/packages/cfd/src/Containers/__tests__/cfd-password-manager-modal.spec.js @@ -2,12 +2,8 @@ import React from 'react'; import { screen, render, fireEvent, waitFor, act, cleanup } from '@testing-library/react'; import CFDPasswordManagerModal from '../cfd-password-manager-modal'; import { BrowserRouter } from 'react-router-dom'; - -jest.mock('Stores/connect', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => Component, -})); +import CFDProviders from '../../cfd-providers'; +import { mockStore } from '@deriv/stores'; jest.mock('@deriv/components', () => { const original_module = jest.requireActual('@deriv/components'); @@ -23,6 +19,7 @@ jest.mock('@deriv/shared/src/services/ws-methods', () => ({ WS: { verifyEmail: jest.fn(() => Promise.resolve()), }, + useWS: () => undefined, })); jest.mock('@contentpass/zxcvbn', () => ({ @@ -67,8 +64,24 @@ jest.mock('@deriv/shared/src/utils/validation/declarative-validation-rules.ts', }); describe('', () => { + const mockRootStore = { + ui: { + enableApp: jest.fn(), + disableApp: jest.fn(), + }, + client: { + email: 'test@domain.com', + }, + modules: { + cfd: { + sendVerifyEmail: jest.fn(), + }, + }, + }; const renderwithRouter = component => { - render({component}); + render({component}, { + wrapper: ({ children }) => {children}, + }); }; let modal_root_el; @@ -85,9 +98,6 @@ describe('', () => { afterEach(cleanup); const mock_props = { - enableApp: jest.fn(), - email: 'test@domain.com', - disableApp: jest.fn(), is_visible: true, platform: 'mt5', selected_login: 'MTD20103241', @@ -96,7 +106,6 @@ describe('', () => { selected_account_type: 'financial', selected_account_group: 'demo', selected_server: 'p01_ts03', - sendVerifyEmail: jest.fn(), }; it('should render the deriv mt5 password modal', () => { diff --git a/packages/cfd/src/Containers/__tests__/cfd-password-modal.spec.js b/packages/cfd/src/Containers/__tests__/cfd-password-modal.spec.js index 3d0dd9b41ca2..e754e10622d0 100644 --- a/packages/cfd/src/Containers/__tests__/cfd-password-modal.spec.js +++ b/packages/cfd/src/Containers/__tests__/cfd-password-modal.spec.js @@ -4,12 +4,8 @@ import { createBrowserHistory } from 'history'; import { WS, getErrorMessages, validPassword, Jurisdiction } from '@deriv/shared'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import CFDPasswordModal from '../cfd-password-modal'; - -jest.mock('Stores/connect.js', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => Component, -})); +import CFDProviders from '../../cfd-providers'; +import { mockStore } from '@deriv/stores'; jest.mock('@deriv/account', () => ({ SentEmailModal: jest.fn(({ should_show_sent_email_modal }) => ( @@ -45,33 +41,44 @@ describe('', () => { const mockSubmitCFDPasswordFn = jest.fn(); const history = createBrowserHistory(); let modal_root_el; + + let mockRootStore = { + client: { + email: '', + account_status: {}, + updateAccountStatus: jest.fn(), + landing_companies: {}, + mt5_login_list: [], + is_dxtrade_allowed: false, + }, + traders_hub: { + show_eu_related_content: false, + }, + modules: { + cfd: { + is_cfd_password_modal_enabled: true, + is_cfd_success_dialog_enabled: false, + submitMt5Password: mockSubmitMt5Password, + submitCFDPassword: mockSubmitCFDPasswordFn, + setError: mockSetMt5Error, + setCFDSuccessDialog: mockSetCFDSuccessDialog, + has_cfd_error: false, + error_message: '', + error_type: '', + account_title: '', + account_type: {}, + disableCFDPasswordModal: mockDisableCFDPasswordModalFn, + getAccountStatus: mockFn, + new_account_response: {}, + jurisdiction_selected_shortcode: Jurisdiction.SVG, + }, + }, + }; + const mock_props = { - account_title: '', - account_type: {}, - account_status: {}, - disableCFDPasswordModal: mockDisableCFDPasswordModalFn, - email: '', - error_message: '', - error_type: '', form_error: '', - getAccountStatus: mockFn, history: history, - is_eu: false, - is_fully_authenticated: false, - is_cfd_password_modal_enabled: true, - is_cfd_success_dialog_enabled: false, - is_dxtrade_allowed: false, - jurisdiction_selected_shortcode: Jurisdiction.SVG, platform: 'mt5', - has_cfd_error: false, - landing_companies: {}, - mt5_login_list: [], - cfd_new_account: {}, - setCFDSuccessDialog: mockSetCFDSuccessDialog, - setMt5Error: mockSetMt5Error, - submitMt5Password: mockSubmitMt5Password, - submitCFDPassword: mockSubmitCFDPasswordFn, - updateAccountStatus: jest.fn(), }; beforeAll(() => { @@ -89,22 +96,34 @@ describe('', () => { }); it('should render create Password modal when valid conditions are met', async () => { + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect(await screen.findByTestId('dt_create_password')).toBeInTheDocument(); }); it('should render password form with Try later button and forget password button', async () => { + const store = mockStore(mockRootStore); + + store.client.account_status = { status: [] }; + store.modules.cfd.error_type = 'PasswordReset'; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect(await screen.findByRole('button', { name: /try later/i })).toBeInTheDocument(); @@ -112,14 +131,18 @@ describe('', () => { }); it('should close modal when Forget Password button is clicked', async () => { + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }; + store.modules.cfd.error_type = 'PasswordReset'; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); const ele_forget_btn = await screen.findByRole('button', { name: /forgot password?/i }); fireEvent.click(ele_forget_btn); @@ -132,15 +155,19 @@ describe('', () => { }); it('should invoke verifyEmail when forgot password is clicked', async () => { + const store = mockStore(mockRootStore); + + store.client.account_status = { status: [], category: 'Real' }; + store.modules.cfd.error_type = 'PasswordReset'; + store.modules.cfd.account_type = { category: 'real', type: 'financial' }; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); const ele_forget_btn = await screen.findByRole('button', { name: /forgot password?/i }); fireEvent.click(ele_forget_btn); @@ -151,10 +178,18 @@ describe('', () => { it('should display password field for user to enter the password and hold the entered value', async () => { const user_input = 'zo8lAet#2q01Ih'; + + const store = mockStore(mockRootStore); + + store.client.account_status = { status: [], category: 'Real' }; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); const ele_password_field = await screen.findByTestId('dt_mt5_password'); @@ -170,14 +205,19 @@ describe('', () => { it('should display error message when password does not meet requirements', async () => { validPassword.mockReturnValue(false); const user_input = 'demo@deriv.com'; + + const store = mockStore(mockRootStore); + + store.client.account_status = { status: [], category: 'Real' }; + store.client.email = user_input; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); const ele_password_input = await screen.findByTestId('dt_mt5_password'); fireEvent.change(ele_password_input, { target: { value: user_input } }); @@ -193,15 +233,19 @@ describe('', () => { it('should display error message when password contain non-english characters', async () => { validPassword.mockReturnValue(false); - const user_input = 'demo@deriv.com'; + + const store = mockStore(mockRootStore); + + store.client.account_status = { status: [], category: 'Real' }; + store.client.email = 'demo@deriv.com'; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); const ele_password_input = await screen.findByTestId('dt_mt5_password'); fireEvent.change(ele_password_input, { target: { value: 'Passwordååøø' } }); @@ -220,19 +264,20 @@ describe('', () => { }); it('should show transfer message on successful DerivX account creation', async () => { - const props = { - is_cfd_success_dialog_enabled: true, - is_password_modal_exited: true, - account_type: { category: 'real', type: 'financial' }, - is_eu: false, - is_fully_authenticated: false, - platform: 'dxtrade', - }; + const store = mockStore(mockRootStore); + + store.client.account_status = { status: [], category: 'Real' }; + store.modules.cfd.account_type = { category: 'real', type: 'financial' }; + store.modules.cfd.is_cfd_success_dialog_enabled = true; + store.modules.cfd.error_type = 'PasswordReset'; render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect( @@ -241,19 +286,20 @@ describe('', () => { }); it('should close the dialog when you click on ok button', async () => { - const props = { - is_cfd_success_dialog_enabled: true, - is_password_modal_exited: true, - account_type: { category: 'real', type: 'financial' }, - is_eu: true, - is_fully_authenticated: false, - jurisdiction_selected_shortcode: Jurisdiction.BVI, - }; + const store = mockStore(mockRootStore); + + store.client.account_status = { status: [], category: 'Real' }; + store.modules.cfd.account_type = { category: 'real', type: 'financial' }; + store.modules.cfd.is_cfd_success_dialog_enabled = true; + store.modules.cfd.jurisdiction_selected_shortcode = 'bvi'; render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); fireEvent.click(await screen.findByRole('button', { name: /ok/i })); @@ -266,17 +312,18 @@ describe('', () => { }); it('should show success dialog with buttons to Transfer now or later when password has been updated successfully', async () => { + const store = mockStore(mockRootStore); + + store.modules.cfd.account_type = { category: 'real', type: 'financial' }; + store.modules.cfd.is_cfd_success_dialog_enabled = true; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect(await screen.findByRole('button', { name: /maybe later/i })); @@ -284,95 +331,123 @@ describe('', () => { }); it('should display Derived icon in Success Dialog', async () => { - const props = { - account_status: { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }, - error_type: 'PasswordError', - account_type: { category: 'real', type: 'synthetic' }, - }; + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }; + store.modules.cfd.account_type = { category: 'real', type: 'synthetic' }; + store.modules.cfd.error_type = 'PasswordError'; + store.modules.cfd.is_cfd_success_dialog_enabled = true; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect(await screen.findByText('IcMt5SyntheticPlatform')).toBeInTheDocument(); }); it('should display icon in Success Dialog in tradershub', async () => { - const props = { - account_status: { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }, - error_type: 'PasswordError', - account_type: { category: 'real', type: 'synthetic' }, - }; + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }; + store.modules.cfd.account_type = { category: 'real', type: 'synthetic' }; + store.modules.cfd.error_type = 'PasswordError'; + store.modules.cfd.is_cfd_success_dialog_enabled = true; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect(await screen.findByText('IcMt5SyntheticPlatform')).toBeInTheDocument(); }); it('should display Financial icon in Success Dialog', async () => { - const props = { - account_status: { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }, - error_type: 'PasswordError', - account_type: { category: 'real', type: 'financial' }, - }; + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }; + store.modules.cfd.account_type = { category: 'real', type: 'financial' }; + store.modules.cfd.error_type = 'PasswordError'; + store.modules.cfd.is_cfd_success_dialog_enabled = true; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect(await screen.findByText('IcMt5FinancialPlatform')).toBeInTheDocument(); }); it('should display IcRebrandingDerivx icon in Success Dialog', async () => { - const props = { - account_status: { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }, - platform: 'dxtrade', - error_type: 'PasswordError', - account_type: { category: 'real', type: 'all' }, - }; + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }; + store.modules.cfd.account_type = { category: 'real', type: 'all' }; + store.modules.cfd.error_type = 'PasswordError'; + store.modules.cfd.is_cfd_success_dialog_enabled = true; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect(await screen.findByText('IcRebrandingDxtradeDashboard')).toBeInTheDocument(); }); it('should display IcCfds icon in Success Dialog', async () => { - const props = { - account_status: { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }, - error_type: 'PasswordError', - account_type: { category: 'real', type: 'financial' }, - }; + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set', 'dxtrade_password_not_set'] }; + store.traders_hub.show_eu_related_content = true; + store.modules.cfd.account_type = { category: 'real', type: 'financial' }; + store.modules.cfd.error_type = 'PasswordError'; + store.modules.cfd.is_cfd_success_dialog_enabled = true; + render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); expect(await screen.findByText('IcMt5CfdPlatform')).toBeInTheDocument(); }); it('should invoke verifyEmail for DerivX when Forgot password is clicked', async () => { - const props = { - account_status: { status: [], category: 'Real' }, - platform: 'dxtrade', - error_type: 'PasswordReset', - setCFDSuccessDialog: mockFn, - account_type: { category: 'demo', type: 'financial' }, - email: 'demo@deriv.com', - }; + const store = mockStore(mockRootStore); + + store.client.account_status = { status: [], category: 'Real' }; + store.client.email = 'demo@deriv.com'; + store.modules.cfd.account_type = { category: 'demo', type: 'financial' }; + store.modules.cfd.error_type = 'PasswordReset'; + store.modules.cfd.setCFDSuccessDialog = mockFn; render( - - + + , + { + wrapper: ({ children }) => {children}, + } ); + const ele_forget_btn = await screen.findByRole('button', { name: /forgot password?/i }); fireEvent.click(ele_forget_btn); await waitFor(() => { @@ -386,15 +461,18 @@ describe('', () => { const user_input = 'zo8lAet#2q01Ih'; validPassword.mockReturnValue(true); + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set'], category: 'Real' }; + store.modules.cfd.account_type = { category: 'real', type: 'financial' }; + render( - - ; - + ; + , + { + wrapper: ({ children }) => {children}, + } ); fireEvent.change(await screen.findByTestId('dt_mt5_password'), { target: { value: user_input } }); fireEvent.click(await screen.findByRole('button', { name: 'Create Deriv MT5 password' })); @@ -408,17 +486,20 @@ describe('', () => { const user_input = 'zo8lAet#2q01Ih'; validPassword.mockReturnValue(true); + const store = mockStore(mockRootStore); + + store.client.account_status = { status: ['mt5_password_not_set'], category: 'Real' }; + store.modules.cfd.account_type = { category: 'real', type: 'financial' }; + render( - - ; - + ; + , + { + wrapper: ({ children }) => {children}, + } ); + fireEvent.change(await screen.findByTestId('dt_dxtrade_password'), { target: { value: user_input } }); fireEvent.click(await screen.findByRole('button', { name: 'Add account' })); diff --git a/packages/cfd/src/Containers/__tests__/cfd-server-error-dialog.spec.js b/packages/cfd/src/Containers/__tests__/cfd-server-error-dialog.spec.js index 823bdbfdae7a..dbe28275cdd0 100644 --- a/packages/cfd/src/Containers/__tests__/cfd-server-error-dialog.spec.js +++ b/packages/cfd/src/Containers/__tests__/cfd-server-error-dialog.spec.js @@ -1,13 +1,8 @@ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; -import { StoreProvider } from '@deriv/stores'; +import { mockStore } from '@deriv/stores'; import CFDServerErrorDialog from '../cfd-server-error-dialog'; - -jest.mock('Stores/connect.js', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => Component, -})); +import CFDProviders from '../../cfd-providers'; describe(' ', () => { beforeAll(() => { @@ -40,7 +35,7 @@ describe(' ', () => { it('should render the component properly', () => { const { container } = render(, { - wrapper: ({ children }) => {children}, + wrapper: ({ children }) => {children}, }); expect(container.firstChild).toHaveClass('dc-dialog__wrapper dc-dialog__wrapper--enter'); @@ -48,7 +43,7 @@ describe(' ', () => { it('should render the proper text and error message', () => { render(, { - wrapper: ({ children }) => {children}, + wrapper: ({ children }) => {children}, }); expect(screen.getByText(/This is a sample error message/i)).toBeInTheDocument(); @@ -69,7 +64,7 @@ describe(' ', () => { }, }; render(, { - wrapper: ({ children }) => {children}, + wrapper: ({ children }) => {children}, }); expect(screen.queryByText(/This is a sample error message/i)).not.toBeInTheDocument(); @@ -89,7 +84,7 @@ describe(' ', () => { }; render(, { - wrapper: ({ children }) => {children}, + wrapper: ({ children }) => {children}, }); expect(screen.queryByText(/This is a sample error message/i)).not.toBeInTheDocument(); @@ -97,7 +92,7 @@ describe(' ', () => { it('should clear the component if OK is clicked', () => { render(, { - wrapper: ({ children }) => {children}, + wrapper: ({ children }) => {children}, }); const ok_btn = screen.getByRole('button', { name: /OK/i }); diff --git a/packages/cfd/src/Containers/__tests__/cfd-top-up-demo-modal.spec.js b/packages/cfd/src/Containers/__tests__/cfd-top-up-demo-modal.spec.js index 27a3f4b65e2b..eff858764deb 100644 --- a/packages/cfd/src/Containers/__tests__/cfd-top-up-demo-modal.spec.js +++ b/packages/cfd/src/Containers/__tests__/cfd-top-up-demo-modal.spec.js @@ -1,12 +1,8 @@ import React from 'react'; -import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { render, screen, fireEvent } from '@testing-library/react'; import CFDTopUpDemoModal from '../cfd-top-up-demo-modal.tsx'; - -jest.mock('Stores/connect.js', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => Component, -})); +import CFDProviders from '../../cfd-providers'; +import { mockStore } from '@deriv/stores'; jest.mock('../../Components/success-dialog.jsx', () => () =>
Success Dialog
); @@ -35,48 +31,57 @@ describe('CFDTopUpDemoModal', () => { }; const mock_props = { - dxtrade_companies: {}, - mt5_companies: { - demo: { - synthetic: { - mt5_account_type: synthetic_config.account_type, - leverage: synthetic_config.leverage, - title: 'Demo Derived', - short_title: synthetic_config.short_title, - }, - financial: { - mt5_account_type: financial_config.account_type, - leverage: financial_config.leverage, - title: 'Demo Financial', - short_title: financial_config.short_title, - }, - }, - real: { - synthetic: { - mt5_account_type: synthetic_config.account_type, - leverage: synthetic_config.leverage, - title: 'Derived', - short_title: synthetic_config.short_title, - }, - financial: { - mt5_account_type: financial_config.account_type, - leverage: financial_config.leverage, - title: 'CFDs', - short_title: financial_config.short_title, + modules: { + cfd: { + dxtrade_companies: {}, + mt5_companies: { + demo: { + synthetic: { + mt5_account_type: synthetic_config.account_type, + leverage: synthetic_config.leverage, + title: 'Demo Derived', + short_title: synthetic_config.short_title, + }, + financial: { + mt5_account_type: financial_config.account_type, + leverage: financial_config.leverage, + title: 'Demo Financial', + short_title: financial_config.short_title, + }, + }, + real: { + synthetic: { + mt5_account_type: synthetic_config.account_type, + leverage: synthetic_config.leverage, + title: 'Derived', + short_title: synthetic_config.short_title, + }, + financial: { + mt5_account_type: financial_config.account_type, + leverage: financial_config.leverage, + title: 'CFDs', + short_title: financial_config.short_title, + }, + }, }, + topUpVirtual: jest.fn(), + current_account: { category: 'demo', type: 'financial', balance: '700', display_balance: '700' }, }, }, - current_account: { category: 'demo', type: 'financial', balance: '700', display_balance: '700' }, - closeSuccessTopUpModal: jest.fn(), - closeTopUpModal: jest.fn(), - is_top_up_virtual_open: true, - is_top_up_virtual_in_progress: false, - is_top_up_virtual_success: false, + ui: { + closeSuccessTopUpModal: jest.fn(), + closeTopUpModal: jest.fn(), + is_top_up_virtual_open: true, + is_top_up_virtual_in_progress: false, + is_top_up_virtual_success: false, + }, platform: 'test platform', - topUpVirtual: jest.fn(), }; + it('should render the button texts correctly', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('Fund top up')).toBeInTheDocument(); expect(screen.getByText('Current balance')).toBeInTheDocument(); expect(screen.queryByTestId('dt_top_up_virtual_description')).toBeInTheDocument(); @@ -84,66 +89,63 @@ describe('CFDTopUpDemoModal', () => { }); it('should render the proper balance in the current balance', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('700.00')).toBeInTheDocument(); }); it('should disable the top up button if the balance is higher than 1000 USD', () => { - render( - - ); + mock_props.modules.cfd.current_account = { category: 'demo', type: 'financial', balance: 2000 }; + + render(, { + wrapper: ({ children }) => {children}, + }); const top_up_btn = screen.getByRole('button', { name: /Top up/i }); expect(top_up_btn).toBeDisabled(); }); it('should enable the top up button if the balance is lower than 1000 USD', () => { - render( - - ); + mock_props.modules.cfd.current_account = { category: 'demo', type: 'financial', balance: 500 }; + + render(, { + wrapper: ({ children }) => {children}, + }); const top_up_btn = screen.getByRole('button', { name: /Top up/i }); expect(top_up_btn).toBeEnabled(); }); it('should render the success dialog component if the user has less than 1000 USD and clicks on top up', () => { - render( - - ); + mock_props.modules.cfd.current_account = { category: 'demo', type: 'financial', balance: 500 }; + + render(, { + wrapper: ({ children }) => {children}, + }); const top_up_btn = screen.getByRole('button', { name: /Top up/i }); fireEvent.click(top_up_btn); expect(screen.getByText('Success Dialog')).toBeInTheDocument(); }); it('should render the success component if the is_top_up_virtual_success is true', () => { - render( - - ); + mock_props.current_account = { category: 'demo', type: 'financial', balance: 500 }; + mock_props.ui.is_top_up_virtual_success = true; + mock_props.ui.is_top_up_virtual_open = false; + + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('Success Dialog')).toBeInTheDocument(); expect(screen.queryByTestId('dt_top_up_virtual_description')).not.toBeInTheDocument(); }); it('should not render the component if conditions are false', () => { - render( - - ); + mock_props.modules.cfd.current_account = { category: 'demo', type: 'financial', balance: 500 }; + mock_props.ui.is_top_up_virtual_success = false; + mock_props.ui.is_top_up_virtual_open = false; + + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.queryByTestId('dt_top_up_virtual_description')).not.toBeInTheDocument(); }); }); diff --git a/packages/cfd/src/Containers/__tests__/compare-accounts-modal.spec.js b/packages/cfd/src/Containers/__tests__/compare-accounts-modal.spec.js index 4bb1a58cec88..740f746e346c 100644 --- a/packages/cfd/src/Containers/__tests__/compare-accounts-modal.spec.js +++ b/packages/cfd/src/Containers/__tests__/compare-accounts-modal.spec.js @@ -1,12 +1,8 @@ import React from 'react'; import { render, screen, waitFor, fireEvent } from '@testing-library/react'; import CompareAccountsModal from '../compare-accounts-modal'; - -jest.mock('Stores/connect.js', () => ({ - __esModule: true, - default: 'mockedDefaultExport', - connect: () => Component => Component, -})); +import CFDProviders from '../../cfd-providers'; +import { mockStore } from '@deriv/stores'; jest.mock('../mt5-compare-table-content', () => jest.fn(() => 'MockedMt5CompareTableContent')); @@ -26,63 +22,82 @@ describe('CompareAccountsModal', () => { let mock_props; beforeEach(() => { mock_props = { - disableApp: jest.fn(), - enableApp: jest.fn(), - is_compare_accounts_visible: true, - is_loading: false, - is_logged_in: true, - is_eu: false, - is_uk: false, - is_eu_country: false, + ui: { + disableApp: jest.fn(), + enableApp: jest.fn(), + openDerivRealAccountNeededModal: jest.fn(), + }, + modules: { + cfd: { + is_compare_accounts_visible: true, + toggleCompareAccountsModal: jest.fn(), + openPasswordModal: jest.fn(), + }, + }, + client: { + is_populating_mt5_account_list: false, + is_logged_in: true, + is_eu: false, + is_uk: false, + residence: 'id', + }, is_real_enabled: true, platform: 'mt5', - residence: 'id', is_demo_tab: true, - toggleCompareAccounts: jest.fn(), - openPasswordModal: jest.fn(), - openDerivRealAccountNeededModal: jest.fn(), }; }); it('should render the modal', async () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); await waitFor(() => { expect(screen.getByText(/compare available accounts/i)).toBeInTheDocument(); }); }); it('should render the MockedMT5CompareTableContent for mt5', async () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); await waitFor(() => { expect(screen.getByText(/compare available accounts/i)).toBeInTheDocument(); }); expect(screen.getByText(/MockedMt5CompareTableContent/i)).toBeInTheDocument(); }); it('should render the CompareAccountsModal if the platform is dxtrade', async () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); await waitFor(() => { expect(screen.getAllByText(/account information/i)[0]).toBeInTheDocument(); }); expect(screen.getAllByText(/maximum leverage/i)[0]).toBeInTheDocument(); }); it('should render the MockedMt5CompareTableContent if the user is not logged in', async () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); await waitFor(() => { expect(screen.getByText(/compare available accounts/i)).toBeInTheDocument(); }); expect(screen.getByText(/MockedMt5CompareTableContent/i)).toBeInTheDocument(); }); it('should call toggleCompareAccountsModal if the compare accounts button is clicked', async () => { - render( - - ); + render(, { + wrapper: ({ children }) => ( + + {children} + + ), + }); await waitFor(() => { expect(screen.getAllByText(/account information/i)[0]).toBeInTheDocument(); }); fireEvent.click(screen.getByText(/account information/i)); - expect(mock_props.toggleCompareAccounts).toHaveBeenCalled(); + expect(mock_props.modules.cfd.toggleCompareAccountsModal).toHaveBeenCalled(); }); }); diff --git a/packages/cfd/src/Containers/cfd-dashboard.tsx b/packages/cfd/src/Containers/cfd-dashboard.tsx index eacb9fe9dc93..da813fd7ab56 100644 --- a/packages/cfd/src/Containers/cfd-dashboard.tsx +++ b/packages/cfd/src/Containers/cfd-dashboard.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { RouteComponentProps, withRouter } from 'react-router'; +import { RouteComponentProps, useLocation } from 'react-router'; import { Redirect, useHistory } from 'react-router-dom'; import { Icon, Tabs, PageError, Loading, Text } from '@deriv/components'; import { @@ -13,7 +13,6 @@ import { } from '@deriv/shared'; import { Localize, localize } from '@deriv/translations'; import { ResetTradingPasswordModal } from '@deriv/account'; -import { connect } from '../Stores/connect'; import MissingRealAccount from './missing-real-account'; import LoadingCFDRealAccountDisplay from './loading-cfd-real-account-display'; import CompareAccountsModal from './compare-accounts-modal'; @@ -29,12 +28,14 @@ import CFDResetPasswordModal from './cfd-reset-password-modal'; import { general_messages } from '../Constants/cfd-shared-strings'; import SwitchToRealAccountModal from './switch-to-real-account'; import 'Sass/cfd-dashboard.scss'; -import RootStore from '../Stores/index'; -import { LandingCompany, ResidenceList, DetailsOfEachMT5Loginid } from '@deriv/api-types'; +import { LandingCompany, DetailsOfEachMT5Loginid } from '@deriv/api-types'; // TODO: Change these imports after real released import CFDDxtradeDemoAccountDisplay from '../Components/cfd-dxtrade-demo-account-display'; import CFDMT5DemoAccountDisplay from '../Components/cfd-mt5-demo-account-display'; import { CFDRealAccountDisplay } from '../Components/cfd-real-account-display'; +import { observer, useStore } from '@deriv/stores'; +import { TCFDPasswordReset } from './props.types'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; import { TTradingPlatformAccounts } from 'Components/props.types'; declare module 'react' { @@ -71,14 +72,6 @@ type TOpenAccountTransferMeta = { type?: string; }; -type TStandPoint = { - financial_company: string; - gaming_company: string; - iom: boolean; - malta: boolean; - maltainvest: boolean; - svg: boolean; -}; type TMt5StatusServerType = { all: number; platform: number; @@ -87,122 +80,108 @@ type TMt5StatusServerType = { withdrawals?: number; }; -type TDXTraderStatusServerType = Record<'all' | 'demo' | 'real', number>; - type TMt5StatusServer = Record<'demo' | 'real', TMt5StatusServerType[]>; export type TObjectCFDAccount = { category: string; type: string; set_password?: number; platform?: string }; export type TCFDDashboardProps = RouteComponentProps & { account_status: object; - beginRealSignupForMt5: () => void; - country: string; - context: Record; - createCFDAccount: (objCFDAccount: TObjectCFDAccount) => void; // TODO: update this type (DetailsOfEachMT5Loginid) when BE changed the schema - current_list: Record< - string, - DetailsOfEachMT5Loginid & { - enabled: number; - } - >; - dxtrade_accounts_list_error: null; - isAccountOfTypeDisabled: (account: Record) => boolean; - is_accounts_switcher_on: boolean; - is_dark_mode_on: boolean; - is_eu: boolean; - is_eu_country: boolean; - is_loading: boolean; - is_logged_in: boolean; - is_logging_in: boolean; - is_mt5_allowed: boolean; - is_mt5_trade_modal_visible: boolean; - is_dxtrade_allowed: boolean; - is_virtual: boolean; - landing_companies: LandingCompany; - has_maltainvest_account: boolean; - has_mt5_real_account_error: boolean; - has_mt5_demo_account_error: boolean; - has_dxtrade_real_account_error: boolean; - has_dxtrade_demo_account_error: boolean; - mt5_disabled_signup_types: { - real: boolean; - demo: boolean; - }; - dxtrade_disabled_signup_types: { - real: boolean; - demo: boolean; - }; - dxtrade_tokens: { - demo: string; - real: string; - }; - derivez_tokens: { - demo: string; - real: string; - }; - has_real_account: boolean; - NotificationMessages: ({ ...props }) => JSX.Element; platform: 'mt5' | 'dxtrade'; - openAccountNeededModal: () => void; - residence: string; - residence_list: ResidenceList; - standpoint: TStandPoint; - toggleAccountsDialog: () => void; - toggleMT5TradeModal: () => void; - toggleShouldShowRealAccountsList: () => void; - upgradeable_landing_companies: unknown[]; - is_reset_trading_password_modal_visible: boolean; - toggleResetTradingPasswordModal: () => void; - enableApp: () => void; - disableApp: () => void; - mt5_verification_code: object; - dxtrade_verification_code: object; - onMount: () => void; - onUnmount: () => void; - location: { - state: string; - pathname: string; - hash: string; - }; - checkShouldOpenAccount: () => void; - setCFDPasswordResetModal: (value: boolean) => void; - disableCFDPasswordModal: () => void; - openPasswordModal: (account_type?: TOpenAccountTransferMeta) => void; - openTopUpModal: () => void; - setCurrentAccount: (data: DetailsOfEachMT5Loginid, meta: TOpenAccountTransferMeta) => void; - setAccountType: (account_type: TOpenAccountTransferMeta) => void; - mt5_status_server: TMt5StatusServer; - dxtrade_status_server: TDXTraderStatusServerType; - getRealSyntheticAccountsExistingData: ( - getRealSyntheticAccountsExistingData: DetailsOfEachMT5Loginid[] | undefined - ) => void; - getRealFinancialAccountsExistingData: ( - getRealSyntheticAccountsExistingData: DetailsOfEachMT5Loginid[] | undefined - ) => void; - openDerivRealAccountNeededModal: () => void; - setIsAcuityModalOpen: (value: boolean) => void; - refreshNotifications: () => void; - real_account_creation_unlock_date: string; - setShouldShowCooldownModal: (value: boolean) => void; - show_eu_related_content: boolean; - is_user_exception: boolean; }; -const CFDDashboard = (props: TCFDDashboardProps) => { +type TPasswordManager = { + is_visible: boolean; + selected_login: string; + selected_account: string; + selected_account_type: string; + selected_account_group: TCFDPasswordReset['account_group']; + selected_server: string; +}; + +const CFDDashboard = observer((props: TCFDDashboardProps) => { + const { client, ui, traders_hub, notifications } = useStore(); + + const { + landing_companies, + isAccountOfTypeDisabled, + is_logged_in, + is_logging_in, + is_eu, + is_eu_country, + is_virtual, + is_mt5_allowed, + is_dxtrade_allowed, + mt5_disabled_signup_types, + dxtrade_disabled_signup_types, + has_maltainvest_account, + dxtrade_accounts_list_error, + residence, + is_populating_mt5_account_list: is_loading, + has_account_error_in_mt5_real_list: has_mt5_real_account_error, + has_account_error_in_mt5_demo_list: has_mt5_demo_account_error, + has_account_error_in_dxtrade_real_list: has_dxtrade_real_account_error, + has_account_error_in_dxtrade_demo_list: has_dxtrade_demo_account_error, + has_active_real_account: has_real_account, + standpoint, + verification_code: platform_verification_code, + website_status, + upgradeable_landing_companies, + real_account_creation_unlock_date, + account_settings, + } = client; + + const { + trading_platform_mt5_password_reset: mt5_verification_code, + trading_platform_dxtrade_password_reset: dxtrade_verification_code, + } = platform_verification_code; + const { mt5_status: mt5_status_server, dx_trade_status: dxtrade_status_server } = website_status; + const { dxtrade_user_exception: is_user_exception, residence: country } = account_settings; + + const { + setCFDPasswordResetModal, + openAccountNeededModal, + is_accounts_switcher_on, + openTopUpModal, + notification_messages_ui: NotificationMessages, + toggleAccountsDialog, + toggleShouldShowRealAccountsList, + is_dark_mode_on, + disableApp, + enableApp, + is_reset_trading_password_modal_visible, + setResetTradingPasswordModalOpen: toggleResetTradingPasswordModal, + openDerivRealAccountNeededModal, + setShouldShowCooldownModal, + } = ui; + const { show_eu_related_content } = traders_hub; + const { refreshNotifications } = notifications; + + const { + onMount, + onUnmount, + setAccountType, + setCurrentAccount, + enableCFDPasswordModal, + getRealSyntheticAccountsExistingData, + getRealFinancialAccountsExistingData, + toggleMT5TradeModal, + beginRealSignupForMt5, + disableCFDPasswordModal, + checkShouldOpenAccount, + is_mt5_trade_modal_visible, + createCFDAccount, + current_list, + dxtrade_tokens, + derivez_tokens, + } = useCfdStore(); + const [is_demo_enabled, setIsDemoEnabled] = React.useState(false); const [is_real_enabled, setIsRealEnabled] = React.useState(false); const [active_index, setActiveIndex] = React.useState(0); const [is_demo_tab, setIsDemoTab] = React.useState(false); const [is_notification_loaded, setIsNotificationLoaded] = React.useState(false); - const [password_manager, setPasswordManager] = React.useState<{ - is_visible: boolean; - selected_login: string; - selected_account: string; - selected_account_type?: string; - selected_account_group?: string; - selected_server?: string; - }>({ + const [password_manager, setPasswordManager] = React.useState({ is_visible: false, selected_login: '', selected_account: '', @@ -212,6 +191,7 @@ const CFDDashboard = (props: TCFDDashboardProps) => { }); const history = useHistory(); + const location = useLocation(); React.useEffect(() => { if (window.location.href.includes(routes.mt5) || window.location.href.includes(routes.dxtrade)) { @@ -222,19 +202,19 @@ const CFDDashboard = (props: TCFDDashboardProps) => { React.useEffect(() => { updateActiveIndex(getIndexToSet()); openResetPassword(); - props.refreshNotifications(); - props.onMount(); + refreshNotifications(); + onMount(); return () => { - props.onUnmount(); + onUnmount(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // eslint-disable-next-line react-hooks/exhaustive-deps React.useEffect(() => { - props.checkShouldOpenAccount(); + checkShouldOpenAccount(); - if (props.is_logged_in) { + if (is_logged_in) { ['demo', 'real'].forEach(account_type => { const should_enable_tab = isDxtradeAllCardVisible(account_type) || @@ -251,7 +231,7 @@ const CFDDashboard = (props: TCFDDashboardProps) => { }); } - if (!props.is_logged_in && (!is_real_enabled || !is_demo_enabled)) { + if (!is_logged_in && (!is_real_enabled || !is_demo_enabled)) { setIsRealEnabled(true); setIsDemoEnabled(true); } @@ -271,11 +251,11 @@ const CFDDashboard = (props: TCFDDashboardProps) => { }, [props.location.hash]); const openResetPassword = () => { - if (!/reset-password/.test(props.location.hash)) { + if (!/reset-password/.test(location.hash)) { return; } - props.setCFDPasswordResetModal(true); + setCFDPasswordResetModal(true); }; const getIndexToSet = () => { @@ -286,9 +266,9 @@ const CFDDashboard = (props: TCFDDashboardProps) => { return 1; } - const hash = props.location.hash; + const hash = location.hash; if (hash) { - return /demo/.test(props.location.hash) ? 1 : 0; + return /demo/.test(location.hash) ? 1 : 0; } return undefined; }; @@ -324,19 +304,19 @@ const CFDDashboard = (props: TCFDDashboardProps) => { sessionStorage.setItem('cfd_transfer_to_login_id', data.account_id || ''); else sessionStorage.setItem('cfd_transfer_to_login_id', data.login || ''); - props.disableCFDPasswordModal(); - props.history.push(routes.cashier_acc_transfer); + disableCFDPasswordModal(); + history.push(routes.cashier_acc_transfer); } } else { - if ('sub_account_type' in data) props.setCurrentAccount(data, meta); - props.openTopUpModal(); + if ('sub_account_type' in data) setCurrentAccount(data, meta); + openTopUpModal(); } }; const togglePasswordManagerModal = ( login?: string, title?: string, - group?: string, + group?: TCFDPasswordReset['account_group'], type?: string, server?: string ) => { @@ -344,15 +324,15 @@ const CFDDashboard = (props: TCFDDashboardProps) => { is_visible: !prev_state.is_visible, selected_login: typeof login === 'string' ? login : '', selected_account: typeof title === 'string' ? title : '', - selected_account_group: group, - selected_account_type: type, - selected_server: server, + selected_account_group: group || '', + selected_account_type: type || '', + selected_server: server || '', })); }; const openRealPasswordModal = (account_type: TOpenAccountTransferMeta) => { - props.setAccountType(account_type); - props.openPasswordModal(); + setAccountType(account_type); + enableCFDPasswordModal(); }; const hasAccount = (category: string, type: string) => { @@ -360,14 +340,14 @@ const CFDDashboard = (props: TCFDDashboardProps) => { }; const isDxtradeAllCardVisible = (account_category: string) => { - const { platform, landing_companies } = props; + const { platform } = props; const has_synthetic_account = hasAccount(account_category, 'synthetic'); const has_financial_account = hasAccount(account_category, 'financial'); if (has_synthetic_account || has_financial_account) return false; - if (props.is_dxtrade_allowed && !props.is_logged_in) return true; + if (is_dxtrade_allowed && !is_logged_in) return true; return isLandingCompanyEnabled({ landing_companies, @@ -377,7 +357,7 @@ const CFDDashboard = (props: TCFDDashboardProps) => { }; const isSyntheticCardVisible = (account_category: string) => { - const { platform, is_eu, is_eu_country, landing_companies, is_logged_in } = props; + const { platform } = props; const has_synthetic_account = hasAccount(account_category, 'synthetic'); const has_financial_account = hasAccount(account_category, 'financial'); @@ -392,7 +372,7 @@ const CFDDashboard = (props: TCFDDashboardProps) => { }; const isFinancialCardVisible = () => { - const { platform, landing_companies, is_logged_in } = props; + const { platform } = props; const has_synthetic_account = hasAccount('real', 'synthetic'); const has_financial_account = hasAccount('real', 'financial'); @@ -409,9 +389,9 @@ const CFDDashboard = (props: TCFDDashboardProps) => { ); }; - const isSwapFreeCardVisible = () => { - const { platform, landing_companies, is_logged_in } = props; + const { account_status, platform } = props; + const isSwapFreeCardVisible = () => { return ( !is_logged_in || isLandingCompanyEnabled({ @@ -422,63 +402,6 @@ const CFDDashboard = (props: TCFDDashboardProps) => { ); }; - const { - account_status, - beginRealSignupForMt5, - country, - createCFDAccount, - current_list, - dxtrade_tokens, - derivez_tokens, - dxtrade_accounts_list_error, - isAccountOfTypeDisabled, - is_accounts_switcher_on, - is_dark_mode_on, - is_eu, - is_eu_country, - is_loading, - is_logged_in, - is_logging_in, - is_mt5_allowed, - is_mt5_trade_modal_visible, - is_dxtrade_allowed, - is_virtual, - landing_companies, - has_maltainvest_account, - has_mt5_real_account_error, - has_mt5_demo_account_error, - has_dxtrade_real_account_error, - has_dxtrade_demo_account_error, - mt5_disabled_signup_types, - dxtrade_disabled_signup_types, - has_real_account, - NotificationMessages, - platform, - openAccountNeededModal, - residence, - standpoint, - toggleAccountsDialog, - toggleMT5TradeModal, - toggleShouldShowRealAccountsList, - upgradeable_landing_companies, - is_reset_trading_password_modal_visible, - toggleResetTradingPasswordModal, - enableApp, - disableApp, - mt5_verification_code, - dxtrade_verification_code, - mt5_status_server, - dxtrade_status_server, - getRealSyntheticAccountsExistingData, - getRealFinancialAccountsExistingData, - openDerivRealAccountNeededModal, - setIsAcuityModalOpen, - real_account_creation_unlock_date, - setShouldShowCooldownModal, - show_eu_related_content, - is_user_exception, - } = props; - const should_show_missing_real_account = is_logged_in && !has_real_account && upgradeable_landing_companies?.length > 0; const should_enable_add_button = should_show_missing_real_account && CFD_PLATFORMS.MT5 && is_real_enabled; @@ -502,6 +425,7 @@ const CFDDashboard = (props: TCFDDashboardProps) => { ? is_suspended_dxtrade_demo_server || has_dxtrade_demo_account_error || dxtrade_disabled_signup_types.demo : is_suspended_dxtrade_real_server || has_dxtrade_real_account_error || dxtrade_disabled_signup_types.real; + // eslint-disable-next-line no-nested-ternary const has_cfd_account_error = is_user_exception ? !is_user_exception : platform === CFD_PLATFORMS.MT5 @@ -563,7 +487,6 @@ const CFDDashboard = (props: TCFDDashboardProps) => { is_visible={password_manager.is_visible} platform={platform} selected_login={password_manager.selected_login} - selected_account={password_manager.selected_account} selected_account_group={password_manager.selected_account_group} selected_account_type={password_manager.selected_account_type} selected_server={password_manager.selected_server} @@ -600,6 +523,7 @@ const CFDDashboard = (props: TCFDDashboardProps) => { is_eu_country={is_eu_country} is_logged_in={is_logged_in} has_cfd_account_error={ + // eslint-disable-next-line no-nested-ternary platform === CFD_PLATFORMS.MT5 ? has_cfd_real_account_mt5_error : is_user_exception @@ -622,12 +546,10 @@ const CFDDashboard = (props: TCFDDashboardProps) => { has_real_account={has_real_account} standpoint={standpoint} toggleAccountsDialog={toggleAccountsDialog} - toggleMT5TradeModal={toggleMT5TradeModal} toggleShouldShowRealAccountsList={toggleShouldShowRealAccountsList} residence={residence} openDerivRealAccountNeededModal={openDerivRealAccountNeededModal} should_enable_add_button={should_enable_add_button} - setIsAcuityModalOpen={setIsAcuityModalOpen} real_account_creation_unlock_date={real_account_creation_unlock_date} setShouldShowCooldownModal={setShouldShowCooldownModal} show_eu_related_content={show_eu_related_content} @@ -696,12 +618,11 @@ const CFDDashboard = (props: TCFDDashboardProps) => {
{ derivez_tokens={derivez_tokens} /> - + - {platform === CFD_PLATFORMS.MT5 && is_logged_in && ( - - )} + {platform === CFD_PLATFORMS.MT5 && is_logged_in && } { )} ); -}; +}); -export default withRouter( - connect(({ client, modules, notifications, ui, traders_hub }: RootStore) => ({ - beginRealSignupForMt5: modules.cfd.beginRealSignupForMt5, - checkShouldOpenAccount: modules.cfd.checkShouldOpenAccount, - country: client.account_settings.residence, - client_email: client.email_address, - context: { ui, modules }, - createCFDAccount: modules.cfd.createCFDAccount, - current_list: modules.cfd.current_list, - dxtrade_tokens: modules.cfd.dxtrade_tokens, - derivez_tokens: modules.cfd.derivez_tokens, - landing_companies: client.landing_companies, - isAccountOfTypeDisabled: client.isAccountOfTypeDisabled, - is_logged_in: client.is_logged_in, - is_logging_in: client.is_logging_in, - is_eu: client.is_eu, - is_eu_country: client.is_eu_country, - is_virtual: client.is_virtual, - is_mt5_allowed: client.is_mt5_allowed, - is_dxtrade_allowed: client.is_dxtrade_allowed, - mt5_disabled_signup_types: client.mt5_disabled_signup_types, - dxtrade_disabled_signup_types: client.dxtrade_disabled_signup_types, - has_maltainvest_account: client.has_maltainvest_account, - can_upgrade_to: client.can_upgrade_to, - disableCFDPasswordModal: modules.cfd.disableCFDPasswordModal, - dxtrade_accounts_list_error: client.dxtrade_accounts_list_error, - is_compare_accounts_visible: modules.cfd.is_compare_accounts_visible, - is_mt5_trade_modal_visible: modules.cfd.is_mt5_trade_modal_visible, - is_fully_authenticated: client.is_fully_authenticated, - openPasswordModal: modules.cfd.enableCFDPasswordModal, - openAccountNeededModal: ui.openAccountNeededModal, - getRealSyntheticAccountsExistingData: modules.cfd.getRealSyntheticAccountsExistingData, - getRealFinancialAccountsExistingData: modules.cfd.getRealFinancialAccountsExistingData, - is_loading: client.is_populating_mt5_account_list, - residence: client.residence, - has_mt5_real_account_error: client.has_account_error_in_mt5_real_list, - has_mt5_demo_account_error: client.has_account_error_in_mt5_demo_list, - has_dxtrade_real_account_error: client.has_account_error_in_dxtrade_real_list, - has_dxtrade_demo_account_error: client.has_account_error_in_dxtrade_demo_list, - has_real_account: client.has_active_real_account, - setAccountType: modules.cfd.setAccountType, - setCFDPasswordResetModal: ui.setCFDPasswordResetModal, - setCurrentAccount: modules.cfd.setCurrentAccount, - standpoint: client.standpoint, - toggleCompareAccounts: modules.cfd.toggleCompareAccountsModal, - toggleMT5TradeModal: modules.cfd.toggleMT5TradeModal, - is_accounts_switcher_on: ui.is_accounts_switcher_on, - openTopUpModal: ui.openTopUpModal, - NotificationMessages: ui.notification_messages_ui, - onMount: modules.cfd.onMount, - onUnmount: modules.cfd.onUnmount, - refreshNotifications: notifications.refreshNotifications, - toggleAccountsDialog: ui.toggleAccountsDialog, - toggleShouldShowRealAccountsList: ui.toggleShouldShowRealAccountsList, - upgradeable_landing_companies: client.upgradeable_landing_companies, - is_dark_mode_on: ui.is_dark_mode_on, - disableApp: ui.disableApp, - enableApp: ui.enableApp, - is_reset_trading_password_modal_visible: ui.is_reset_trading_password_modal_visible, - toggleResetTradingPasswordModal: ui.setResetTradingPasswordModalOpen, - mt5_verification_code: client.verification_code.trading_platform_mt5_password_reset, - dxtrade_verification_code: client.verification_code.trading_platform_dxtrade_password_reset, - mt5_status_server: client.website_status.mt5_status, - dxtrade_status_server: client.website_status.dxtrade_status, - openDerivRealAccountNeededModal: ui.openDerivRealAccountNeededModal, - setIsAcuityModalOpen: ui.setIsAcuityModalOpen, - setShouldShowCooldownModal: ui.setShouldShowCooldownModal, - real_account_creation_unlock_date: client.real_account_creation_unlock_date, - show_eu_related_content: traders_hub.show_eu_related_content, - is_user_exception: client.account_settings.dxtrade_user_exception, - }))(CFDDashboard) -); +export default CFDDashboard; diff --git a/packages/cfd/src/Containers/cfd-dbvi-onboarding.tsx b/packages/cfd/src/Containers/cfd-dbvi-onboarding.tsx index 5e77900cb668..35899f963d04 100644 --- a/packages/cfd/src/Containers/cfd-dbvi-onboarding.tsx +++ b/packages/cfd/src/Containers/cfd-dbvi-onboarding.tsx @@ -11,13 +11,12 @@ import { UILoader, } from '@deriv/components'; import { localize } from '@deriv/translations'; -import RootStore from '../Stores/index'; import { PoiPoaDocsSubmitted } from '@deriv/account'; -import { connect } from '../Stores/connect'; import { getAuthenticationStatusInfo, isMobile, WS, Jurisdiction } from '@deriv/shared'; import { AccountStatusResponse } from '@deriv/api-types'; -import { TCFDDbviOnboardingProps } from './props.types'; import CFDFinancialStpRealAccountSignup from './cfd-financial-stp-real-account-signup'; +import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; const SwitchToRealAccountMessage = ({ onClickOk }: { onClickOk: () => void }) => (
@@ -37,22 +36,21 @@ const SwitchToRealAccountMessage = ({ onClickOk }: { onClickOk: () => void }) =>
); -const CFDDbviOnboarding = ({ - account_status, - context, - disableApp, - enableApp, - fetchAccountSettings, - has_created_account_for_selected_jurisdiction, - has_submitted_cfd_personal_details, - is_cfd_verification_modal_visible, - is_virtual, - jurisdiction_selected_shortcode, - openPasswordModal, - toggleCFDVerificationModal, - updateAccountStatus, - updateMT5Status, -}: TCFDDbviOnboardingProps) => { +const CFDDbviOnboarding = observer(() => { + const { client, ui } = useStore(); + + const { account_status, fetchAccountSettings, is_virtual, updateAccountStatus, updateMT5Status } = client; + const { disableApp, enableApp } = ui; + + const { + has_created_account_for_selected_jurisdiction, + has_submitted_cfd_personal_details, + is_cfd_verification_modal_visible, + jurisdiction_selected_shortcode, + enableCFDPasswordModal, + toggleCFDVerificationModal, + } = useCfdStore(); + const [showSubmittedModal, setShowSubmittedModal] = React.useState(true); const [is_loading, setIsLoading] = React.useState(false); @@ -104,8 +102,7 @@ const CFDDbviOnboarding = ({ account_status={account_status} jurisdiction_selected_shortcode={jurisdiction_selected_shortcode} has_created_account_for_selected_jurisdiction={has_created_account_for_selected_jurisdiction} - openPasswordModal={openPasswordModal} - context={context} + openPasswordModal={enableCFDPasswordModal} /> ) : ( ); }; @@ -140,7 +136,6 @@ const CFDDbviOnboarding = ({ toggleModal={toggleCFDVerificationModal} height='700px' width='996px' - context={context} onMount={() => getAccountStatusFromAPI()} exit_classname='cfd-modal--custom-exit' > @@ -154,29 +149,12 @@ const CFDDbviOnboarding = ({ wrapper_classname='cfd-financial-stp-modal' visible={is_cfd_verification_modal_visible} onClose={toggleCFDVerificationModal} - context={context} > {getModalContent()} ); -}; +}); -export default connect(({ client, modules: { cfd }, ui }: RootStore) => ({ - account_status: client.account_status, - account_type: cfd.account_type, - disableApp: ui.disableApp, - enableApp: ui.enableApp, - fetchAccountSettings: client.fetchAccountSettings, - has_created_account_for_selected_jurisdiction: cfd.has_created_account_for_selected_jurisdiction, - has_submitted_cfd_personal_details: cfd.has_submitted_cfd_personal_details, - is_cfd_verification_modal_visible: cfd.is_cfd_verification_modal_visible, - is_virtual: client.is_virtual, - jurisdiction_selected_shortcode: cfd.jurisdiction_selected_shortcode, - mt5_login_list: client.mt5_login_list, - openPasswordModal: cfd.enableCFDPasswordModal, - toggleCFDVerificationModal: cfd.toggleCFDVerificationModal, - updateAccountStatus: client.updateAccountStatus, - updateMT5Status: client.updateMT5Status, -}))(CFDDbviOnboarding); +export default CFDDbviOnboarding; diff --git a/packages/cfd/src/Containers/cfd-financial-stp-real-account-signup.tsx b/packages/cfd/src/Containers/cfd-financial-stp-real-account-signup.tsx index 08f9b4fa3c01..8f34449b3e2e 100644 --- a/packages/cfd/src/Containers/cfd-financial-stp-real-account-signup.tsx +++ b/packages/cfd/src/Containers/cfd-financial-stp-real-account-signup.tsx @@ -1,69 +1,85 @@ import React from 'react'; import { Div100vhContainer } from '@deriv/components'; import { isDesktop, getAuthenticationStatusInfo, Jurisdiction } from '@deriv/shared'; -import { connect } from '../Stores/connect'; -import { LandingCompany, ResidenceList, GetSettings, StatesList, GetAccountStatus } from '@deriv/api-types'; import CFDPOA from '../Components/cfd-poa'; import CFDPOI from '../Components/cfd-poi'; import CFDPersonalDetailsContainer from './cfd-personal-details-container'; -import RootStore from '../Stores/index'; - -type TAuthenticationStatus = { document_status: string; identity_status: string }; - -type TStoreProofOfAddressArgs = { - file_uploader_ref: HTMLDivElement | null; - values: { [key: string]: string }; -}; - -type TRemoveNotificationMessage = { - key: string; - should_show_again: boolean; -}; - -type TGetSettings = GetSettings & { - upload_file?: string; - poi_state?: string; -}; +import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; +import { TCoreStores } from '@deriv/stores/types'; type TCFDFinancialStpRealAccountSignupProps = { - addNotificationByKey: (key: string) => void; - authentication_status: TAuthenticationStatus; - get_settings: TGetSettings; - client_email: string; - context: RootStore; - is_fully_authenticated: boolean; - landing_company: LandingCompany; - refreshNotifications: () => void; - removeNotificationMessage: () => void; - removeNotificationByKey: (args: TRemoveNotificationMessage) => void; - residence_list: ResidenceList; - states_list: StatesList; - storeProofOfAddress: TStoreProofOfAddressArgs; - fetchStatesList: () => void; - account_status: GetAccountStatus; onFinish: () => void; - jurisdiction_selected_shortcode: string; - has_submitted_cfd_personal_details: boolean; }; type TNextStep = (index: number, value: { [key: string]: string | undefined }) => void; -type TItemsState = { +type TItem = { + refreshNotifications: TCoreStores['notifications']['refreshNotifications']; + removeNotificationMessage: TCoreStores['notifications']['removeNotificationMessage']; + removeNotificationByKey: TCoreStores['notifications']['removeNotificationByKey']; + addNotificationMessageByKey: TCoreStores['notifications']['addNotificationMessageByKey']; + authentication_status: TCoreStores['client']['authentication_status']; + account_settings: TCoreStores['client']['account_settings']; + email: TCoreStores['client']['email']; + is_fully_authenticated: TCoreStores['client']['is_fully_authenticated']; + landing_company: TCoreStores['client']['landing_company']; + residence_list: TCoreStores['client']['residence_list']; + states_list: TCoreStores['client']['states_list']; + fetchStatesList: TCoreStores['client']['fetchStatesList']; + account_status: TCoreStores['client']['account_status']; + storeProofOfAddress: TCoreStores['modules']['cfd']['storeProofOfAddress']; + jurisdiction_selected_shortcode: TCoreStores['modules']['cfd']['jurisdiction_selected_shortcode']; + has_submitted_cfd_personal_details: TCoreStores['modules']['cfd']['has_submitted_cfd_personal_details']; + onFinish: TCFDFinancialStpRealAccountSignupProps['onFinish']; +}; + +type TItemsState = { body: typeof CFDPOI | typeof CFDPOA | typeof CFDPersonalDetailsContainer; form_value: { [key: string]: string | undefined }; - forwarded_props: Array>; + forwarded_props: Array>; }; -const CFDFinancialStpRealAccountSignup = (props: TCFDFinancialStpRealAccountSignupProps) => { +const CFDFinancialStpRealAccountSignup = observer(({ onFinish }: TCFDFinancialStpRealAccountSignupProps) => { + const { notifications, client } = useStore(); + + const { refreshNotifications, removeNotificationMessage, removeNotificationByKey, addNotificationMessageByKey } = + notifications; + const { - account_status, authentication_status, + account_settings, + email, + is_fully_authenticated, + landing_company, + residence_list, + states_list, fetchStatesList, - get_settings, + account_status, + } = client; + + const { storeProofOfAddress, jurisdiction_selected_shortcode, has_submitted_cfd_personal_details } = useCfdStore(); + + const passthroughProps = { refreshNotifications, - has_submitted_cfd_personal_details, + removeNotificationMessage, + removeNotificationByKey, + addNotificationMessageByKey, + authentication_status, + account_settings, + email, + is_fully_authenticated, + landing_company, + residence_list, + states_list, + fetchStatesList, + account_status, + storeProofOfAddress, jurisdiction_selected_shortcode, - } = props; + has_submitted_cfd_personal_details, + onFinish, + } as const; + const [step, setStep] = React.useState(0); const [form_error, setFormError] = React.useState(''); const state_index = step; @@ -71,13 +87,13 @@ const CFDFinancialStpRealAccountSignup = (props: TCFDFinancialStpRealAccountSign const { need_poi_for_vanuatu_maltainvest, need_poi_for_bvi_labuan } = getAuthenticationStatusInfo(account_status); - const poi_config: TItemsState = { + const poi_config: TItemsState = { body: CFDPOI, form_value: { poi_state: 'unknown', }, forwarded_props: [ - 'addNotificationByKey', + 'addNotificationMessageByKey', 'authentication_status', 'refreshNotifications', 'removeNotificationMessage', @@ -86,20 +102,20 @@ const CFDFinancialStpRealAccountSignup = (props: TCFDFinancialStpRealAccountSign ], }; - const poa_config: TItemsState = { + const poa_config: TItemsState = { body: CFDPOA, form_value: { - address_line_1: get_settings.address_line_1, - address_line_2: get_settings.address_line_2, - address_city: get_settings.address_city, - address_state: get_settings.address_state, - address_postcode: get_settings.address_postcode, + address_line_1: account_settings.address_line_1, + address_line_2: account_settings.address_line_2, + address_city: account_settings.address_city, + address_state: account_settings.address_state, + address_postcode: account_settings.address_postcode, upload_file: '', }, - forwarded_props: ['states_list', 'get_settings', 'storeProofOfAddress', 'refreshNotifications'], + forwarded_props: ['states_list', 'account_settings', 'storeProofOfAddress', 'refreshNotifications'], }; - const personal_details_config: TItemsState = { + const personal_details_config: TItemsState = { body: CFDPersonalDetailsContainer, form_value: { citizen: '', @@ -128,7 +144,7 @@ const CFDFinancialStpRealAccountSignup = (props: TCFDFinancialStpRealAccountSign ...(should_show_personal_details ? [personal_details_config] : []), ]; - const [items, setItems] = React.useState(verification_configs); + const [items, setItems] = React.useState[]>(verification_configs); const clearError = () => { setFormError(''); @@ -144,12 +160,12 @@ const CFDFinancialStpRealAccountSignup = (props: TCFDFinancialStpRealAccountSign const unmount = () => { is_mounted = false; - props.onFinish(); + onFinish(); }; const saveFormData = (index: number, value: { [key: string]: string | undefined }) => { if (!is_mounted) return; // avoiding state update on unmounted component - const cloned_items: TItemsState[] = [...items]; + const cloned_items: TItemsState[] = [...items]; cloned_items[index].form_value = value; setItems(cloned_items); }; @@ -169,7 +185,7 @@ const CFDFinancialStpRealAccountSignup = (props: TCFDFinancialStpRealAccountSign } else unmount(); }; - const getCurrent = (key?: keyof TItemsState) => { + const getCurrent = (key?: keyof TItemsState) => { return key ? items[state_index][key] : items[state_index]; }; @@ -177,14 +193,13 @@ const CFDFinancialStpRealAccountSignup = (props: TCFDFinancialStpRealAccountSign const form_value = getCurrent('form_value'); - const passthrough = ((getCurrent('forwarded_props') || []) as TItemsState['forwarded_props']).reduce( - (forwarded_prop, item) => { - return Object.assign(forwarded_prop, { - [item]: props[item], - }); - }, - {} - ); + const passthrough = ( + (getCurrent('forwarded_props') || []) as TItemsState['forwarded_props'] + ).reduce((forwarded_prop, item) => { + return Object.assign(forwarded_prop, { + [item]: passthroughProps[item], + }); + }, {}); return (
); -}; +}); -export default connect(({ client, modules: { cfd }, notifications }: RootStore) => ({ - addNotificationByKey: notifications.addNotificationMessageByKey, - authentication_status: client.authentication_status, - get_settings: client.account_settings, - client_email: client.email, - is_fully_authenticated: client.is_fully_authenticated, - landing_company: client.landing_company, - refreshNotifications: notifications.refreshNotifications, - removeNotificationMessage: notifications.removeNotificationMessage, - removeNotificationByKey: notifications.removeNotificationByKey, - residence_list: client.residence_list, - states_list: client.states_list, - fetchStatesList: client.fetchStatesList, - storeProofOfAddress: cfd.storeProofOfAddress, - account_status: client.account_status, - jurisdiction_selected_shortcode: cfd.jurisdiction_selected_shortcode, - has_submitted_cfd_personal_details: cfd.has_submitted_cfd_personal_details, -}))(CFDFinancialStpRealAccountSignup); +export default CFDFinancialStpRealAccountSignup; diff --git a/packages/cfd/src/Containers/cfd-password-manager-modal.tsx b/packages/cfd/src/Containers/cfd-password-manager-modal.tsx index 182a8298af39..f7a8b9a9f570 100644 --- a/packages/cfd/src/Containers/cfd-password-manager-modal.tsx +++ b/packages/cfd/src/Containers/cfd-password-manager-modal.tsx @@ -23,11 +23,9 @@ import { CFD_PLATFORMS, } from '@deriv/shared'; import { FormikErrors } from 'formik'; -import { connect } from '../Stores/connect'; import CFDStore from '../Stores/Modules/CFD/cfd-store'; import TradingPasswordManager from './trading-password-manager'; import InvestorPasswordManager from './investor-password-manager'; -import RootStore from '../Stores/index'; import { TCountdownComponent, TCFDPasswordReset, @@ -37,6 +35,8 @@ import { TFormValues, TPasswordManagerModalFormValues, } from './props.types'; +import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; const CountdownComponent = ({ count_from = 60, onTimeout }: TCountdownComponent) => { const [count, setCount] = React.useState(count_from); @@ -66,7 +66,6 @@ const CFDPasswordReset = ({ account_type, account_group, server, - context, password_type, }: TCFDPasswordReset) => { const [is_resend_verification_requested, setResendVerification] = React.useState(false); @@ -156,7 +155,6 @@ const CFDPasswordManagerTabContent = ({ setPasswordType, multi_step_ref, platform, - context, onChangeActiveTabIndex, account_group, }: TCFDPasswordManagerTabContent) => { @@ -291,111 +289,107 @@ const CFDPasswordManagerTabContent = ({ ); }; -const CFDPasswordManagerModal = ({ - enableApp, - email, - disableApp, - is_visible, - platform, - context, - selected_login, - toggleModal, - selected_account_type, - selected_account_group, - selected_server, - sendVerifyEmail, -}: TCFDPasswordManagerModal) => { - const multi_step_ref: React.MutableRefObject = React.useRef(); - const [index, setIndex] = React.useState(0); +const CFDPasswordManagerModal = observer( + ({ + is_visible, + platform, + selected_login, + toggleModal, + selected_account_type, + selected_account_group, + selected_server, + }: TCFDPasswordManagerModal) => { + const { client, ui } = useStore(); - const [password_type, setPasswordType] = React.useState('main'); + const { email } = client; + const { enableApp, disableApp } = ui; - if (!selected_login) return null; + const { sendVerifyEmail } = useCfdStore(); - const getTitle = () => { - return localize('Manage {{platform}} password', { - platform: getCFDPlatformLabel(platform), - }); - }; + const multi_step_ref: React.MutableRefObject = React.useRef(); + const [index, setIndex] = React.useState(0); + + const [password_type, setPasswordType] = React.useState('main'); + + if (!selected_login) return null; - const getHeader = (i: number) => { - if (i === 0) { + const getTitle = () => { return localize('Manage {{platform}} password', { platform: getCFDPlatformLabel(platform), }); - } - return localize('Manage password'); - }; + }; - const onChangeActiveTabIndex = (i: number) => { - setIndex(i); - }; + const getHeader = (i: number) => { + if (i === 0) { + return localize('Manage {{platform}} password', { + platform: getCFDPlatformLabel(platform), + }); + } + return localize('Manage password'); + }; - const steps = [ - { - component: ( - - ), - }, - { - component: ( - - ), - }, - ]; + const onChangeActiveTabIndex = (i: number) => { + setIndex(i); + }; - return ( - }> - - - - - - - - - - - - ); -}; + const steps = [ + { + component: ( + + ), + }, + { + component: ( + + ), + }, + ]; + + return ( + }> + + + + + + + + + + + + ); + } +); -export default connect(({ modules: { cfd }, client, ui }: RootStore) => ({ - email: client.email, - enableApp: ui.enableApp, - disableApp: ui.disableApp, - is_eu: client.is_eu, - sendVerifyEmail: cfd.sendVerifyEmail, -}))(CFDPasswordManagerModal); +export default CFDPasswordManagerModal; diff --git a/packages/cfd/src/Containers/cfd-password-modal.tsx b/packages/cfd/src/Containers/cfd-password-modal.tsx index 582efee1345d..6dc0a6e07537 100644 --- a/packages/cfd/src/Containers/cfd-password-modal.tsx +++ b/packages/cfd/src/Containers/cfd-password-modal.tsx @@ -1,9 +1,7 @@ import { Formik, FormikErrors, FormikHelpers } from 'formik'; import React from 'react'; -import { RouteComponentProps, withRouter } from 'react-router'; +import { useHistory } from 'react-router'; import { SentEmailModal } from '@deriv/account'; -import { DetailsOfEachMT5Loginid, GetAccountStatus, LandingCompany, Mt5NewAccount } from '@deriv/api-types'; -import RootStore from '../Stores/index'; import { getDxCompanies, getMtCompanies, @@ -38,18 +36,15 @@ import { WS, } from '@deriv/shared'; import { localize, Localize } from '@deriv/translations'; -import SuccessDialog from '../Components/success-dialog'; -import 'Sass/cfd.scss'; -import { connect } from '../Stores/connect'; +import SuccessDialog from '../Components/success-dialog.jsx'; +import '../sass/cfd.scss'; import ChangePasswordConfirmation from './cfd-change-password-confirmation'; import TradingPlatformIcon from '../Assets/svgs/trading-platform'; +import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; export type TCFDPasswordFormValues = { password: string }; -type TExtendedDetailsOfEachMT5Loginid = Omit & { - market_type?: 'synthetic' | 'financial' | 'gaming' | 'all'; -}; - type TOnSubmitPassword = (values: TCFDPasswordFormValues, actions: FormikHelpers) => void; type TPasswordModalHeaderProps = { @@ -57,7 +52,6 @@ type TPasswordModalHeaderProps = { is_password_reset_error: boolean; platform: string; has_mt5_account?: boolean; - context: RootStore; }; type TIconTypeProps = { @@ -68,21 +62,18 @@ type TIconTypeProps = { type TCFDPasswordFormReusedProps = { platform: string; - context: RootStore; error_message: string; validatePassword: (values: TCFDPasswordFormValues) => FormikErrors; }; type TCFDCreatePasswordProps = TCFDPasswordFormReusedProps & { password: string; - context: RootStore; onSubmit: TOnSubmitPassword; is_real_financial_stp: boolean; }; type TCFDCreatePasswordFormProps = TCFDPasswordFormReusedProps & { has_mt5_account: boolean; - context: RootStore; submitPassword: TOnSubmitPassword; is_real_financial_stp: boolean; }; @@ -104,7 +95,6 @@ type TCFDPasswordFormProps = TCFDPasswordFormReusedProps & { type?: string; }; closeModal: () => void; - context: RootStore; error_type?: string; form_error?: string; has_mt5_account: boolean; @@ -119,41 +109,10 @@ type TCFDPasswordFormProps = TCFDPasswordFormReusedProps & { submitPassword: TOnSubmitPassword; }; -type TCFDPasswordModalProps = RouteComponentProps & { - account_title: string; - context: RootStore; - account_type: { - category?: string; - type?: string; - }; - account_status: GetAccountStatus; - disableCFDPasswordModal: () => void; - email: string; - error_message: string; +type TCFDPasswordModalProps = { error_type?: string; form_error?: string; - getAccountStatus: (platform: string) => void; - is_eu: boolean; - is_logged_in: boolean; - is_fully_authenticated: boolean; - is_cfd_password_modal_enabled: boolean; - is_cfd_success_dialog_enabled: boolean; - is_dxtrade_allowed: boolean; - jurisdiction_selected_shortcode: string; platform: string; - has_cfd_error: boolean; - landing_companies: LandingCompany; - mt5_login_list: TExtendedDetailsOfEachMT5Loginid[]; - cfd_new_account: Mt5NewAccount; - setCFDSuccessDialog: (value: boolean) => void; - setMt5Error: (state: boolean, obj?: Error) => void; - show_eu_related_content: boolean; - submitMt5Password: (values: TCFDPasswordFormValues, actions: FormikHelpers) => void; - submitCFDPassword: ( - values: TCFDPasswordFormValues & { platform?: string }, - actions: FormikHelpers - ) => void; - updateAccountStatus: () => void; }; const getAccountTitle = ( @@ -286,7 +245,6 @@ const CreatePassword = ({ password, platform, validatePassword, - context, onSubmit, error_message, is_real_financial_stp, @@ -340,7 +298,6 @@ const CreatePassword = ({
@@ -377,7 +334,6 @@ const CreatePassword = ({ platform: getCFDPlatformLabel(platform), })} is_center={true} - context={context} />
@@ -390,7 +346,6 @@ const CFDCreatePasswordForm = ({ has_mt5_account, platform, error_message, - context, validatePassword, submitPassword, is_real_financial_stp, @@ -412,7 +367,6 @@ const CFDCreatePasswordForm = ({ component: ( multi_step_ref.current?.goPrevStep()} - context={context} /> ), }, @@ -443,7 +396,6 @@ const CFDPasswordForm = ({ account_title, account_type, closeModal, - context, error_message, error_type, form_error, @@ -496,7 +448,6 @@ const CFDPasswordForm = ({ has_cancel={has_cancel_button} cancel_label={cancel_button_label} onCancel={handleCancel} - context={context} is_absolute={isMobile()} label={button_label} /> @@ -512,7 +463,6 @@ const CFDPasswordForm = ({ return ( @@ -643,35 +592,40 @@ const CFDPasswordForm = ({ ); }; -const CFDPasswordModal = ({ - account_title, - account_type, - account_status, - disableCFDPasswordModal, - email, - error_message, - error_type, - form_error, - getAccountStatus, - history, - is_logged_in, - context, - is_cfd_password_modal_enabled, - is_cfd_success_dialog_enabled, - is_dxtrade_allowed, - jurisdiction_selected_shortcode, - platform, - has_cfd_error, - landing_companies, - mt5_login_list, - cfd_new_account, - setCFDSuccessDialog, - setMt5Error, - submitMt5Password, - submitCFDPassword, - updateAccountStatus, - show_eu_related_content, -}: TCFDPasswordModalProps) => { +const CFDPasswordModal = observer(({ form_error, platform }: TCFDPasswordModalProps) => { + const { client, traders_hub } = useStore(); + + const { + email, + account_status, + landing_companies, + is_logged_in, + is_dxtrade_allowed, + mt5_login_list, + updateAccountStatus, + } = client; + const { show_eu_related_content } = traders_hub; + + const { + account_title, + account_type, + disableCFDPasswordModal, + error_message, + error_type, + getAccountStatus, + has_cfd_error, + is_cfd_success_dialog_enabled, + is_cfd_password_modal_enabled, + jurisdiction_selected_shortcode, + setError, + setCFDSuccessDialog, + submitMt5Password, + submitCFDPassword, + new_account_response, + } = useCfdStore(); + + const history = useHistory(); + const [is_password_modal_exited, setPasswordModalExited] = React.useState(true); const is_bvi = landing_companies?.mt_financial_company?.financial_stp?.shortcode === 'bvi'; const has_mt5_account = Boolean(mt5_login_list?.length); @@ -745,7 +699,7 @@ const CFDPasswordModal = ({ const closeDialogs = () => { setCFDSuccessDialog(false); - setMt5Error(false); + setError(false); }; const closeModal = () => { @@ -757,7 +711,7 @@ const CFDPasswordModal = ({ disableCFDPasswordModal(); closeDialogs(); if (account_type.category === 'real') { - sessionStorage.setItem('cfd_transfer_to_login_id', cfd_new_account.login || ''); + sessionStorage.setItem('cfd_transfer_to_login_id', new_account_response.login || ''); history.push(routes.cashier_acc_transfer); } }; @@ -926,7 +880,6 @@ const CFDPasswordModal = ({ const cfd_password_form = ( )} onUnmount={() => getAccountStatus(platform)} @@ -984,7 +936,6 @@ const CFDPasswordModal = ({ has_mt5_account={has_mt5_account} is_password_reset_error={is_password_reset} platform={platform} - context={context} /> {cfd_password_form} @@ -1028,33 +979,6 @@ const CFDPasswordModal = ({ /> ); -}; +}); -export default connect(({ client, modules, traders_hub }: RootStore) => ({ - email: client.email, - account_title: modules.cfd.account_title, - account_type: modules.cfd.account_type, - account_status: client.account_status, - disableCFDPasswordModal: modules.cfd.disableCFDPasswordModal, - error_message: modules.cfd.error_message, - error_type: modules.cfd.error_type, - getAccountStatus: modules.cfd.getAccountStatus, - has_cfd_error: modules.cfd.has_cfd_error, - landing_companies: client.landing_companies, - is_eu: client.is_eu, - is_eu_country: client.is_eu_country, - is_logged_in: client.is_logged_in, - is_cfd_success_dialog_enabled: modules.cfd.is_cfd_success_dialog_enabled, - is_cfd_password_modal_enabled: modules.cfd.is_cfd_password_modal_enabled, - is_dxtrade_allowed: client.is_dxtrade_allowed, - jurisdiction_selected_shortcode: modules.cfd.jurisdiction_selected_shortcode, - setMt5Error: modules.cfd.setError, - setCFDSuccessDialog: modules.cfd.setCFDSuccessDialog, - submitMt5Password: modules.cfd.submitMt5Password, - submitCFDPassword: modules.cfd.submitCFDPassword, - cfd_new_account: modules.cfd.new_account_response, - mt5_trading_servers: client.mt5_trading_servers, - mt5_login_list: client.mt5_login_list, - updateAccountStatus: client.updateAccountStatus, - show_eu_related_content: traders_hub.show_eu_related_content, -}))(withRouter(CFDPasswordModal)); +export default CFDPasswordModal; diff --git a/packages/cfd/src/Containers/cfd-personal-details-container.tsx b/packages/cfd/src/Containers/cfd-personal-details-container.tsx index 7a5b3d9836e3..508c70d32f42 100644 --- a/packages/cfd/src/Containers/cfd-personal-details-container.tsx +++ b/packages/cfd/src/Containers/cfd-personal-details-container.tsx @@ -1,25 +1,20 @@ import React from 'react'; import { DesktopWrapper, Div100vhContainer, MobileWrapper, Text } from '@deriv/components'; import { localize } from '@deriv/translations'; -import { connect } from '../Stores/connect'; -import RootStore from '../Stores/index'; import { TCFDPersonalDetailsContainerProps } from './props.types'; import CFDPersonalDetailsForm from '../Components/cfd-personal-details-form'; import { getPropertyValue, isDesktop, WS } from '@deriv/shared'; import { GetSettings } from '@deriv/api-types'; +import { observer, useStore } from '@deriv/stores'; type TFormValues = { [key: string]: string }; type TSetSubmitting = (isSubmitting: boolean) => void; -const CFDPersonalDetailsContainer = ({ - account_settings, - context, - getChangeableFields, - landing_company, - residence_list, - setAccountSettings, - onSubmit, -}: TCFDPersonalDetailsContainerProps) => { +const CFDPersonalDetailsContainer = observer(({ onSubmit }: TCFDPersonalDetailsContainerProps) => { + const { client } = useStore(); + + const { account_settings, getChangeableFields, landing_company, residence_list, setAccountSettings } = client; + const [form_error, setFormError] = React.useState(''); const [is_loading, setIsLoading] = React.useState(false); const [form_values, setFormValues] = React.useState({ @@ -113,7 +108,6 @@ const CFDPersonalDetailsContainer = ({
{getPersonalDetailsForm()} ); -}; +}); -export default connect(({ ui, client }: RootStore) => ({ - account_settings: client.account_settings, - disableApp: ui.disableApp, - enableApp: ui.enableApp, - getChangeableFields: client.getChangeableFields, - landing_company: client.landing_company, - residence_list: client.residence_list, - setAccountSettings: client.setAccountSettings, -}))(CFDPersonalDetailsContainer); +export default CFDPersonalDetailsContainer; diff --git a/packages/cfd/src/Containers/cfd-reset-password-modal.tsx b/packages/cfd/src/Containers/cfd-reset-password-modal.tsx index ab128029f8d5..4b1101d23e07 100644 --- a/packages/cfd/src/Containers/cfd-reset-password-modal.tsx +++ b/packages/cfd/src/Containers/cfd-reset-password-modal.tsx @@ -1,16 +1,14 @@ -import PropTypes from 'prop-types'; import { Formik, FormikHelpers } from 'formik'; -import RootStore from '../Stores/index'; import React from 'react'; -import { withRouter } from 'react-router-dom'; import { Button, Icon, PasswordMeter, PasswordInput, FormSubmitButton, Loading, Modal, Text } from '@deriv/components'; import { validLength, validPassword, getErrorMessages, CFD_PLATFORMS, WS, redirectToLogin } from '@deriv/shared'; import { localize, Localize, getLanguage } from '@deriv/translations'; -import { connect } from '../Stores/connect'; import { getMtCompanies, TMtCompanies } from '../Stores/Modules/CFD/Helpers/cfd-config'; import { TResetPasswordIntent, TCFDResetPasswordModal, TError } from './props.types'; +import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; -const ResetPasswordIntent = ({ current_list, context, children, is_eu, ...props }: TResetPasswordIntent) => { +const ResetPasswordIntent = ({ current_list, children, is_eu, ...props }: TResetPasswordIntent) => { const reset_password_intent = localStorage.getItem('cfd_reset_password_intent'); const reset_password_type = localStorage.getItem('cfd_reset_password_type') || 'main'; // Default to main const has_intent = @@ -44,16 +42,14 @@ const ResetPasswordIntent = ({ current_list, context, children, is_eu, ...props }); }; -const CFDResetPasswordModal = ({ - current_list, - email, - is_cfd_reset_password_modal_enabled, - is_eu, - context, - is_logged_in, - platform, - setCFDPasswordResetModal, -}: TCFDResetPasswordModal) => { +const CFDResetPasswordModal = observer(({ platform }: TCFDResetPasswordModal) => { + const { client, ui } = useStore(); + + const { email, is_eu, is_logged_in } = client; + const { is_cfd_reset_password_modal_enabled, setCFDPasswordResetModal } = ui; + + const { current_list } = useCfdStore(); + const [state, setState] = React.useState<{ error_code: string | number | undefined; has_error: boolean; @@ -142,7 +138,6 @@ const CFDResetPasswordModal = ({ return ( setCFDPasswordResetModal(false)} title={ @@ -155,7 +150,7 @@ const CFDResetPasswordModal = ({ > {!getIsListFetched() && !state.has_error && } {getIsListFetched() && !state.has_error && !state.is_finished && ( - + {({ type, login }) => ( ); -}; - -CFDResetPasswordModal.propTypes = { - current_list: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), - email: PropTypes.string, - is_cfd_reset_password_modal_enabled: PropTypes.bool, - is_eu: PropTypes.bool, - is_logged_in: PropTypes.bool, - platform: PropTypes.string, - setCFDPasswordResetModal: PropTypes.func, - history: PropTypes.object, - context: PropTypes.object, -}; +}); -export default React.memo( - withRouter( - connect(({ modules: { cfd }, client, ui }: RootStore) => ({ - email: client.email, - is_eu: client.is_eu, - is_cfd_reset_password_modal_enabled: ui.is_cfd_reset_password_modal_enabled, - setCFDPasswordResetModal: ui.setCFDPasswordResetModal, - current_list: cfd.current_list, - is_logged_in: client.is_logged_in, - }))(CFDResetPasswordModal) - ) -); +export default React.memo(CFDResetPasswordModal); diff --git a/packages/cfd/src/Containers/cfd-server-error-dialog.tsx b/packages/cfd/src/Containers/cfd-server-error-dialog.tsx index f05f336b6a51..8e29dfb63b8c 100644 --- a/packages/cfd/src/Containers/cfd-server-error-dialog.tsx +++ b/packages/cfd/src/Containers/cfd-server-error-dialog.tsx @@ -2,12 +2,12 @@ import React from 'react'; import { Dialog, UnhandledErrorModal } from '@deriv/components'; import { localize } from '@deriv/translations'; import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; const CFDServerErrorDialog = observer(() => { - const { ui, modules } = useStore(); + const { ui } = useStore(); const { enableApp, disableApp } = ui; - const { cfd } = modules; - const { clearCFDError, error_message, error_type, has_cfd_error, is_cfd_success_dialog_enabled } = cfd; + const { clearCFDError, error_message, error_type, has_cfd_error, is_cfd_success_dialog_enabled } = useCfdStore(); const should_show_error = has_cfd_error && diff --git a/packages/cfd/src/Containers/cfd-top-up-demo-modal.tsx b/packages/cfd/src/Containers/cfd-top-up-demo-modal.tsx index 136efc99b972..16b750ad3d44 100644 --- a/packages/cfd/src/Containers/cfd-top-up-demo-modal.tsx +++ b/packages/cfd/src/Containers/cfd-top-up-demo-modal.tsx @@ -3,47 +3,28 @@ import SuccessDialog from '../Components/success-dialog.jsx'; import { Icon, Modal, Button, Money, Text } from '@deriv/components'; import { getCFDPlatformLabel, CFD_PLATFORMS } from '@deriv/shared'; import { localize, Localize } from '@deriv/translations'; -import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; -import RootStore from '../Stores/index'; -import { connect } from '../Stores/connect'; import { TDxCompanies, TMtCompanies, TDerivezCompanies } from '../Stores/Modules/CFD/Helpers/cfd-config'; import { getTopUpConfig } from '../Helpers/constants'; - -type TExtendedCurrentAccount = DetailsOfEachMT5Loginid & { - display_login: string; - category: string; - type: string; -}; +import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; type TCFDTopUpDemoModalProps = { - dxtrade_companies: TDxCompanies; - derivez_companies: TDerivezCompanies; - mt5_companies: TMtCompanies; - current_account?: TExtendedCurrentAccount; - closeSuccessTopUpModal: () => void; - closeTopUpModal: () => void; - is_top_up_virtual_open: boolean; - is_top_up_virtual_in_progress: boolean; - is_top_up_virtual_success: boolean; - context: RootStore; platform: string; - topUpVirtual: (platform: string) => void; }; -const CFDTopUpDemoModal = ({ - dxtrade_companies, - derivez_companies, - mt5_companies, - current_account, - closeSuccessTopUpModal, - closeTopUpModal, - is_top_up_virtual_open, - is_top_up_virtual_in_progress, - is_top_up_virtual_success, - platform, - context, - topUpVirtual, -}: TCFDTopUpDemoModalProps) => { +const CFDTopUpDemoModal = observer(({ platform }: TCFDTopUpDemoModalProps) => { + const { ui } = useStore(); + + const { + is_top_up_virtual_open, + is_top_up_virtual_in_progress, + is_top_up_virtual_success, + closeTopUpModal, + closeSuccessTopUpModal, + } = ui; + + const { current_account, dxtrade_companies, derivez_companies, mt5_companies, topUpVirtual } = useCfdStore(); + const getAccountTitle = React.useCallback(() => { let title = ''; if ((!mt5_companies && !dxtrade_companies && !derivez_companies) || !current_account) return ''; @@ -88,7 +69,6 @@ const CFDTopUpDemoModal = ({ ); -}; +}); -export default connect(({ ui, modules }: RootStore) => ({ - is_top_up_virtual_open: ui.is_top_up_virtual_open, - is_top_up_virtual_in_progress: ui.is_top_up_virtual_in_progress, - is_top_up_virtual_success: ui.is_top_up_virtual_success, - closeTopUpModal: ui.closeTopUpModal, - closeSuccessTopUpModal: ui.closeSuccessTopUpModal, - current_account: modules.cfd.current_account, - dxtrade_companies: modules.cfd.dxtrade_companies, - mt5_companies: modules.cfd.mt5_companies, - derivez_companies: modules.cfd.derivez_companies, - topUpVirtual: modules.cfd.topUpVirtual, -}))(CFDTopUpDemoModal); +export default CFDTopUpDemoModal; diff --git a/packages/cfd/src/Containers/compare-accounts-modal.tsx b/packages/cfd/src/Containers/compare-accounts-modal.tsx old mode 100644 new mode 100755 index 807f1998c42f..095e070602e1 --- a/packages/cfd/src/Containers/compare-accounts-modal.tsx +++ b/packages/cfd/src/Containers/compare-accounts-modal.tsx @@ -1,19 +1,16 @@ import React from 'react'; import { Button, Modal, DesktopWrapper, MobileDialog, MobileWrapper, UILoader } from '@deriv/components'; import { localize } from '@deriv/translations'; -import { connect } from '../Stores/connect'; -import RootStore from '../Stores/index'; import { CFD_PLATFORMS, isLandingCompanyEnabled, ContentFlag } from '@deriv/shared'; -import { LandingCompany } from '@deriv/api-types'; import ModalContent from './compare-accounts-content'; import DMT5CompareModalContent from './mt5-compare-table-content'; import CfdDxtradeCompareContent from '../Components/cfd-dxtrade-compare-content'; +import { observer, useStore } from '@deriv/stores'; +import { LandingCompany } from '@deriv/api-types'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; type TCompareAccountsReusedProps = { - landing_companies: LandingCompany; platform: string; - is_logged_in: boolean; - is_uk: boolean; }; type TOpenAccountTransferMeta = { @@ -22,28 +19,12 @@ type TOpenAccountTransferMeta = { }; type TCompareAccountsModalProps = TCompareAccountsReusedProps & { - disableApp: () => void; - enableApp: () => void; - is_compare_accounts_visible: boolean; - is_loading: boolean; - is_eu: boolean; is_real_enabled: boolean; - residence: string; is_demo_tab: boolean; has_unmerged_account: boolean; - toggleCompareAccounts: () => void; openPasswordModal: (account_type: TOpenAccountTransferMeta) => void; - openDerivRealAccountNeededModal: () => void; - context: RootStore; real_account_creation_unlock_date: string; - show_eu_related_content: boolean; setShouldShowCooldownModal: (value: boolean) => void; - is_eu_user: string; - is_cr_demo_account: boolean; - upgradeable_landing_companies: unknown[]; - landing_company_shortcode: string; - content_flag: string; - CFDs_restricted_countries: string[]; }; type TDxtradeCompareAccountContent = TCompareAccountsReusedProps & { @@ -52,6 +33,9 @@ type TDxtradeCompareAccountContent = TCompareAccountsReusedProps & { has_unmerged_account: boolean; residence: string; is_eu: boolean; + is_logged_in: boolean; + is_uk: boolean; + landing_companies: LandingCompany; }; // TODO: Remove this component and use one component for both when real released. @@ -93,221 +77,206 @@ const DxtradeCompareAccountContent = ({ ); }; -const CompareAccountsModal = ({ - context, - disableApp, - enableApp, - has_unmerged_account, - is_compare_accounts_visible, - is_demo_tab, - is_eu, - is_loading, - is_logged_in, - is_real_enabled, - is_uk, - landing_companies, - openDerivRealAccountNeededModal, - openPasswordModal, - platform, - real_account_creation_unlock_date, - residence, - setShouldShowCooldownModal, - toggleCompareAccounts, - content_flag, - show_eu_related_content, - CFDs_restricted_countries, -}: TCompareAccountsModalProps) => { - const location = window.location.pathname; - const is_pre_appstore_setting = location.startsWith('/appstore/traders-hub'); +const CompareAccountsModal = observer( + ({ + has_unmerged_account, + is_demo_tab, + is_real_enabled, + openPasswordModal, + platform, + real_account_creation_unlock_date, + setShouldShowCooldownModal, + }: TCompareAccountsModalProps) => { + const { ui, client, traders_hub } = useStore(); - // TODO : should change the type to all after changing derivx api - const has_derivx = - isLandingCompanyEnabled({ + const { disableApp, enableApp, openDerivRealAccountNeededModal } = ui; + const { + is_populating_mt5_account_list: is_loading, + is_eu, + is_uk, + is_logged_in, landing_companies, - platform: CFD_PLATFORMS.DXTRADE, - type: 'financial', - }) || - isLandingCompanyEnabled({ - landing_companies, - platform: CFD_PLATFORMS.DXTRADE, - type: 'gaming', - }) || - isLandingCompanyEnabled({ - landing_companies, - platform: CFD_PLATFORMS.DXTRADE, - type: 'all', - }); + residence, + } = client; + const { content_flag, show_eu_related_content, CFDs_restricted_countries } = traders_hub; - const should_show_derivx = is_pre_appstore_setting && has_derivx && !show_eu_related_content; + const { is_compare_accounts_visible, toggleCompareAccountsModal } = useCfdStore(); + const location = window.location.pathname; + const is_pre_appstore_setting = location.startsWith('/appstore/traders-hub'); - const show_preappstore_eu_demo = is_pre_appstore_setting && show_eu_related_content && is_demo_tab; - const is_preappstore_cr_demo_account = is_pre_appstore_setting && content_flag === ContentFlag.CR_DEMO; + // TODO : should change the type to all after changing derivx api + const has_derivx = + isLandingCompanyEnabled({ + landing_companies, + platform: CFD_PLATFORMS.DXTRADE, + type: 'financial', + }) || + isLandingCompanyEnabled({ + landing_companies, + platform: CFD_PLATFORMS.DXTRADE, + type: 'gaming', + }) || + isLandingCompanyEnabled({ + landing_companies, + platform: CFD_PLATFORMS.DXTRADE, + type: 'all', + }); - const is_preappstore_restricted_cr_demo_account = - is_pre_appstore_setting && CFDs_restricted_countries && content_flag === ContentFlag.CR_DEMO; + const should_show_derivx = is_pre_appstore_setting && has_derivx && !show_eu_related_content; - const is_dxtrade = platform && platform === CFD_PLATFORMS.DXTRADE; - const mt5_accounts = [ - landing_companies?.mt_gaming_company?.financial, - landing_companies?.mt_financial_company?.financial, - landing_companies?.mt_financial_company?.financial_stp, - ]; + const is_preappstore_cr_demo_account = is_pre_appstore_setting && content_flag === ContentFlag.CR_DEMO; - const cfd_account_button_label = - mt5_accounts.filter(Boolean).length === 1 || - (is_demo_tab && platform === CFD_PLATFORMS.DXTRADE) || - (!has_unmerged_account && platform === CFD_PLATFORMS.DXTRADE) - ? localize('Account Information') - : localize('Compare accounts'); + const is_preappstore_restricted_cr_demo_account = + is_pre_appstore_setting && CFDs_restricted_countries && content_flag === ContentFlag.CR_DEMO; - const getCFDModalTitle = () => { - if (is_pre_appstore_setting && show_eu_related_content) { - return is_demo_tab ? localize('Deriv MT5 CFDs demo account') : localize('Deriv MT5 CFDs real account'); - } else if (should_show_derivx) { - return is_demo_tab ? localize('Compare CFDs demo accounts') : localize('Compare CFDs real accounts'); - } - return is_dxtrade ? cfd_account_button_label : localize('Compare available accounts'); - }; - const getModalStyle = () => { - if (is_dxtrade) { - return { - height: '696px', - width: '903px', - }; - } else if (is_preappstore_cr_demo_account) { - return { - height: '404px', - width: '610px', - }; - } else if (show_eu_related_content) { - if (is_pre_appstore_setting) { - if (content_flag === ContentFlag.EU_DEMO) { + const is_dxtrade = platform && platform === CFD_PLATFORMS.DXTRADE; + const mt5_accounts = [ + landing_companies?.mt_gaming_company?.financial, + landing_companies?.mt_financial_company?.financial, + landing_companies?.mt_financial_company?.financial_stp, + ]; + + const cfd_account_button_label = + mt5_accounts.filter(Boolean).length === 1 || + (is_demo_tab && platform === CFD_PLATFORMS.DXTRADE) || + (!has_unmerged_account && platform === CFD_PLATFORMS.DXTRADE) + ? localize('Account Information') + : localize('Compare accounts'); + + const getCFDModalTitle = () => { + if (is_pre_appstore_setting && show_eu_related_content) { + return is_demo_tab ? localize('Deriv MT5 CFDs demo account') : localize('Deriv MT5 CFDs real account'); + } else if (should_show_derivx) { + return is_demo_tab ? localize('Compare CFDs demo accounts') : localize('Compare CFDs real accounts'); + } + return is_dxtrade ? cfd_account_button_label : localize('Compare available accounts'); + }; + const getModalStyle = () => { + if (is_dxtrade) { + return { + height: '696px', + width: '903px', + }; + } else if (is_preappstore_cr_demo_account) { + return { + height: '404px', + width: '610px', + }; + } else if (show_eu_related_content) { + if (is_pre_appstore_setting) { + if (content_flag === ContentFlag.EU_DEMO) { + return { + height: '350px', + width: '483px', + }; + } return { - height: '350px', + height: '560px', width: '483px', }; } return { - height: '560px', - width: '483px', + height: '525px', + width: '300px', + }; + } else if (is_pre_appstore_setting && should_show_derivx) { + return { + height: '600px', + width: '1115px', }; } return { - height: '525px', - width: '300px', + height: '506px', + width: '996px', }; - } else if (is_pre_appstore_setting && should_show_derivx) { - return { - height: '600px', - width: '1115px', - }; - } - return { - height: '506px', - width: '996px', }; - }; - const getModalContent = () => { - return is_dxtrade ? ( - - ) : ( - - ); - }; + const getModalContent = () => { + return is_dxtrade ? ( + + ) : ( + + ); + }; - return ( - <> -
- {!(is_demo_tab && platform === 'mt5') && !is_pre_appstore_setting && ( -
- - ); -}; + return ( + <> +
+ {!(is_demo_tab && platform === 'mt5') && !is_pre_appstore_setting && ( +
+ + ); + } +); -export default connect(({ modules, ui, client, traders_hub }: RootStore) => ({ - disableApp: ui.disableApp, - enableApp: ui.enableApp, - is_compare_accounts_visible: modules.cfd.is_compare_accounts_visible, - is_loading: client.is_populating_mt5_account_list, - is_eu: client.is_eu, - is_uk: client.is_uk, - is_eu_country: client.is_eu_country, - is_logged_in: client.is_logged_in, - landing_companies: client.landing_companies, - residence: client.residence, - toggleCompareAccounts: modules.cfd.toggleCompareAccountsModal, - openDerivRealAccountNeededModal: ui.openDerivRealAccountNeededModal, - selected_region: traders_hub.selected_region, - is_eu_user: traders_hub.is_eu_user, - content_flag: traders_hub.content_flag, - show_eu_related_content: traders_hub.show_eu_related_content, - CFDs_restricted_countries: traders_hub.CFDs_restricted_countries, -}))(CompareAccountsModal); +export default CompareAccountsModal; diff --git a/packages/cfd/src/Containers/derivx-trade-modal.tsx b/packages/cfd/src/Containers/derivx-trade-modal.tsx index cc8ff412423f..e315b014e48e 100644 --- a/packages/cfd/src/Containers/derivx-trade-modal.tsx +++ b/packages/cfd/src/Containers/derivx-trade-modal.tsx @@ -18,6 +18,7 @@ import { getPlatformDXTradeDownloadLink, getPlatformMt5DownloadLink, } from '../Helpers/constants'; +import { TCFDPasswordReset } from './props.types'; type TDxTradeModalProps = { mt5_trade_account: Required; @@ -25,7 +26,7 @@ type TDxTradeModalProps = { onPasswordManager: ( arg1: string | undefined, arg2: string, - arg3: string, + group: TCFDPasswordReset['account_group'], arg4: string, arg5: string | undefined ) => void; diff --git a/packages/cfd/src/Containers/dmt5-trade-modal.tsx b/packages/cfd/src/Containers/dmt5-trade-modal.tsx index b4e95931b8ee..7a8753cacc8d 100644 --- a/packages/cfd/src/Containers/dmt5-trade-modal.tsx +++ b/packages/cfd/src/Containers/dmt5-trade-modal.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Text, Button, Icon, Money, Popover } from '@deriv/components'; -import { TPasswordBoxProps, TTradingPlatformAccounts, TCFDDashboardContainer } from '../Components/props.types'; +import { TPasswordBoxProps, TTradingPlatformAccounts } from '../Components/props.types'; import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; import { CFD_PLATFORMS, @@ -15,6 +15,7 @@ import { Localize, localize } from '@deriv/translations'; import { CFDAccountCopy } from '../Components/cfd-account-copy'; import { getPlatformMt5DownloadLink, getMT5WebTerminalLink } from '../Helpers/constants'; import TradingPlatformIcon from '../Assets/svgs/trading-platform'; +import { TCFDPasswordReset } from './props.types'; type TMT5TradeModalProps = { mt5_trade_account: DetailsOfEachMT5Loginid; @@ -22,13 +23,11 @@ type TMT5TradeModalProps = { onPasswordManager: ( arg1: string | undefined, arg2: string, - arg3: string, + group: TCFDPasswordReset['account_group'], arg4: string, arg5: string | undefined ) => void; toggleModal: () => void; - dxtrade_tokens: TCFDDashboardContainer['dxtrade_tokens']; - derivez_tokens: TCFDDashboardContainer['derivez_tokens']; }; export type TSpecBoxProps = { diff --git a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-card-back.tsx b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-card-back.tsx index 1099135c58d8..ac7b7f2366cf 100644 --- a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-card-back.tsx +++ b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-card-back.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React from 'react'; import { Icon, Text } from '@deriv/components'; -import { jurisdictionVerificationContents } from 'Constants/jurisdiction-contents/jurisdiction-verification-contents'; +import { jurisdictionVerificationContents } from '../../Constants/jurisdiction-contents/jurisdiction-verification-contents'; import { TJurisdictionCardBackProps } from 'Containers/props.types'; const JurisdictionCardBack = ({ diff --git a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal-checkbox.tsx b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal-checkbox.tsx index 7de131031f52..114ac0eeb076 100644 --- a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal-checkbox.tsx +++ b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal-checkbox.tsx @@ -9,7 +9,6 @@ const JurisdictionCheckBox = ({ is_checked, jurisdiction_selected_shortcode, onCheck, - context, should_restrict_bvi_account_creation, should_restrict_vanuatu_account_creation, }: TJurisdictionCheckBoxProps) => { @@ -55,7 +54,6 @@ const JurisdictionCheckBox = ({ {shouldShowCheckBox() && (
{ + const { client, traders_hub } = useStore(); + + const { show_eu_related_content } = traders_hub; + + const { + trading_platform_available_accounts, + account_status, + fetchAccountSettings, + residence, + residence_list, + is_virtual, + updateMT5Status, + should_restrict_vanuatu_account_creation, + should_restrict_bvi_account_creation, + } = client; + + const { + is_jurisdiction_modal_visible, + has_submitted_cfd_personal_details, + jurisdiction_selected_shortcode, + toggleCFDVerificationModal, + toggleJurisdictionModal, + account_type, + real_financial_accounts_existing_data, + real_swapfree_accounts_existing_data, + real_synthetic_accounts_existing_data, + setJurisdictionSelectedShortcode, + } = useCfdStore(); -const JurisdictionModalContentWrapper = ({ - account_status, - account_type, - context, - fetchAccountSettings, - has_submitted_cfd_personal_details, - is_jurisdiction_modal_visible, - is_virtual, - jurisdiction_selected_shortcode, - openPasswordModal, - real_financial_accounts_existing_data, - real_swapfree_accounts_existing_data, - real_synthetic_accounts_existing_data, - residence, - residence_list, - setJurisdictionSelectedShortcode, - should_restrict_bvi_account_creation, - should_restrict_vanuatu_account_creation, - show_eu_related_content, - toggleCFDVerificationModal, - trading_platform_available_accounts, - toggleJurisdictionModal, - updateMT5Status, -}: TJurisdictionModalContentWrapperProps) => { const [checked, setChecked] = React.useState(false); const { @@ -202,14 +208,12 @@ const JurisdictionModalContentWrapper = ({ account_status={account_status} account_type={account_type.type} card_classname={`cfd-jurisdiction-card--${account_type.type}`} - context={context} jurisdiction_selected_shortcode={jurisdiction_selected_shortcode} should_restrict_bvi_account_creation={should_restrict_bvi_account_creation} should_restrict_vanuatu_account_creation={should_restrict_vanuatu_account_creation} /> setChecked(!checked)} class_name={`cfd-jurisdiction-card--${account_type.type}__jurisdiction-checkbox`} jurisdiction_selected_shortcode={jurisdiction_selected_shortcode} @@ -234,26 +238,6 @@ const JurisdictionModalContentWrapper = ({
); -}; -export default connect(({ modules: { cfd }, client, traders_hub }: RootStore) => ({ - account_status: client.account_status, - account_type: cfd.account_type, - fetchAccountSettings: client.fetchAccountSettings, - has_submitted_cfd_personal_details: cfd.has_submitted_cfd_personal_details, - is_jurisdiction_modal_visible: cfd.is_jurisdiction_modal_visible, - is_virtual: client.is_virtual, - jurisdiction_selected_shortcode: cfd.jurisdiction_selected_shortcode, - real_financial_accounts_existing_data: cfd.real_financial_accounts_existing_data, - real_swapfree_accounts_existing_data: cfd.real_swapfree_accounts_existing_data, - real_synthetic_accounts_existing_data: cfd.real_synthetic_accounts_existing_data, - residence: client.residence, - residence_list: client.residence_list, - setJurisdictionSelectedShortcode: cfd.setJurisdictionSelectedShortcode, - should_restrict_bvi_account_creation: client.should_restrict_bvi_account_creation, - should_restrict_vanuatu_account_creation: client.should_restrict_vanuatu_account_creation, - show_eu_related_content: traders_hub.show_eu_related_content, - toggleCFDVerificationModal: cfd.toggleCFDVerificationModal, - trading_platform_available_accounts: client.trading_platform_available_accounts, - toggleJurisdictionModal: cfd.toggleJurisdictionModal, - updateMT5Status: client.updateMT5Status, -}))(JurisdictionModalContentWrapper); +}); + +export default JurisdictionModalContentWrapper; diff --git a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal-foot-note.tsx b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal-foot-note.tsx index d9e96028bf5f..24dd6e7aef52 100644 --- a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal-foot-note.tsx +++ b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal-foot-note.tsx @@ -7,7 +7,6 @@ import { TJurisdictionModalFootNoteProps } from '../props.types'; const FooterNote = ({ account_status, account_type, - context, card_classname, jurisdiction_selected_shortcode, should_restrict_bvi_account_creation, diff --git a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal.tsx b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal.tsx index 54405437302e..002d32416a4e 100644 --- a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal.tsx +++ b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-modal.tsx @@ -1,22 +1,20 @@ import React from 'react'; import { DesktopWrapper, MobileDialog, MobileWrapper, Modal, UILoader } from '@deriv/components'; import { localize } from '@deriv/translations'; -import { connect } from '../../Stores/connect'; -import RootStore from '../../Stores/index'; import { getMT5Title } from '@deriv/shared'; import { TJurisdictionModalProps } from '../props.types'; +import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../../Stores/Modules/CFD/Helpers/useCfdStores'; import JurisdictionModalContentWrapper from './jurisdiction-modal-content-wrapper'; -const JurisdictionModal = ({ - account_type, - context, - disableApp, - enableApp, - is_jurisdiction_modal_visible, - openPasswordModal, - show_eu_related_content, - toggleJurisdictionModal, -}: TJurisdictionModalProps) => { +const JurisdictionModal = observer(({ openPasswordModal }: TJurisdictionModalProps) => { + const { traders_hub, ui } = useStore(); + + const { show_eu_related_content } = traders_hub; + const { disableApp, enableApp } = ui; + + const { account_type, is_jurisdiction_modal_visible, toggleJurisdictionModal } = useCfdStore(); + const modal_title = show_eu_related_content ? localize('Choose a jurisdiction for your Deriv MT5 CFDs account') : localize('Choose a jurisdiction for your Deriv MT5 {{account_type}} account', { @@ -36,33 +34,24 @@ const JurisdictionModal = ({ title={modal_title} toggleModal={toggleJurisdictionModal} type='button' - context={context} width={account_type.type === 'financial' ? '1200px' : '1040px'} > - +
- +
); -}; +}); -export default connect(({ modules: { cfd }, ui, traders_hub }: RootStore) => ({ - account_type: cfd.account_type, - disableApp: ui.disableApp, - enableApp: ui.enableApp, - is_jurisdiction_modal_visible: cfd.is_jurisdiction_modal_visible, - show_eu_related_content: traders_hub.show_eu_related_content, - toggleJurisdictionModal: cfd.toggleJurisdictionModal, -}))(JurisdictionModal); +export default JurisdictionModal; diff --git a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-title-indicator.tsx b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-title-indicator.tsx index 13dd1d564e4a..5583b06c4806 100644 --- a/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-title-indicator.tsx +++ b/packages/cfd/src/Containers/jurisdiction-modal/jurisdiction-title-indicator.tsx @@ -2,7 +2,7 @@ import React from 'react'; import classNames from 'classnames'; import { Icon, Text } from '@deriv/components'; import { getAuthenticationStatusInfo, Jurisdiction } from '@deriv/shared'; -import { jurisdictionVerificationContents } from 'Constants/jurisdiction-contents/jurisdiction-verification-contents'; +import { jurisdictionVerificationContents } from '../../Constants/jurisdiction-contents/jurisdiction-verification-contents'; import { TJurisdictionTitleIndicatorProps } from 'Containers/props.types'; import { TJurisdictionCardItemVerificationItem, TJurisdictionCardVerificationStatus } from 'Components/props.types'; diff --git a/packages/cfd/src/Containers/mt5-compare-table-content.tsx b/packages/cfd/src/Containers/mt5-compare-table-content.tsx old mode 100644 new mode 100755 index 95d2865eccf6..eb18d1b97c26 --- a/packages/cfd/src/Containers/mt5-compare-table-content.tsx +++ b/packages/cfd/src/Containers/mt5-compare-table-content.tsx @@ -3,8 +3,6 @@ import classNames from 'classnames'; import { Table, Button, Text, Popover } from '@deriv/components'; import { localize } from '@deriv/translations'; import { isDesktop, WS, getAuthenticationStatusInfo, CFD_PLATFORMS, ContentFlag, Jurisdiction } from '@deriv/shared'; -import { connect } from '../Stores/connect'; -import RootStore from '../Stores/index'; import { TDMT5CompareModalContentProps, TCompareAccountContentProps, @@ -23,6 +21,8 @@ import { getEuFooterButtons, } from '../Constants/cfd_compare_account_content'; import { GetSettings, GetAccountSettingsResponse } from '@deriv/api-types'; +import { observer, useStore } from '@deriv/stores'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; const Row = ({ id, @@ -156,458 +156,440 @@ const Row = ({ ); }; -const DMT5CompareModalContent = ({ - content_flag, - account_settings, - account_status, - clearCFDError, - current_list, - has_real_account, - is_demo_tab, - is_logged_in, - is_pre_appstore_setting, - is_preappstore_cr_demo_account, - is_preappstore_restricted_cr_demo_account, - is_real_enabled, - is_virtual, - openDerivRealAccountNeededModal, - openPasswordModal, - openSwitchToRealAccountModal, - real_account_creation_unlock_date, - setAccountSettings, - setAccountType, - setAppstorePlatform, - setJurisdictionSelectedShortcode, - setShouldShowCooldownModal, - should_restrict_bvi_account_creation, - should_restrict_vanuatu_account_creation, - should_show_derivx, - show_eu_related_content, - toggleCFDVerificationModal, - toggleCompareAccounts, - trading_platform_available_accounts, - upgradeable_landing_companies, - updateMT5Status, - no_CR_account, - is_eu_user, - no_MF_account, - CFDs_restricted_countries, - financial_restricted_countries, -}: TDMT5CompareModalContentProps) => { - const [has_submitted_personal_details, setHasSubmittedPersonalDetails] = React.useState(false); - - const mt5_platforms = trading_platform_available_accounts.map( - account => `${account.market_type === 'gaming' ? 'synthetic' : account.market_type}_${account.shortcode}` - ); - - const has_synthetic = trading_platform_available_accounts.some(account => account.market_type === 'gaming'); - const available_accounts_keys = [...mt5_platforms, ...(should_show_derivx && has_synthetic ? ['derivx'] : [])]; - - const logged_out_available_accounts_count = show_eu_related_content ? 1 : 6; - const available_accounts_count = is_logged_in - ? available_accounts_keys.length - : logged_out_available_accounts_count; - const synthetic_accounts_count = - !is_logged_in && !show_eu_related_content - ? 2 - : available_accounts_keys.filter(key => key.startsWith('synthetic')).length; - const financial_accounts_count = - !is_logged_in && !show_eu_related_content - ? 4 - : available_accounts_keys.filter(key => key.startsWith('financial')).length || 1; - - const is_high_risk_for_mt5 = synthetic_accounts_count === 1 && financial_accounts_count === 1; - const { - poi_or_poa_not_submitted, - poi_acknowledged_for_vanuatu_maltainvest, - poi_acknowledged_for_bvi_labuan, - poa_acknowledged, - poa_pending, - } = getAuthenticationStatusInfo(account_status); - - React.useEffect(() => { - if (is_logged_in && !is_virtual) { - updateMT5Status(); - } - if (!has_submitted_personal_details) { - let get_settings_response: GetSettings = {}; - if (!account_settings) { - WS.authorized.storage.getSettings().then((response: GetAccountSettingsResponse) => { - get_settings_response = response.get_settings as GetSettings; - setAccountSettings(response.get_settings as GetSettings); - }); - } else { - get_settings_response = account_settings; - } - const { citizen, place_of_birth, tax_residence, tax_identification_number, account_opening_reason } = - get_settings_response; - if (citizen && place_of_birth && tax_residence && tax_identification_number && account_opening_reason) { - setHasSubmittedPersonalDetails(true); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const getAvailableAccountsContent = (modal_content: TCompareAccountContentProps[]) => { - if (!is_logged_in) { - if (show_eu_related_content) { - return modal_content; +const DMT5CompareModalContent = observer( + ({ + content_flag, + is_demo_tab, + is_logged_in, + is_pre_appstore_setting, + is_preappstore_cr_demo_account, + is_preappstore_restricted_cr_demo_account, + is_real_enabled, + openDerivRealAccountNeededModal, + openPasswordModal, + real_account_creation_unlock_date, + setShouldShowCooldownModal, + should_show_derivx, + show_eu_related_content, + toggleCompareAccounts, + }: TDMT5CompareModalContentProps) => { + const { client, ui, common, traders_hub } = useStore(); + + const { + account_settings, + account_status, + has_active_real_account: has_real_account, + is_virtual, + should_restrict_bvi_account_creation, + setAccountSettings, + should_restrict_vanuatu_account_creation, + trading_platform_available_accounts, + updateMT5Status, + upgradeable_landing_companies, + } = client; + const { openSwitchToRealAccountModal } = ui; + const { setAppstorePlatform } = common; + const { no_CR_account, is_eu_user, no_MF_account, CFDs_restricted_countries, financial_restricted_countries } = + traders_hub; + + const { + clearCFDError, + current_list, + setAccountType, + setJurisdictionSelectedShortcode, + toggleCFDVerificationModal, + } = useCfdStore(); + + const [has_submitted_personal_details, setHasSubmittedPersonalDetails] = React.useState(false); + + const mt5_platforms = trading_platform_available_accounts.map( + account => `${account.market_type === 'gaming' ? 'synthetic' : account.market_type}_${account.shortcode}` + ); + + const has_synthetic = trading_platform_available_accounts.some(account => account.market_type === 'gaming'); + const available_accounts_keys = [...mt5_platforms, ...(should_show_derivx && has_synthetic ? ['derivx'] : [])]; + + const logged_out_available_accounts_count = show_eu_related_content ? 1 : 6; + const available_accounts_count = is_logged_in + ? available_accounts_keys.length + : logged_out_available_accounts_count; + const synthetic_accounts_count = + !is_logged_in && !show_eu_related_content + ? 2 + : available_accounts_keys.filter(key => key.startsWith('synthetic')).length; + const financial_accounts_count = + !is_logged_in && !show_eu_related_content + ? 4 + : available_accounts_keys.filter(key => key.startsWith('financial')).length || 1; + + const is_high_risk_for_mt5 = synthetic_accounts_count === 1 && financial_accounts_count === 1; + const { + poi_or_poa_not_submitted, + poi_acknowledged_for_vanuatu_maltainvest, + poi_acknowledged_for_bvi_labuan, + poa_acknowledged, + poa_pending, + } = getAuthenticationStatusInfo(account_status); + + React.useEffect(() => { + if (is_logged_in && !is_virtual) { + updateMT5Status(); } - const mt5_data = modal_content.map(item => { - const { derivx, ...rest } = item.values; // eslint-disable-line @typescript-eslint/no-unused-vars - return { ...item, values: rest }; - }); - return mt5_data; - } - return modal_content.map(row_data => { - const available_accounts_values = Object.entries(row_data.values).reduce( - (acc, [key, value]) => (available_accounts_keys.includes(key) ? { ...acc, [key]: value } : acc), - {} as TCompareAccountContentValues - ); - const content_data = { ...row_data, values: {} as TCompareAccountContentValues }; - const col_num = should_show_derivx ? 7 : 6; - if (available_accounts_keys.length < col_num && !show_eu_related_content) { - // order of the values matters for data to be correctly displayed in the table - const sorted_values = [ - 'synthetic_svg', - 'synthetic_bvi', - 'financial_svg', - 'financial_bvi', - 'financial_vanuatu', - 'financial_labuan', - ...(should_show_derivx && synthetic_accounts_count > 0 ? ['derivx'] : []), - ]; - content_data.values = sorted_values.reduce( - (acc, el) => (available_accounts_keys.includes(el) ? { ...acc, [el]: undefined } : acc), - {} - ); - available_accounts_keys.forEach(key => { - if (row_data.id === 'leverage' && (key === 'financial_svg' || key === 'financial_bvi')) { - content_data.values[key] = row_data.values.financial_vanuatu; - } else if (row_data.id === 'instruments' && key === 'synthetic_bvi') { - content_data.values[key] = row_data.values.synthetic_svg; - } else if (row_data.id === 'instruments' && key === 'financial_bvi') { - content_data.values[key] = row_data.values.financial_svg; - } - }); + if (!has_submitted_personal_details) { + let get_settings_response: GetSettings = {}; + if (!account_settings) { + WS.authorized.storage.getSettings().then((response: GetAccountSettingsResponse) => { + get_settings_response = response.get_settings as GetSettings; + setAccountSettings(response.get_settings as GetSettings); + }); + } else { + get_settings_response = account_settings; + } + const { citizen, place_of_birth, tax_residence, tax_identification_number, account_opening_reason } = + get_settings_response; + if (citizen && place_of_birth && tax_residence && tax_identification_number && account_opening_reason) { + setHasSubmittedPersonalDetails(true); + } } - return { ...content_data, values: { ...content_data.values, ...available_accounts_values } }; - }); - }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); - const getAvailableAccountsFooterButtons = (footer_button_data: TCompareAccountFooterButtonData[]) => { - return footer_button_data.filter(data => { - if (CFDs_restricted_countries) { - //remove derivx button if user is from restricted countries - if (data.action === 'derivx') return false; + const getAvailableAccountsContent = (modal_content: TCompareAccountContentProps[]) => { + if (!is_logged_in) { + if (show_eu_related_content) { + return modal_content; + } + const mt5_data = modal_content.map(item => { + const { derivx, ...rest } = item.values; // eslint-disable-line @typescript-eslint/no-unused-vars + return { ...item, values: rest }; + }); + return mt5_data; } - return available_accounts_keys.includes(data.action); - }); - }; - - const onSelectRealAccount = (item: TCompareAccountFooterButtonData) => { - const selected_account_type = () => { - if (item.action === 'derivx') return 'all'; - return item.action.startsWith('financial') ? 'financial' : 'synthetic'; + return modal_content.map(row_data => { + const available_accounts_values = Object.entries(row_data.values).reduce( + (acc, [key, value]) => (available_accounts_keys.includes(key) ? { ...acc, [key]: value } : acc), + {} as TCompareAccountContentValues + ); + const content_data = { ...row_data, values: {} as TCompareAccountContentValues }; + const col_num = should_show_derivx ? 7 : 6; + if (available_accounts_keys.length < col_num && !show_eu_related_content) { + // order of the values matters for data to be correctly displayed in the table + const sorted_values = [ + 'synthetic_svg', + 'synthetic_bvi', + 'financial_svg', + 'financial_bvi', + 'financial_vanuatu', + 'financial_labuan', + ...(should_show_derivx && synthetic_accounts_count > 0 ? ['derivx'] : []), + ]; + content_data.values = sorted_values.reduce( + (acc, el) => (available_accounts_keys.includes(el) ? { ...acc, [el]: undefined } : acc), + {} + ); + available_accounts_keys.forEach(key => { + if (row_data.id === 'leverage' && (key === 'financial_svg' || key === 'financial_bvi')) { + content_data.values[key] = row_data.values.financial_vanuatu; + } else if (row_data.id === 'instruments' && key === 'synthetic_bvi') { + content_data.values[key] = row_data.values.synthetic_svg; + } else if (row_data.id === 'instruments' && key === 'financial_bvi') { + content_data.values[key] = row_data.values.financial_svg; + } + }); + } + return { ...content_data, values: { ...content_data.values, ...available_accounts_values } }; + }); }; - const type_of_account = { - category: is_demo_tab ? 'demo' : 'real', - type: selected_account_type(), - }; - clearCFDError(); - setAccountType(type_of_account); - - switch (item.action) { - case 'synthetic_svg': - case 'financial_svg': - setAppstorePlatform(CFD_PLATFORMS.MT5); - setJurisdictionSelectedShortcode(Jurisdiction.SVG); - openPasswordModal(type_of_account); - break; - case 'synthetic_bvi': - case 'financial_bvi': - setAppstorePlatform(CFD_PLATFORMS.MT5); - setJurisdictionSelectedShortcode(Jurisdiction.BVI); - if ( - poi_acknowledged_for_bvi_labuan && - !poi_or_poa_not_submitted && - !should_restrict_bvi_account_creation && - has_submitted_personal_details && - poa_acknowledged - ) { - openPasswordModal(type_of_account); - } else { - toggleCFDVerificationModal(); + const getAvailableAccountsFooterButtons = (footer_button_data: TCompareAccountFooterButtonData[]) => { + return footer_button_data.filter(data => { + if (CFDs_restricted_countries) { + //remove derivx button if user is from restricted countries + if (data.action === 'derivx') return false; } - break; - case 'synthetic_vanuatu': - case 'financial_vanuatu': - setAppstorePlatform(CFD_PLATFORMS.MT5); - setJurisdictionSelectedShortcode(Jurisdiction.VANUATU); - if ( - poi_acknowledged_for_vanuatu_maltainvest && - !poi_or_poa_not_submitted && - !should_restrict_vanuatu_account_creation && - has_submitted_personal_details && - poa_acknowledged - ) { - openPasswordModal(type_of_account); - } else { - toggleCFDVerificationModal(); - } - break; - case 'financial_labuan': - setAppstorePlatform(CFD_PLATFORMS.MT5); - setJurisdictionSelectedShortcode(Jurisdiction.LABUAN); - if (poi_acknowledged_for_bvi_labuan && poa_acknowledged && has_submitted_personal_details) { + return available_accounts_keys.includes(data.action); + }); + }; + + const onSelectRealAccount = (item: TCompareAccountFooterButtonData) => { + const selected_account_type = () => { + if (item.action === 'derivx') return 'all'; + return item.action.startsWith('financial') ? 'financial' : 'synthetic'; + }; + + const type_of_account = { + category: is_demo_tab ? 'demo' : 'real', + type: selected_account_type(), + }; + clearCFDError(); + setAccountType(type_of_account); + + switch (item.action) { + case 'synthetic_svg': + case 'financial_svg': + setAppstorePlatform(CFD_PLATFORMS.MT5); + setJurisdictionSelectedShortcode(Jurisdiction.SVG); openPasswordModal(type_of_account); - } else { - toggleCFDVerificationModal(); - } - break; - case 'financial_maltainvest': - setAppstorePlatform(CFD_PLATFORMS.MT5); - setJurisdictionSelectedShortcode(Jurisdiction.MALTA_INVEST); - if ((poi_acknowledged_for_vanuatu_maltainvest && poa_acknowledged) || is_demo_tab) { + break; + case 'synthetic_bvi': + case 'financial_bvi': + setAppstorePlatform(CFD_PLATFORMS.MT5); + setJurisdictionSelectedShortcode(Jurisdiction.BVI); + if ( + poi_acknowledged_for_bvi_labuan && + !poi_or_poa_not_submitted && + !should_restrict_bvi_account_creation && + has_submitted_personal_details && + poa_acknowledged + ) { + openPasswordModal(type_of_account); + } else { + toggleCFDVerificationModal(); + } + break; + case 'synthetic_vanuatu': + case 'financial_vanuatu': + setAppstorePlatform(CFD_PLATFORMS.MT5); + setJurisdictionSelectedShortcode(Jurisdiction.VANUATU); + if ( + poi_acknowledged_for_vanuatu_maltainvest && + !poi_or_poa_not_submitted && + !should_restrict_vanuatu_account_creation && + has_submitted_personal_details && + poa_acknowledged + ) { + openPasswordModal(type_of_account); + } else { + toggleCFDVerificationModal(); + } + break; + case 'financial_labuan': + setAppstorePlatform(CFD_PLATFORMS.MT5); + setJurisdictionSelectedShortcode(Jurisdiction.LABUAN); + if (poi_acknowledged_for_bvi_labuan && poa_acknowledged && has_submitted_personal_details) { + openPasswordModal(type_of_account); + } else { + toggleCFDVerificationModal(); + } + break; + case 'financial_maltainvest': + setAppstorePlatform(CFD_PLATFORMS.MT5); + setJurisdictionSelectedShortcode(Jurisdiction.MALTA_INVEST); + if ((poi_acknowledged_for_vanuatu_maltainvest && poa_acknowledged) || is_demo_tab) { + openPasswordModal(type_of_account); + } else { + toggleCFDVerificationModal(); + } + break; + case 'derivx': + setAppstorePlatform(CFD_PLATFORMS.DXTRADE); openPasswordModal(type_of_account); + break; + default: + } + }; + + const isMt5AccountAdded = (item: TCompareAccountFooterButtonData) => + Object.entries(current_list).some(([key, value]) => { + const [market, type] = item.action.split('_'); + const current_account_type = is_demo_tab ? 'demo' : 'real'; + return ( + value.market_type === market && + value.landing_company_short === type && + value.account_type === current_account_type && + key.includes(CFD_PLATFORMS.MT5) + ); + }); + + const isDxtradeAccountAdded = () => + Object.entries(current_list).some(([key, value]) => { + const current_account_type = is_demo_tab ? 'demo' : 'real'; + return value.account_type === current_account_type && key.includes(CFD_PLATFORMS.DXTRADE); + }); + + const onButtonClick = (item: TCompareAccountFooterButtonData) => { + const if_no_corresponding_real_account = is_pre_appstore_setting + ? (no_CR_account && !is_eu_user) || (no_MF_account && is_eu_user) + : !has_real_account; + + const should_show_missing_real_account = + is_logged_in && + if_no_corresponding_real_account && + upgradeable_landing_companies?.length > 0 && + is_real_enabled; + + toggleCompareAccounts(); + if (should_show_missing_real_account) { + if (real_account_creation_unlock_date && item.action === 'financial_maltainvest') { + setShouldShowCooldownModal(true); } else { - toggleCFDVerificationModal(); + openDerivRealAccountNeededModal(); } - break; - case 'derivx': - setAppstorePlatform(CFD_PLATFORMS.DXTRADE); - openPasswordModal(type_of_account); - break; - default: - } - }; - - const isMt5AccountAdded = (item: TCompareAccountFooterButtonData) => - Object.entries(current_list).some(([key, value]) => { - const [market, type] = item.action.split('_'); - const current_account_type = is_demo_tab ? 'demo' : 'real'; - return ( - value.market_type === market && - value.landing_company_short === type && - value.account_type === current_account_type && - key.includes(CFD_PLATFORMS.MT5) - ); - }); - - const isDxtradeAccountAdded = () => - Object.entries(current_list).some(([key, value]) => { - const current_account_type = is_demo_tab ? 'demo' : 'real'; - return value.account_type === current_account_type && key.includes(CFD_PLATFORMS.DXTRADE); - }); - - const onButtonClick = (item: TCompareAccountFooterButtonData) => { - const if_no_corresponding_real_account = is_pre_appstore_setting - ? (no_CR_account && !is_eu_user) || (no_MF_account && is_eu_user) - : !has_real_account; - - const should_show_missing_real_account = - is_logged_in && - if_no_corresponding_real_account && - upgradeable_landing_companies?.length > 0 && - is_real_enabled; - - toggleCompareAccounts(); - if (should_show_missing_real_account) { - if (real_account_creation_unlock_date && item.action === 'financial_maltainvest') { - setShouldShowCooldownModal(true); + } else if ( + is_virtual && + !['synthetic_svg', 'financial_svg', 'derivx', 'financial_maltainvest'].includes(item.action) + ) { + openSwitchToRealAccountModal(); } else { - openDerivRealAccountNeededModal(); + onSelectRealAccount(item); } - } else if ( - is_virtual && - !['synthetic_svg', 'financial_svg', 'derivx', 'financial_maltainvest'].includes(item.action) - ) { - openSwitchToRealAccountModal(); - } else { - onSelectRealAccount(item); - } - }; + }; - const getModalContent = () => { - if (is_preappstore_cr_demo_account) { - return getPreappstoreCrDemoContent(); - } else if (show_eu_related_content) { - if (is_pre_appstore_setting && content_flag === ContentFlag.EU_DEMO) { - return getPreappstoreEuDemoContent(); + const getModalContent = () => { + if (is_preappstore_cr_demo_account) { + return getPreappstoreCrDemoContent(); + } else if (show_eu_related_content) { + if (is_pre_appstore_setting && content_flag === ContentFlag.EU_DEMO) { + return getPreappstoreEuDemoContent(); + } + return getEuRealContent(); } - return getEuRealContent(); - } - return getCrRealContent(); - }; + return getCrRealContent(); + }; - const modal_footer = () => { - if (is_preappstore_cr_demo_account) return getPreappstoreCrDemoFooterButtons(); - else if (is_demo_tab && show_eu_related_content) return getEuFooterButtons(); - return show_eu_related_content ? getEuFooterButtons() : getCrRealFooterButtons(); - }; + const modal_footer = () => { + if (is_preappstore_cr_demo_account) return getPreappstoreCrDemoFooterButtons(); + else if (is_demo_tab && show_eu_related_content) return getEuFooterButtons(); + return show_eu_related_content ? getEuFooterButtons() : getCrRealFooterButtons(); + }; - const shouldShowPendingStatus = (item: TCompareAccountFooterButtonData) => { - const type = item.action.split('_')[1]; - if (isMt5AccountAdded(item)) { - return false; - } else if (item.action === 'derivx') { - return false; - } else if (type === 'bvi' && should_restrict_bvi_account_creation && poa_pending) { - return true; - } else if (type === 'vanuatu' && should_restrict_vanuatu_account_creation && poa_pending) { - return true; - } + const shouldShowPendingStatus = (item: TCompareAccountFooterButtonData) => { + const type = item.action.split('_')[1]; + if (isMt5AccountAdded(item)) { + return false; + } else if (item.action === 'derivx') { + return false; + } else if (type === 'bvi' && should_restrict_bvi_account_creation && poa_pending) { + return true; + } else if (type === 'vanuatu' && should_restrict_vanuatu_account_creation && poa_pending) { + return true; + } - return false; - }; + return false; + }; - const pre_appstore_class = should_show_derivx && synthetic_accounts_count ? '__pre-appstore' : ''; + const pre_appstore_class = should_show_derivx && synthetic_accounts_count ? '__pre-appstore' : ''; - const getClassNamesForDemoAndEu = () => { - if (is_preappstore_cr_demo_account) return 'cfd-accounts-compare-modal-row-demo'; - else if (show_eu_related_content) return 'cfd-accounts-compare-modal-row-eu'; - return null; - }; + const getClassNamesForDemoAndEu = () => { + if (is_preappstore_cr_demo_account) return 'cfd-accounts-compare-modal-row-demo'; + else if (show_eu_related_content) return 'cfd-accounts-compare-modal-row-eu'; + return null; + }; - const classname_for_demo_and_eu = getClassNamesForDemoAndEu(); + const classname_for_demo_and_eu = getClassNamesForDemoAndEu(); - return ( -
-
- - - - - {!show_eu_related_content && synthetic_accounts_count > 0 && ( - - {localize('Derived')} - - )} - {!CFDs_restricted_countries && financial_accounts_count > 0 && ( - - {show_eu_related_content ? localize('CFDs') : localize('Financial')} - - )} - {!CFDs_restricted_countries && should_show_derivx && synthetic_accounts_count > 0 && ( - - {localize('Deriv X')} - - )} - - - - - - {getAvailableAccountsContent(getModalContent()).map(row => ( - - ))} - - {is_logged_in && ( + return ( +
+
+
+ - + {!show_eu_related_content && synthetic_accounts_count > 0 && ( + + {localize('Derived')} + + )} + {!CFDs_restricted_countries && financial_accounts_count > 0 && ( + + {show_eu_related_content ? localize('CFDs') : localize('Financial')} + + )} + {!CFDs_restricted_countries && should_show_derivx && synthetic_accounts_count > 0 && ( + + {localize('Deriv X')} + + )} + + + + + + {getAvailableAccountsContent(getModalContent()).map(row => ( + + ))} + + {is_logged_in && ( + - - {getAvailableAccountsFooterButtons(modal_footer()).map((item, index) => ( + > - {!is_demo_tab && shouldShowPendingStatus(item) ? ( -
- - {localize('Pending verification')} - -
- ) : ( - - )} -
- ))} -
- )} -
-
+ fixed + className={ + 'cfd-accounts-compare-modal__table-empty-cell cfd-accounts-compare-modal__table-footer__item' + } + /> + + {getAvailableAccountsFooterButtons(modal_footer()).map((item, index) => ( + + {!is_demo_tab && shouldShowPendingStatus(item) ? ( +
+ + {localize('Pending verification')} + +
+ ) : ( + + )} +
+ ))} + + )} + + +
-
- ); -}; + ); + } +); -export default connect(({ modules, client, common, ui, traders_hub }: RootStore) => ({ - account_settings: client.account_settings, - account_status: client.account_status, - account_type: modules.cfd.account_type, - clearCFDError: modules.cfd.clearCFDError, - current_list: modules.cfd.current_list, - has_real_account: client.has_active_real_account, - has_real_mt5_login: client.has_real_mt5_login, - is_virtual: client.is_virtual, - openSwitchToRealAccountModal: ui.openSwitchToRealAccountModal, - setAccountSettings: client.setAccountSettings, - setAccountType: modules.cfd.setAccountType, - setJurisdictionSelectedShortcode: modules.cfd.setJurisdictionSelectedShortcode, - should_restrict_bvi_account_creation: client.should_restrict_bvi_account_creation, - should_restrict_vanuatu_account_creation: client.should_restrict_vanuatu_account_creation, - toggleCFDVerificationModal: modules.cfd.toggleCFDVerificationModal, - trading_platform_available_accounts: client.trading_platform_available_accounts, - updateMT5Status: client.updateMT5Status, - upgradeable_landing_companies: client.upgradeable_landing_companies, - setAppstorePlatform: common.setAppstorePlatform, - no_CR_account: traders_hub.no_CR_account, - is_eu_user: traders_hub.is_eu_user, - no_MF_account: traders_hub.no_MF_account, - CFDs_restricted_countries: traders_hub.CFDs_restricted_countries, - financial_restricted_countries: traders_hub.financial_restricted_countries, -}))(DMT5CompareModalContent); +export default DMT5CompareModalContent; diff --git a/packages/cfd/src/Containers/mt5-trade-modal.tsx b/packages/cfd/src/Containers/mt5-trade-modal.tsx index 35cea86a5a05..ca89966bdf4b 100644 --- a/packages/cfd/src/Containers/mt5-trade-modal.tsx +++ b/packages/cfd/src/Containers/mt5-trade-modal.tsx @@ -1,107 +1,90 @@ import React from 'react'; import { DesktopWrapper, Div100vhContainer, Modal, MobileWrapper, PageOverlay, UILoader } from '@deriv/components'; -import { connect } from '../Stores/connect'; -import RootStore from '../Stores/index'; import { localize } from '@deriv/translations'; -import { DetailsOfEachMT5Loginid } from '@deriv/api-types'; -import { TTradingPlatformAvailableAccount } from '../../types'; -import { TCFDDashboardContainer } from '../Components/props.types'; +import { observer, useStore } from '@deriv/stores'; import TradeModal from './trade-modal'; import DMT5TradeModal from './dmt5-trade-modal'; +import { TCFDPasswordReset } from './props.types'; +import { useCfdStore } from '../Stores/Modules/CFD/Helpers/useCfdStores'; type TMT5TradeModalProps = { - mt5_trade_account: Required< - DetailsOfEachMT5Loginid & { market_type?: TTradingPlatformAvailableAccount['market_type'] | 'synthetic' } - >; is_eu_user: boolean; is_open: boolean; onPasswordManager: ( arg1: string | undefined, arg2: string, - arg3: string, + group: TCFDPasswordReset['account_group'], arg4: string, arg5: string | undefined ) => void; toggleModal: () => void; - platform: 'mt5' | 'dxtrade' | 'derivez'; - dxtrade_tokens: TCFDDashboardContainer['dxtrade_tokens']; - derivez_tokens: TCFDDashboardContainer['derivez_tokens']; is_demo: string; - show_eu_related_content: boolean; }; -const MT5TradeModal = ({ - mt5_trade_account, - is_eu_user, - is_open, - onPasswordManager, - toggleModal, - dxtrade_tokens, - derivez_tokens, - platform, - is_demo, - show_eu_related_content, -}: TMT5TradeModalProps) => { - const CFDTradeModal = () => { - if (platform === 'mt5') { + +const MT5TradeModal = observer( + ({ is_eu_user, is_open, onPasswordManager, toggleModal, is_demo }: TMT5TradeModalProps) => { + const { traders_hub, common } = useStore(); + + const { show_eu_related_content } = traders_hub; + const { platform } = common; + + const { mt5_trade_account, dxtrade_tokens, derivez_tokens } = useCfdStore(); + + const CFDTradeModal = () => { + if (platform === 'mt5') { + return ( + + ); + } return ( - ); - } + }; + return ( - + }> + + + + + + + + + + + + + ); - }; + } +); - return ( - }> - - - - - - - - - - - - - - ); -}; -export default connect(({ modules: { cfd }, modules, common, traders_hub }: RootStore) => ({ - dxtrade_tokens: cfd.dxtrade_tokens, - derivez_tokens: cfd.derivez_tokens, - platform: common.platform, - mt5_trade_account: modules.cfd.mt5_trade_account, - show_eu_related_content: traders_hub.show_eu_related_content, -}))(MT5TradeModal); +export default MT5TradeModal; diff --git a/packages/cfd/src/Containers/props.types.ts b/packages/cfd/src/Containers/props.types.ts index 01840e99884b..d895ab26c64a 100644 --- a/packages/cfd/src/Containers/props.types.ts +++ b/packages/cfd/src/Containers/props.types.ts @@ -1,12 +1,5 @@ import React from 'react'; -import { - DetailsOfEachMT5Loginid, - GetAccountStatus, - GetSettings, - LandingCompany, - ResidenceList, - VerifyEmailResponse, -} from '@deriv/api-types'; +import { DetailsOfEachMT5Loginid, GetAccountStatus, VerifyEmailResponse } from '@deriv/api-types'; import { FormikHelpers as FormikActions } from 'formik'; import { TCFDPasswordFormValues } from './cfd-password-modal'; import { @@ -21,12 +14,6 @@ import { import RootStore from '../Stores/index'; export type TCFDPersonalDetailsContainerProps = { - account_settings: GetSettings; - getChangeableFields: () => string[]; - context: RootStore; - landing_company: LandingCompany; - residence_list: ResidenceList; - setAccountSettings: (account_settings: GetSettings) => void; onSubmit: (index: number, value: { [key: string]: string }) => void; }; @@ -75,7 +62,7 @@ export type TChangePassword = { export type TPasswordResetAndTradingPasswordManager = { email: string; platform: CFD_Platform; - account_group: 'real' | 'demo'; + account_group: TCFDPasswordReset['account_group']; toggleModal?: () => void; }; @@ -92,14 +79,7 @@ export type TError = { }; export type TCFDResetPasswordModal = { - current_list: Record; - email: string; - context?: RootStore; - is_cfd_reset_password_modal_enabled: boolean; - is_eu: boolean; - is_logged_in: boolean; platform: CFD_Platform; - setCFDPasswordResetModal: (value: boolean) => void; }; export type TCFDPasswordSuccessMessage = { @@ -134,9 +114,8 @@ export type TCountdownComponent = { export type TCFDPasswordReset = { sendVerifyEmail: () => Promise; account_type: string; - account_group: 'real' | 'demo'; + account_group: 'demo' | 'real' | ''; server: string; - context: RootStore; password_type: string; }; @@ -149,38 +128,30 @@ export type TCFDPasswordManagerTabContent = { toggleModal: () => void; selected_login: string; email: string; - context: RootStore; setPasswordType: (value: string) => void; multi_step_ref: React.MutableRefObject; platform: CFD_Platform; onChangeActiveTabIndex: (value: number) => void; - account_group: 'real' | 'demo'; + account_group: TCFDPasswordReset['account_group']; }; export type TCFDPasswordManagerModal = { - enableApp: () => void; - email: string; - is_eu: boolean; - context: RootStore; - disableApp: () => void; is_visible: boolean; platform: CFD_Platform; selected_login: string; - selected_account: string; toggleModal: () => void; selected_account_type: string; - selected_account_group: 'real' | 'demo'; + selected_account_group: TCFDPasswordReset['account_group']; selected_server: string; - sendVerifyEmail: () => Promise; }; export type TJurisdictionCardProps = { + jurisdiction_selected_shortcode: string; + setJurisdictionSelectedShortcode: (card_type: string) => void; account_status: GetAccountStatus; account_type: string; disabled: boolean; is_non_idv_design: boolean; - jurisdiction_selected_shortcode: string; - setJurisdictionSelectedShortcode: (card_type: string) => void; type_of_card: TJurisdictionCardType; }; @@ -223,12 +194,9 @@ export type TJurisdictionCardSectionProps = { export type TJurisdictionCardType = 'svg' | 'bvi' | 'vanuatu' | 'labuan' | 'maltainvest'; export type TVerificationStatusBannerProps = { - account_status: GetAccountStatus; account_type: string; - context: RootStore; card_classname: string; disabled: boolean; - is_virtual: boolean; type_of_card: string; real_synthetic_accounts_existing_data: TExistingData; real_financial_accounts_existing_data: TExistingData; @@ -239,7 +207,6 @@ export type TVerificationStatusBannerProps = { export type TJurisdictionCheckBoxProps = { class_name: string; - context: RootStore; is_checked: boolean; jurisdiction_selected_shortcode: string; onCheck: () => void; @@ -251,40 +218,12 @@ type TOpenAccountTransferMeta = { type?: string; }; -type TJurisdictionModalCommonProps = { - account_type: { - type: string; - category: string; - }; - context: RootStore; - is_jurisdiction_modal_visible: boolean; +export type TJurisdictionModalContentWrapperProps = { openPasswordModal: (account_type: TOpenAccountTransferMeta) => void; - show_eu_related_content: boolean; - toggleJurisdictionModal: () => void; -}; - -export type TJurisdictionModalContentWrapperProps = TJurisdictionModalCommonProps & { - account_status: GetAccountStatus; - fetchAccountSettings: () => void; - has_submitted_cfd_personal_details: boolean; - is_virtual: boolean; - jurisdiction_selected_shortcode: string; - real_financial_accounts_existing_data: TExistingData; - real_swapfree_accounts_existing_data: TExistingData; - real_synthetic_accounts_existing_data: TExistingData; - residence: string; - residence_list: ResidenceList; - setJurisdictionSelectedShortcode: (shortcode: string) => void; - should_restrict_bvi_account_creation: boolean; - should_restrict_vanuatu_account_creation: boolean; - toggleCFDVerificationModal: () => void; - trading_platform_available_accounts: TTradingPlatformAvailableAccount[]; - updateMT5Status: () => void; }; -export type TJurisdictionModalProps = TJurisdictionModalCommonProps & { - disableApp: () => void; - enableApp: () => void; +export type TJurisdictionModalProps = { + openPasswordModal: (account_type: TOpenAccountTransferMeta) => void; }; export type TJurisdictionModalContentProps = { @@ -302,11 +241,12 @@ export type TJurisdictionModalContentProps = { is_virtual: boolean; }; +type TAccountStatus = Omit & Partial>; + export type TJurisdictionModalFootNoteProps = { - account_status: GetAccountStatus; + account_status: TAccountStatus; account_type: string; card_classname: string; - context: RootStore; jurisdiction_selected_shortcode: string; should_restrict_bvi_account_creation: boolean; should_restrict_vanuatu_account_creation: boolean; @@ -330,8 +270,8 @@ export type TCompareAccountRowProps = TCompareAccountContentProps & { is_pre_appstore_setting: boolean; pre_appstore_class: string; is_high_risk_for_mt5: boolean; - CFDs_restricted_countries: string[]; - financial_restricted_countries: string[]; + CFDs_restricted_countries: boolean; + financial_restricted_countries: boolean; is_preappstore_restricted_cr_demo_account: boolean; }; @@ -344,45 +284,20 @@ export type TCompareAccountContentProps = { export type TCompareAccountFooterButtonData = { label: string; action: string }; export type TDMT5CompareModalContentProps = { - account_settings: GetSettings; - account_status: GetAccountStatus; - account_type: TOpenAccountTransferMeta; - clearCFDError: () => void; content_flag: string; - context: RootStore; - current_list: Record; - has_real_account: boolean; is_demo_tab: boolean; is_logged_in: boolean; is_pre_appstore_setting: boolean; is_preappstore_cr_demo_account: boolean; is_preappstore_restricted_cr_demo_account: boolean; is_real_enabled: boolean; - is_virtual: boolean; openDerivRealAccountNeededModal: () => void; openPasswordModal: (account_type: TOpenAccountTransferMeta) => void; - openSwitchToRealAccountModal: () => void; real_account_creation_unlock_date: string; - setAccountSettings: (get_settings_response: GetSettings) => void; - setAccountType: (account_type: TOpenAccountTransferMeta) => void; - setAppstorePlatform: (platform: string) => void; - setJurisdictionSelectedShortcode: (shortcode: string) => void; setShouldShowCooldownModal: (value: boolean) => void; - should_restrict_bvi_account_creation: boolean; - should_restrict_vanuatu_account_creation: boolean; should_show_derivx: boolean; show_eu_related_content: boolean; - toggleCFDPersonalDetailsModal: (is_from_mt5_compare_accounts?: boolean) => void; - toggleCFDVerificationModal: () => void; toggleCompareAccounts: () => void; - trading_platform_available_accounts: TTradingPlatformAvailableAccount[]; - updateMT5Status: () => void; - upgradeable_landing_companies: unknown[]; - no_CR_account: boolean; - is_eu_user: boolean; - no_MF_account: boolean; - CFDs_restricted_countries: string[]; - financial_restricted_countries: string[]; }; export type TCFDDbviOnboardingProps = { diff --git a/packages/cfd/src/Containers/routes.jsx b/packages/cfd/src/Containers/routes.jsx index 48f87523d584..9eadfc445176 100644 --- a/packages/cfd/src/Containers/routes.jsx +++ b/packages/cfd/src/Containers/routes.jsx @@ -1,41 +1,27 @@ -import { PropTypes as MobxPropTypes } from 'mobx-react'; import PropTypes from 'prop-types'; import React from 'react'; import { withRouter } from 'react-router'; import BinaryRoutes from '../Components/Routes'; -import { connect } from '../Stores/connect'; import ErrorComponent from '../Components/Errors/error-component.jsx'; +import { observer, useStore } from '@deriv/stores'; -const Routes = props => { - if (props.has_error) { - return ; +const Routes = observer(({ passthrough }) => { + const { client, common } = useStore(); + + const { is_logged_in, is_logging_in } = client; + const { error, has_error } = common; + + if (has_error) { + return ; } - return ( - - ); -}; + return ; +}); Routes.propTypes = { - error: MobxPropTypes.objectOrObservableObject, - has_error: PropTypes.bool, - is_logged_in: PropTypes.bool, - is_logging_in: PropTypes.bool, - is_virtual: PropTypes.bool, passthrough: PropTypes.object, }; // need to wrap withRouter around connect // to prevent updates on from being blocked -export default withRouter( - connect(({ client, common }) => ({ - is_logged_in: client.is_logged_in, - is_logging_in: client.is_logging_in, - error: common.error, - has_error: common.has_error, - }))(Routes) -); +export default withRouter(Routes); diff --git a/packages/cfd/src/Containers/switch-to-real-account.tsx b/packages/cfd/src/Containers/switch-to-real-account.tsx index 705b5fc8a538..60cf470967d8 100644 --- a/packages/cfd/src/Containers/switch-to-real-account.tsx +++ b/packages/cfd/src/Containers/switch-to-real-account.tsx @@ -2,17 +2,18 @@ import React from 'react'; import { Dialog, Icon, Text } from '@deriv/components'; import { localize } from '@deriv/translations'; import { isMobile } from '@deriv/shared'; -import RootStore from '../Stores/index'; -import { connect } from '../Stores/connect'; +import { observer, useStore } from '@deriv/stores'; -type TSwitchToRealAccountModal = { - is_open: boolean; - onClose: () => void; - disableApp: () => void; - enableApp: () => void; -}; +const SwitchToRealAccountModal = observer(() => { + const { ui } = useStore(); + + const { + is_switch_to_deriv_account_modal_visible: is_open, + openSwitchToRealAccountModal: onClose, + disableApp, + enableApp, + } = ui; -const SwitchToRealAccountModal = ({ is_open, onClose, disableApp, enableApp }: TSwitchToRealAccountModal) => { return ( ); -}; +}); -export default connect(({ ui }: RootStore) => ({ - is_open: ui.is_switch_to_deriv_account_modal_visible, - onClose: ui.openSwitchToRealAccountModal, - disableApp: ui.disableApp, - enableApp: ui.enableApp, -}))(SwitchToRealAccountModal); +export default SwitchToRealAccountModal; diff --git a/packages/cfd/src/Containers/trade-modal.tsx b/packages/cfd/src/Containers/trade-modal.tsx index 320b5f5189a4..e24a287390a4 100644 --- a/packages/cfd/src/Containers/trade-modal.tsx +++ b/packages/cfd/src/Containers/trade-modal.tsx @@ -6,8 +6,9 @@ import { CFD_PLATFORMS, getCFDAccountKey, isMobile } from '@deriv/shared'; import { localize, Localize } from '@deriv/translations'; import { getPlatformQRCode, PlatformsDesktopDownload } from '../Helpers/config'; import { getTitle, platformsText, mobileDownloadLink } from '../Helpers/constants'; -import SpecBox from 'Components/specbox'; -import PasswordBox from 'Components/passwordbox'; +import SpecBox from '../Components/specbox'; +import PasswordBox from '../Components/passwordbox'; +import { TCFDPasswordReset } from './props.types'; type TTradeModalProps = { mt5_trade_account: Required; @@ -15,7 +16,7 @@ type TTradeModalProps = { onPasswordManager: ( arg1: string | undefined, arg2: string, - arg3: string, + group: TCFDPasswordReset['account_group'], arg4: string, arg5: string | undefined ) => void; diff --git a/packages/cfd/src/Stores/Modules/CFD/Helpers/useCfdStores.tsx b/packages/cfd/src/Stores/Modules/CFD/Helpers/useCfdStores.tsx new file mode 100644 index 000000000000..59e2a9defed2 --- /dev/null +++ b/packages/cfd/src/Stores/Modules/CFD/Helpers/useCfdStores.tsx @@ -0,0 +1,28 @@ +import React, { createContext, PropsWithChildren, useContext } from 'react'; +import { useStore } from '@deriv/stores'; +import type { TCFDStore } from '../../../../types/cfd-store.types'; + +const CFDStoreContext = createContext(null); + +export const CFDStoreProvider = ({ children }: PropsWithChildren) => { + const { modules } = useStore(); + + return ( + + {children} + + ); +}; + +export const useCfdStore = () => { + const store = useContext(CFDStoreContext); + + if (!store) { + throw new Error('useCfdStore must be used within CfdStoreContext'); + } + + return store; +}; diff --git a/packages/cfd/src/Stores/Modules/CFD/cfd-store.js b/packages/cfd/src/Stores/Modules/CFD/cfd-store.js index b27032ab31ff..9680f5742435 100644 --- a/packages/cfd/src/Stores/Modules/CFD/cfd-store.js +++ b/packages/cfd/src/Stores/Modules/CFD/cfd-store.js @@ -11,8 +11,8 @@ export default class CFDStore extends BaseStore { jurisdiction_selected_shortcode = ''; account_type = { - category: undefined, - type: undefined, + category: '', + type: '', }; mt5_trade_account = {}; diff --git a/packages/cfd/src/Stores/connect.js b/packages/cfd/src/Stores/connect.js deleted file mode 100644 index 474c716e9381..000000000000 --- a/packages/cfd/src/Stores/connect.js +++ /dev/null @@ -1,33 +0,0 @@ -import { useObserver } from 'mobx-react'; -import React from 'react'; - -const isClassComponent = Component => - !!(typeof Component === 'function' && Component.prototype && Component.prototype.isReactComponent); - -export const MobxContent = React.createContext(null); - -function injectStorePropsToComponent(propsToSelectFn, BaseComponent) { - const Component = own_props => { - const store = React.useContext(MobxContent); - - let ObservedComponent = BaseComponent; - - if (isClassComponent(BaseComponent)) { - const FunctionalWrapperComponent = props => ; - ObservedComponent = FunctionalWrapperComponent; - } - - // This is a temporary approach to pass stores from different packages - const context = own_props.context || store; - return useObserver(() => ObservedComponent({ ...own_props, ...propsToSelectFn(context, own_props) })); - }; - - Component.displayName = BaseComponent.name; - return Component; -} - -export const MobxContentProvider = ({ store, children }) => { - return {children}; -}; - -export const connect = propsToSelectFn => Component => injectStorePropsToComponent(propsToSelectFn, Component); diff --git a/packages/cfd/src/app.tsx b/packages/cfd/src/app.tsx index 721f91275641..8779a57da52f 100644 --- a/packages/cfd/src/app.tsx +++ b/packages/cfd/src/app.tsx @@ -1,37 +1,24 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import PropTypes from 'prop-types'; import React from 'react'; -import { StoreProvider } from '@deriv/stores'; import Routes from './Containers/routes.jsx'; -import { MobxContentProvider } from './Stores/connect'; -import initStore from './init-store'; // eslint-disable-line import/extensions +import initStore from './init-store'; +import CFDProviders from './cfd-providers'; +import type { TCoreStores } from '@deriv/stores/types'; type TAppProps = { passthrough: { - root_store: any; - WS: any; + root_store: TCoreStores; + WS: unknown; }; }; const App = ({ passthrough }: TAppProps) => { - const [root_store] = React.useState(initStore(passthrough.root_store, passthrough.WS)); + initStore(passthrough.root_store, passthrough.WS); return ( - - - - - - - + + + ); }; -App.propTypes = { - passthrough: PropTypes.shape({ - root_store: PropTypes.object, - WS: PropTypes.object, - }), -}; - export default App; diff --git a/packages/cfd/src/cfd-providers.tsx b/packages/cfd/src/cfd-providers.tsx new file mode 100644 index 000000000000..a67a9192db7c --- /dev/null +++ b/packages/cfd/src/cfd-providers.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { StoreProvider } from '@deriv/stores'; +import { CFDStoreProvider } from './Stores/Modules/CFD/Helpers/useCfdStores'; +import type { TCoreStores } from '@deriv/stores/types'; + +const CFDProviders = ({ children, store }: React.PropsWithChildren<{ store: TCoreStores }>) => { + return ( + + {children} + + ); +}; + +export default CFDProviders; diff --git a/packages/cfd/src/types/cfd-store.types.ts b/packages/cfd/src/types/cfd-store.types.ts new file mode 100644 index 000000000000..57d29e7e4650 --- /dev/null +++ b/packages/cfd/src/types/cfd-store.types.ts @@ -0,0 +1,97 @@ +import { DetailsOfEachMT5Loginid, Mt5NewAccount, VerifyEmailResponse } from '@deriv/api-types'; +import { TTradingPlatformAvailableAccount } from 'Components/props.types'; +import { TCFDPasswordFormValues } from 'Containers/cfd-password-modal'; +import { TDerivezCompanies, TDxCompanies, TMtCompanies } from 'Stores/Modules/CFD/Helpers/cfd-config'; +import { FormikHelpers } from 'formik'; + +type TStoreProofOfAddressArgs = { + file_uploader_ref: HTMLDivElement | null; + values: { + [key: string]: string; + }; +}; + +export type TCFDStore = { + setMT5TradeAccount: (arg: T) => void; + toggleCFDVerificationModal: () => void; + setJurisdictionSelectedShortcode: (shortcode: string) => void; + setAccountType: (account_type: { category: string; type?: string }) => void; + dxtrade_tokens: { + demo: string; + real: string; + }; + derivez_tokens: { + demo: string; + real: string; + }; + mt5_trade_account: Required< + DetailsOfEachMT5Loginid & { market_type?: TTradingPlatformAvailableAccount['market_type'] | 'synthetic' } + >; + real_synthetic_accounts_existing_data: DetailsOfEachMT5Loginid & DetailsOfEachMT5Loginid[]; + real_swapfree_accounts_existing_data: DetailsOfEachMT5Loginid & DetailsOfEachMT5Loginid[]; + real_financial_accounts_existing_data: DetailsOfEachMT5Loginid & DetailsOfEachMT5Loginid[]; + account_type: { + type: string; + category: string; + }; + jurisdiction_selected_shortcode: string; + toggleJurisdictionModal: () => void; + has_submitted_cfd_personal_details: boolean; + is_jurisdiction_modal_visible: boolean; + clearCFDError: () => void; + current_list: Record; + is_compare_accounts_visible: boolean; + toggleCompareAccountsModal: () => void; + dxtrade_companies: TDxCompanies; + derivez_companies: TDerivezCompanies; + mt5_companies: TMtCompanies; + platform: string; + topUpVirtual: (platform: string) => void; + current_account?: DetailsOfEachMT5Loginid & { + display_login: string; + category: string; + type: string; + }; + sendVerifyEmail: () => Promise; + account_title: string; + disableCFDPasswordModal: () => void; + error_message: string; + error_type?: string; + getAccountStatus: (platform: string) => void; + has_cfd_error: boolean; + is_cfd_password_modal_enabled: boolean; + is_cfd_success_dialog_enabled: boolean; + setCFDSuccessDialog: (value: boolean) => void; + setError: (state: boolean, obj?: Error) => void; + submitMt5Password: (values: TCFDPasswordFormValues, actions: FormikHelpers) => void; + submitCFDPassword: ( + values: TCFDPasswordFormValues & { platform?: string }, + actions: FormikHelpers + ) => void; + new_account_response: Mt5NewAccount; + is_cfd_verification_modal_visible: boolean; + has_created_account_for_selected_jurisdiction: boolean; + enableCFDPasswordModal: () => void; + onMount: () => void; + onUnmount: () => void; + setCurrentAccount: ( + data: DetailsOfEachMT5Loginid, + meta: { + category: string; + type?: string; + } + ) => void; + getRealSyntheticAccountsExistingData: (getRealSyntheticAccountsExistingData?: DetailsOfEachMT5Loginid[]) => void; + getRealFinancialAccountsExistingData: (getRealSyntheticAccountsExistingData?: DetailsOfEachMT5Loginid[]) => void; + toggleMT5TradeModal: () => void; + beginRealSignupForMt5: () => void; + checkShouldOpenAccount: () => void; + is_mt5_trade_modal_visible: boolean; + createCFDAccount: (objCFDAccount: { + category: string; + type: string; + set_password?: number; + platform?: string; + }) => void; + storeProofOfAddress: TStoreProofOfAddressArgs; +}; diff --git a/packages/cfd/tsconfig.json b/packages/cfd/tsconfig.json index 98d7ae73fb36..7e2de89e1576 100644 --- a/packages/cfd/tsconfig.json +++ b/packages/cfd/tsconfig.json @@ -16,6 +16,6 @@ "outDir": "./dist", "baseUrl": "./" }, - "include": ["src", "globals.d.ts", "@deriv-stores.d.ts"], + "include": ["src", "globals.d.ts"], "exclude": ["**/__tests__/**/*"] } diff --git a/packages/stores/src/mockStore.ts b/packages/stores/src/mockStore.ts index 080694a3d746..a6d20e11ec82 100644 --- a/packages/stores/src/mockStore.ts +++ b/packages/stores/src/mockStore.ts @@ -58,7 +58,7 @@ const mock = (): TStores & { is_mock: boolean } => { submissions_left: 3, }, manual: { - status: 'verified', + status: 'none', }, onfido: { country_code: 'IDN', @@ -149,8 +149,12 @@ const mock = (): TStores & { is_mock: boolean } => { responseMt5LoginList: jest.fn(), responseTradingPlatformAccountsList: jest.fn(), standpoint: { - iom: '', - malta: '', + financial_company: '', + gaming_company: '', + maltainvest: false, + svg: false, + iom: false, + malta: false, }, switchAccount: jest.fn(), verification_code: { @@ -187,6 +191,51 @@ const mock = (): TStores & { is_mock: boolean } => { switched: false, switch_broadcast: false, switchEndSignal: jest.fn(), + is_uk: false, + isEligibleForMoreRealMt5: jest.fn(), + isEligibleForMoreDemoMt5Svg: jest.fn(), + updateMT5Status: jest.fn(), + is_high_risk: false, + fetchResidenceList: jest.fn(), + residence_list: [], + should_restrict_bvi_account_creation: false, + should_restrict_vanuatu_account_creation: false, + fetchAccountSettings: jest.fn(), + setAccountSettings: jest.fn(), + upgradeable_landing_companies: [], + is_populating_mt5_account_list: false, + landing_companies: {}, + landing_company: {}, + getChangeableFields: jest.fn(), + isAccountOfTypeDisabled: jest.fn(), + is_mt5_allowed: false, + mt5_disabled_signup_types: { + real: false, + demo: false, + }, + dxtrade_disabled_signup_types: { + real: false, + demo: false, + }, + dxtrade_accounts_list_error: null, + has_account_error_in_mt5_demo_list: false, + has_account_error_in_mt5_real_list: false, + has_account_error_in_dxtrade_demo_list: false, + has_account_error_in_dxtrade_real_list: false, + website_status: { + dx_trade_status: { + all: 0, + demo: 0, + real: 0, + }, + mt5_status: { + real: [], + demo: [], + }, + }, + is_fully_authenticated: false, + states_list: [], + fetchStatesList: jest.fn(), is_crypto: jest.fn(), dxtrade_accounts_list: [], derivez_accounts_list: [], @@ -196,8 +245,8 @@ const mock = (): TStores & { is_mock: boolean } => { setTwoFAStatus: jest.fn(), has_changed_two_fa: false, setTwoFAChangedStatus: jest.fn(), + real_account_creation_unlock_date: '', has_any_real_account: false, - real_account_creation_unlock_date: 0, setPrevAccountType: jest.fn(), }, common: { @@ -224,6 +273,9 @@ const mock = (): TStores & { is_mock: boolean } => { is_network_online: false, server_time: undefined, is_language_changing: false, + setAppstorePlatform: jest.fn(), + app_routing_history: [], + getExchangeRate: jest.fn(), }, ui: { app_contents_scroll_ref: { @@ -244,7 +296,7 @@ const mock = (): TStores & { is_mock: boolean } => { setDarkMode: jest.fn(), setReportsTabIndex: jest.fn(), has_real_account_signup_ended: false, - notification_messages_ui: null, + notification_messages_ui: jest.fn(), openRealAccountSignup: jest.fn(), setIsClosingCreateRealAccountModal: jest.fn(), setRealAccountSignupEnd: jest.fn(), @@ -265,9 +317,26 @@ const mock = (): TStores & { is_mock: boolean } => { is_real_acc_signup_on: false, is_need_real_account_for_cashier_modal_visible: false, toggleNeedRealAccountForCashierModal: jest.fn(), + setIsAcuityModalOpen: jest.fn(), + is_switch_to_deriv_account_modal_visible: false, + openSwitchToRealAccountModal: jest.fn(), + is_top_up_virtual_open: false, + is_top_up_virtual_in_progress: false, + is_top_up_virtual_success: false, + closeTopUpModal: jest.fn(), + closeSuccessTopUpModal: jest.fn(), + is_cfd_reset_password_modal_enabled: false, + setCFDPasswordResetModal: jest.fn(), + openDerivRealAccountNeededModal: jest.fn(), populateHeaderExtensions: jest.fn(), populateSettingsExtensions: jest.fn(), setShouldShowCooldownModal: jest.fn(), + openAccountNeededModal: jest.fn(), + is_accounts_switcher_on: false, + openTopUpModal: jest.fn(), + toggleShouldShowRealAccountsList: jest.fn(), + is_reset_trading_password_modal_visible: false, + setResetTradingPasswordModalOpen: jest.fn(), }, traders_hub: { closeModal: jest.fn(), @@ -284,6 +353,23 @@ const mock = (): TStores & { is_mock: boolean } => { selectRegion: jest.fn(), setSelectedAccount: jest.fn(), is_low_risk_cr_eu_real: false, + show_eu_related_content: false, + platform_real_balance: { + currency: '', + balance: 0, + }, + cfd_demo_balance: { + currency: '', + balance: 0, + }, + platform_demo_balance: { + currency: '', + balance: 0, + }, + cfd_real_balance: { + currency: '', + balance: 0, + }, closeAccountTransferModal: jest.fn(), toggleRegulatorsCompareModal: jest.fn(), selected_region: '', @@ -304,6 +390,7 @@ const mock = (): TStores & { is_mock: boolean } => { }, notifications: { addNotificationMessage: jest.fn(), + addNotificationMessageByKey: jest.fn(), client_notifications: {}, filterNotificationMessages: jest.fn(), refreshNotifications: jest.fn(), diff --git a/packages/stores/types.ts b/packages/stores/types.ts index ad3723e9bb41..0b8532114400 100644 --- a/packages/stores/types.ts +++ b/packages/stores/types.ts @@ -1,12 +1,16 @@ +import type { ElementType } from 'react'; import type { AccountLimitsResponse, Authorize, DetailsOfEachMT5Loginid, GetAccountStatus, GetLimits, - GetSettings, - LogOutResponse, ProposalOpenContract, + LogOutResponse, + ResidenceList, + LandingCompany, + StatesList, + GetSettings, } from '@deriv/api-types'; import type { Moment } from 'moment'; import type { RouteComponentProps } from 'react-router'; @@ -18,6 +22,14 @@ type TPopulateSettingsExtensionsMenuItem = { value: (props: T) => JSX.Element; }; +type TAppRoutingHistory = { + action: string; + hash: string; + key: string; + pathname: string; + search: string; +}; + type TAccount = NonNullable[0] & { balance?: number; }; @@ -70,7 +82,7 @@ type TTradingPlatformAvailableAccount = { }; signup: string[]; }; - shortcode: 'bvi' | 'labuan' | 'svg' | 'vanuatu'; + shortcode: 'bvi' | 'labuan' | 'svg' | 'vanuatu' | 'maltainvest'; sub_account_type: string; }; @@ -127,9 +139,29 @@ type TNotification = | ((withdrawal_locked: boolean, deposit_locked: boolean) => TNotificationMessage) | ((excluded_until: number) => TNotificationMessage); +type TStandPoint = { + financial_company: string; + gaming_company: string; + iom: boolean; + malta: boolean; + maltainvest: boolean; + svg: boolean; +}; + +type TMt5StatusServerType = { + all: number; + platform: number; + server_number: number; + deposits?: number; + withdrawals?: number; +}; + +type TDXTraderStatusServerType = Record<'all' | 'demo' | 'real', number>; + +type TMt5StatusServer = Record<'demo' | 'real', TMt5StatusServerType[]>; + type TClientStore = { accounts: { [k: string]: TActiveAccount }; - is_eu_country: boolean; active_accounts: TActiveAccount[]; active_account_landing_company: string; trading_platform_available_accounts: TTradingPlatformAvailableAccount[]; @@ -138,8 +170,7 @@ type TClientStore = { api_initial_load_error?: string; }; account_list: TAccountsList; - account_settings: GetSettings; - account_status: Omit & Partial>; + account_status: GetAccountStatus; available_crypto_currencies: string[]; balance?: string | number; can_change_fiat_currency: boolean; @@ -156,7 +187,9 @@ type TClientStore = { is_account_setting_loaded: boolean; is_deposit_lock: boolean; is_dxtrade_allowed: boolean; + is_eu_country: boolean; is_eu: boolean; + is_uk: boolean; is_authorize: boolean; is_financial_account: boolean; is_financial_information_incomplete: boolean; @@ -190,10 +223,7 @@ type TClientStore = { }: { trading_platform_accounts: DetailsOfEachMT5Loginid[]; }) => DetailsOfEachMT5Loginid[]; - standpoint: { - iom: string; - malta: string; - }; + standpoint: TStandPoint; setAccountStatus: (status?: GetAccountStatus) => void; setBalanceOtherAccounts: (balance: number) => void; setInitialized: (status?: boolean) => void; @@ -215,6 +245,7 @@ type TClientStore = { trading_platform_dxtrade_password_reset: string; trading_platform_mt5_password_reset: string; }; + website_status: { mt5_status: TMt5StatusServer; dx_trade_status: TDXTraderStatusServerType }; email: string; setVerificationCode: (code: string, action: string) => void; updateAccountStatus: () => Promise; @@ -223,6 +254,43 @@ type TClientStore = { mt5_login_list: DetailsOfEachMT5Loginid[]; logout: () => Promise; should_allow_authentication: boolean; + isEligibleForMoreDemoMt5Svg: (market_type: 'synthetic' | 'financial' | 'gaming' | 'all') => boolean; + isEligibleForMoreRealMt5: (market_type: 'synthetic' | 'financial' | 'gaming' | 'all') => boolean; + fetchResidenceList?: () => Promise; + account_settings: GetSettings & { + upload_file?: string; + poi_state?: string; + }; + residence_list: ResidenceList; + is_high_risk: boolean; + should_restrict_bvi_account_creation: boolean; + should_restrict_vanuatu_account_creation: boolean; + updateMT5Status: () => Promise; + fetchAccountSettings: () => Promise; + setAccountSettings: (get_settings_response: GetSettings) => void; + upgradeable_landing_companies: unknown[]; + is_populating_mt5_account_list: boolean; + landing_companies: LandingCompany; + getChangeableFields: () => string[]; + landing_company: LandingCompany; + isAccountOfTypeDisabled: (account: Record) => boolean; + is_mt5_allowed: boolean; + mt5_disabled_signup_types: { + real: boolean; + demo: boolean; + }; + dxtrade_disabled_signup_types: { + real: boolean; + demo: boolean; + }; + dxtrade_accounts_list_error: null; + has_account_error_in_mt5_real_list: boolean; + has_account_error_in_mt5_demo_list: boolean; + has_account_error_in_dxtrade_real_list: boolean; + has_account_error_in_dxtrade_demo_list: boolean; + is_fully_authenticated: boolean; + states_list: StatesList; + fetchStatesList: () => Promise; is_crypto: (currency?: string) => boolean; dxtrade_accounts_list: DetailsOfEachMT5Loginid[]; derivez_accounts_list: DetailsOfEachMT5Loginid[]; @@ -232,13 +300,13 @@ type TClientStore = { setTwoFAStatus: (status: boolean) => void; has_changed_two_fa: boolean; setTwoFAChangedStatus: (status: boolean) => void; + real_account_creation_unlock_date: string; has_any_real_account: boolean; - real_account_creation_unlock_date: number; setPrevAccountType: (account_type: string) => void; }; type TCommonStoreError = { - app_routing_history: unknown[]; + app_routing_history: TAppRoutingHistory[]; header: string | JSX.Element; message: string | JSX.Element; redirect_label: string; @@ -255,7 +323,7 @@ type TCommonStore = { has_error: boolean; is_from_derivgo: boolean; is_network_online: boolean; - platform: string; + platform: 'dxtrade' | 'derivez' | 'mt5' | 'ctrader' | ''; routeBackInApp: (history: Pick, additional_platform_path?: string[]) => void; routeTo: (pathname: string) => void; server_time?: Moment; @@ -263,6 +331,9 @@ type TCommonStore = { changeSelectedLanguage: (key: string) => void; current_language: string; is_language_changing: boolean; + setAppstorePlatform: (value: string) => void; + app_routing_history: TAppRoutingHistory[]; + getExchangeRate: (from_currency: string, to_currency: string) => Promise; }; type TUiStore = { @@ -281,7 +352,7 @@ type TUiStore = { openRealAccountSignup: ( value: 'maltainvest' | 'svg' | 'add_crypto' | 'choose' | 'add_fiat' | 'set_currency' | 'manage' ) => void; - notification_messages_ui: React.FC | null; + notification_messages_ui: ElementType; setCurrentFocus: (value: string) => void; setDarkMode: (is_dark_mode_on: boolean) => boolean; setReportsTabIndex: (value: number) => void; @@ -305,6 +376,23 @@ type TUiStore = { is_real_acc_signup_on: boolean; is_need_real_account_for_cashier_modal_visible: boolean; toggleNeedRealAccountForCashierModal: () => void; + setIsAcuityModalOpen: (value: boolean) => void; + is_switch_to_deriv_account_modal_visible: boolean; + openSwitchToRealAccountModal: () => void; + openDerivRealAccountNeededModal: () => void; + is_top_up_virtual_open: boolean; + is_top_up_virtual_in_progress: boolean; + is_top_up_virtual_success: boolean; + closeSuccessTopUpModal: () => void; + closeTopUpModal: () => void; + is_cfd_reset_password_modal_enabled: boolean; + setCFDPasswordResetModal: (value: boolean) => void; + openAccountNeededModal: () => void; + is_accounts_switcher_on: boolean; + openTopUpModal: () => void; + toggleShouldShowRealAccountsList: () => void; + is_reset_trading_password_modal_visible: boolean; + setResetTradingPasswordModalOpen: () => void; populateHeaderExtensions: (header_items: JSX.Element | null) => void; populateSettingsExtensions: (menu_items: Array | null) => void; setShouldShowCooldownModal: (value: boolean) => void; @@ -334,6 +422,7 @@ type TMenuStore = { type TNotificationStore = { addNotificationMessage: (message: TNotification) => void; + addNotificationMessageByKey: (key: string) => void; client_notifications: object; filterNotificationMessages: () => void; refreshNotifications: () => void; @@ -344,6 +433,11 @@ type TNotificationStore = { setP2PRedirectTo: () => void; }; +type TBalance = { + currency: string; + balance: number; +}; + type TTradersHubStore = { closeModal: () => void; content_flag: 'low_risk_cr_eu' | 'low_risk_cr_non_eu' | 'high_risk_cr' | 'cr_demo' | 'eu_demo' | 'eu_real' | ''; @@ -361,6 +455,7 @@ type TTradersHubStore = { }; is_low_risk_cr_eu_real: boolean; is_eu_user: boolean; + show_eu_related_content: boolean; setTogglePlatformType: (platform_type: string) => void; is_real: boolean; selectRegion: (region: string) => void; @@ -377,6 +472,10 @@ type TTradersHubStore = { CFDs_restricted_countries: boolean; toggleAccountTransferModal: () => void; is_demo: boolean; + platform_real_balance: TBalance; + cfd_demo_balance: TBalance; + platform_demo_balance: TBalance; + cfd_real_balance: TBalance; selectAccountType: (account_type: string) => void; };