diff --git a/packages/account/src/Components/account-limits/__tests__/account-limits.spec.js b/packages/account/src/Components/account-limits/__tests__/account-limits.spec.tsx similarity index 87% rename from packages/account/src/Components/account-limits/__tests__/account-limits.spec.js rename to packages/account/src/Components/account-limits/__tests__/account-limits.spec.tsx index 5abe6a692b6a..5b5353ee6c45 100644 --- a/packages/account/src/Components/account-limits/__tests__/account-limits.spec.js +++ b/packages/account/src/Components/account-limits/__tests__/account-limits.spec.tsx @@ -7,7 +7,7 @@ import { BrowserRouter } from 'react-router-dom'; jest.mock('Stores/connect.js', () => ({ __esModule: true, default: 'mockedDefaultExport', - connect: () => Component => Component, + connect: () => (Component: React.ReactElement) => Component, })); jest.mock('@deriv/components', () => { @@ -31,11 +31,12 @@ jest.mock('Components/load-error-message', () => jest.fn(() => 'mockedLoadErrorM jest.mock('../account-limits-footer', () => jest.fn(() => 'mockedAccountLimitsFooter')); describe('', () => { - const props = { + const props: React.ComponentProps = { currency: 'AUD', is_fully_authenticated: true, is_switching: false, is_virtual: false, + overlay_ref: document.createElement('div'), getLimits: jest.fn(() => Promise.resolve({ data: {} })), account_limits: { account_balance: 300000, @@ -66,9 +67,9 @@ describe('', () => { cryptocurrency: [ { name: 'Cryptocurrencies', - payout_limit: '100.00', + payout_limit: 100.0, profile_name: 'extreme_risk', - turnover_limit: '1000.00', + turnover_limit: 1000.0, }, ], forex: [ @@ -124,15 +125,31 @@ describe('', () => { }); it('should render DemoMessage component if is_virtual is true', () => { - const { container } = render(); - expect(container.firstChild).toHaveClass('account__demo-message-wrapper'); - + render(); + expect(screen.queryByTestId('dt_account_demo_message_wrapper')).toHaveClass('account__demo-message-wrapper'); expect(screen.getByText('mockedDemoMessage')).toBeInTheDocument(); }); it('should render LoadErrorMessage component if there is api_initial_load_error', () => { render( - + ); expect(screen.getByText('mockedLoadErrorMessage')).toBeInTheDocument(); }); @@ -153,8 +170,8 @@ describe('', () => { }); it('should render AccountLimitsArticle component if should_show_article is true and is_from_derivgo is false in mobile mode', () => { - isMobile.mockReturnValue(true); - isDesktop.mockReturnValue(false); + (isMobile as jest.Mock).mockReturnValue(true); + (isDesktop as jest.Mock).mockReturnValue(false); render(); expect(screen.getByRole('heading', { name: /account limits/i })).toBeInTheDocument(); expect( @@ -163,8 +180,8 @@ describe('', () => { }); it('should render AccountLimitsArticle component if should_show_article is true and is_from_derivgo is true in mobile mode', () => { - isMobile.mockReturnValue(true); - isDesktop.mockReturnValue(false); + (isMobile as jest.Mock).mockReturnValue(true); + (isDesktop as jest.Mock).mockReturnValue(false); render(); expect(screen.getByRole('heading', { name: /account limits/i })).toBeInTheDocument(); expect( @@ -173,8 +190,8 @@ describe('', () => { }); it('should not render AccountLimitsArticle component if should_show_article is false', () => { - isMobile.mockReturnValue(true); - isDesktop.mockReturnValue(false); + (isMobile as jest.Mock).mockReturnValue(true); + (isDesktop as jest.Mock).mockReturnValue(false); render(); expect(screen.queryByText('/account limits/i')).not.toBeInTheDocument(); }); @@ -210,7 +227,7 @@ describe('', () => { const { open_positions } = props.account_limits; expect( screen.getByRole('cell', { - name: open_positions, + name: open_positions?.toString(), }) ).toBeInTheDocument(); }); @@ -300,13 +317,10 @@ describe('', () => { ); expect(screen.getByText(/to increase limit please verify your identity/i)).toBeInTheDocument(); - expect( - screen - .getByRole('link', { - name: /verify/i, - }) - .closest('a') + screen.getByRole('link', { + name: /verify/i, + }) ).toHaveAttribute('href', '/account/proof-of-identity'); const { num_of_days_limit } = props.account_limits; expect(formatMoney).toHaveBeenCalledWith(props.currency, num_of_days_limit, true); @@ -330,8 +344,8 @@ describe('', () => { }); it('should show limit_notice message when is_appstore is true and is_fully_authenticated is false in mobile mode', () => { - isDesktop.mockReturnValue(false); - isMobile.mockReturnValue(true); + (isMobile as jest.Mock).mockReturnValue(true); + (isDesktop as jest.Mock).mockReturnValue(false); render( @@ -343,8 +357,8 @@ describe('', () => { }); it('should not show limit_notice message when is_appstore is false and is_fully_authenticated is false', () => { - isDesktop.mockReturnValue(true); - isMobile.mockReturnValue(false); + (isMobile as jest.Mock).mockReturnValue(false); + (isDesktop as jest.Mock).mockReturnValue(true); render( @@ -358,8 +372,8 @@ describe('', () => { }); it('should show AccountLimitsArticle when should_show_article and isDesktop is true', () => { - isDesktop.mockReturnValue(true); - isMobile.mockReturnValue(false); + (isMobile as jest.Mock).mockReturnValue(false); + (isDesktop as jest.Mock).mockReturnValue(true); render(); expect(screen.getByRole('heading', { name: /account limits/i })).toBeInTheDocument(); expect(screen.getByText(/these are default limits that we apply to your accounts\./i)).toBeInTheDocument(); @@ -367,16 +381,15 @@ describe('', () => { screen.getByText(/to learn more about trading limits and how they apply, please go to the/i) ).toBeInTheDocument(); expect( - screen - .getByRole('link', { - name: /help centre/i, - }) - .closest('a') + screen.getByRole('link', { + name: /help centre/i, + }) ).toHaveAttribute('href', 'https://deriv.com/help-centre/trading/#trading-limits'); }); it('should show AccountLimitsFooter if footer_ref is passed', () => { - const footer = { current: { offsetWidth: 100 } }; + const footer = React.createRef(); + render(); expect(screen.getByText(/mockedaccountlimitsfooter/i)).toBeInTheDocument(); }); diff --git a/packages/account/src/Components/account-limits/account-limits-turnover-limit-row.tsx b/packages/account/src/Components/account-limits/account-limits-turnover-limit-row.tsx index ffbae261b3a8..2fd4b11e538f 100644 --- a/packages/account/src/Components/account-limits/account-limits-turnover-limit-row.tsx +++ b/packages/account/src/Components/account-limits/account-limits-turnover-limit-row.tsx @@ -3,8 +3,8 @@ import { formatMoney } from '@deriv/shared'; import AccountLimitsTableCell from './account-limits-table-cell'; import AccountLimitsContext, { TAccountLimitsContext } from './account-limits-context'; -type TAccountLimits = { - level: string; +export type TAccountLimitsCollection = { + level?: string; name: string; payout_limit: number; profile_name: string; @@ -12,8 +12,8 @@ type TAccountLimits = { }; type TAccountLimitsTurnoverLimitRow = { - collection: TAccountLimits[]; - title: string; + collection: TAccountLimitsCollection[]; + title?: string; }; const AccountLimitsTurnoverLimitRow = ({ collection, title }: TAccountLimitsTurnoverLimitRow) => { diff --git a/packages/account/src/Components/account-limits/account-limits.jsx b/packages/account/src/Components/account-limits/account-limits.tsx similarity index 87% rename from packages/account/src/Components/account-limits/account-limits.jsx rename to packages/account/src/Components/account-limits/account-limits.tsx index c6590f36c67c..f7be2ea9acca 100644 --- a/packages/account/src/Components/account-limits/account-limits.jsx +++ b/packages/account/src/Components/account-limits/account-limits.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import * as React from 'react'; import classNames from 'classnames'; import { Loading, ThemedScrollbars, Text, ButtonLink } from '@deriv/components'; @@ -7,13 +6,54 @@ import { Localize, localize } from '@deriv/translations'; import LoadErrorMessage from 'Components/load-error-message'; import DemoMessage from 'Components/demo-message'; import AccountLimitsArticle from './account-limits-article'; -import AccountLimitsContext from './account-limits-context'; +import AccountLimitsContext, { TAccountLimitsContext } from './account-limits-context'; import AccountLimitsExtraInfo from './account-limits-extra-info'; import AccountLimitsFooter from './account-limits-footer'; import AccountLimitsOverlay from './account-limits-overlay'; import AccountLimitsTableCell from './account-limits-table-cell'; import AccountLimitsTableHeader from './account-limits-table-header'; -import AccountLimitsTurnoverLimitRow from './account-limits-turnover-limit-row'; +import AccountLimitsTurnoverLimitRow, { TAccountLimitsCollection } from './account-limits-turnover-limit-row'; +import { FormikValues } from 'formik'; + +type TAccountLimits = { + account_limits: { + api_initial_load_error?: string; + open_positions?: React.ReactNode; + account_balance: string | number; + daily_transfers?: object; + payout: string | number; + lifetime_limit?: number; + market_specific: { + commodities: TAccountLimitsCollection[]; + cryptocurrency: TAccountLimitsCollection[]; + forex: TAccountLimitsCollection[]; + indices: TAccountLimitsCollection[]; + synthetic_index: TAccountLimitsCollection[]; + }; + num_of_days?: number; + num_of_days_limit: string | number; + remainder: string | number; + withdrawal_for_x_days_monetary?: number; + withdrawal_since_inception_monetary: string | number; + }; + currency: string; + footer_ref?: React.RefObject; + is_app_settings?: boolean; + getLimits: () => Promise<{ data: object }>; + is_fully_authenticated: boolean; + is_from_derivgo?: boolean; + is_switching: boolean; + is_virtual: boolean; + overlay_ref: HTMLDivElement; + setIsOverlayShown?: (is_overlay_shown: boolean | undefined) => void; + setIsPopupOverlayShown?: (is_popup_overlay_shown: boolean) => void; + should_bypass_scrollbars?: boolean; + should_show_article?: boolean; +}; + +type TPlarformContext = { + is_appstore: boolean; +}; const AccountLimits = ({ account_limits, @@ -29,11 +69,11 @@ const AccountLimits = ({ setIsOverlayShown: setIsPopupOverlayShown, should_bypass_scrollbars, should_show_article, -}) => { +}: TAccountLimits) => { const isMounted = useIsMounted(); const [is_loading, setLoading] = React.useState(false); const [is_overlay_shown, setIsOverlayShown] = React.useState(false); - const { is_appstore } = React.useContext(PlatformContext); + const { is_appstore } = React.useContext>(PlatformContext); React.useEffect(() => { if (is_virtual) { @@ -67,6 +107,7 @@ const AccountLimits = ({ if (is_virtual) { return (
; @@ -96,17 +137,14 @@ const AccountLimits = ({ } const { commodities, forex, indices, synthetic_index } = { ...market_specific }; - const forex_ordered = forex?.slice().sort((a, b) => (a.name > b.name ? 1 : b.name > a.name ? -1 : 0)); - // sort submarkets by names alphabetically and put 'market' at the beginning + const forex_ordered = forex + ?.slice() + .sort((a: FormikValues, b: FormikValues) => (a.name > b.name ? 1 : b.name > a.name ? -1 : 0)); const derived_ordered = synthetic_index ?.slice() - .sort((a, b) => - a.level === 'submarket' && b.level === 'submarket' - ? a.name.localeCompare(b.name) - : a.level.localeCompare(b.level) - ); + .sort((a: FormikValues, b: FormikValues) => (a.level < b.level ? 1 : -1)); - const context_value = { + const context_value: TAccountLimitsContext = { currency, footer_ref, overlay_ref, @@ -163,12 +201,7 @@ const AccountLimits = ({ - {/* null or 0 are expected form BE when max balance limit is not set */} - {account_balance ? ( - formatMoney(currency, account_balance, true) - ) : ( - - )} + {formatMoney(currency, account_balance, true)} @@ -255,11 +288,13 @@ const AccountLimits = ({ - {is_appstore ? ( - - ) : ( - - )} + {is_appstore && !is_fully_authenticated && (