From c7a33d9309ec4b334fbcb21e1409f60b7d00df20 Mon Sep 17 00:00:00 2001 From: Likhith Kolayari Date: Mon, 28 Aug 2023 12:56:08 +0400 Subject: [PATCH 1/4] refactor: :art: migrated account component to TSX --- .../src/Containers/Account/account.jsx | 148 +++++++++++++ .../Account/page-overlay-wrapper.tsx | 75 +++++++ .../Containers/Account/tradinghub-logout.tsx | 22 ++ packages/account/src/Containers/account.jsx | 195 ------------------ packages/account/src/Sections/index.js | 2 +- .../components/vertical-tab/vertical-tab.tsx | 2 +- packages/shared/src/utils/route/route.ts | 8 +- 7 files changed, 251 insertions(+), 201 deletions(-) create mode 100644 packages/account/src/Containers/Account/account.jsx create mode 100644 packages/account/src/Containers/Account/page-overlay-wrapper.tsx create mode 100644 packages/account/src/Containers/Account/tradinghub-logout.tsx delete mode 100644 packages/account/src/Containers/account.jsx diff --git a/packages/account/src/Containers/Account/account.jsx b/packages/account/src/Containers/Account/account.jsx new file mode 100644 index 000000000000..7ab146040dd1 --- /dev/null +++ b/packages/account/src/Containers/Account/account.jsx @@ -0,0 +1,148 @@ +import React from 'react'; +import { withRouter } from 'react-router-dom'; +import { FadeWrapper, Loading } from '@deriv/components'; +import { matchRoute, routes as shared_routes } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; +import { flatten } from '../../Helpers/flatten'; +import PageOverlayWrapper from './page-overlay-wrapper'; +import 'Styles/account.scss'; + +// const onClickLogout = (logout, history) => { +// history.push(shared_routes.index); +// logout().then(() => (window.location.href = getStaticUrl('/'))); +// }; + +// const PageOverlayWrapper = ({ +// is_from_derivgo, +// is_appstore, +// list_groups, +// logout, +// onClickClose, +// selected_route, +// subroutes, +// history, +// }) => { +// const routeToPrevious = () => history.push(shared_routes.traders_hub); + +// if (isMobile() && selected_route) { +// return ( +// +// +// +// ); +// } +// return ( +// +// } +// /> +// +// ); +// }; + +/** + * Component that renders the account section + * @name Account + * @param history - history object passed from react-router-dom + * @param location - location object passed from react-router-dom + * @param routes - routes object passed from react-router-dom + * @returns React component + */ +const Account = observer(({ history, location, routes }) => { + const { client, ui } = useStore(); + const { + is_virtual, + is_logged_in, + is_logging_in, + is_risky_client, + is_pending_proof_of_ownership, + landing_company_shortcode, + should_allow_authentication, + // logout, + } = client; + // const { routeBackInApp } = common; + const { toggleAccountSettings, is_account_settings_visible } = ui; + // const { is_appstore } = React.useContext(PlatformContext); + const subroutes = flatten(routes.map(i => i.subroutes)); + // let list_groups = [...routes]; + // list_groups = list_groups.map(route_group => ({ + // icon: route_group.icon, + // label: route_group.getTitle(), + // subitems: route_group.subroutes.map(sub => subroutes.indexOf(sub)), + // })); + let selected_content = subroutes.find(r => matchRoute(r, location.pathname)); + // const onClickClose = React.useCallback(() => routeBackInApp(history), [routeBackInApp, history]); + + React.useEffect(() => { + toggleAccountSettings(true); + }, [toggleAccountSettings]); + + routes.forEach(menu_item => { + menu_item.subroutes.forEach(route => { + if (route.path === shared_routes.financial_assessment) { + route.is_disabled = is_virtual || (landing_company_shortcode === 'maltainvest' && !is_risky_client); + } + + if (route.path === shared_routes.trading_assessment) { + route.is_disabled = is_virtual || landing_company_shortcode !== 'maltainvest'; + } + + if (route.path === shared_routes.proof_of_identity || route.path === shared_routes.proof_of_address) { + route.is_disabled = !should_allow_authentication; + } + + if (route.path === shared_routes.proof_of_ownership) { + route.is_disabled = is_virtual || !is_pending_proof_of_ownership; + } + }); + }); + + if (!selected_content) { + // fallback + selected_content = subroutes[0]; + history.push(shared_routes.personal_details); + } + + if (!is_logged_in && is_logging_in) { + return ; + } + + // const selected_route = getSelectedRoute({ routes: subroutes, pathname: location.pathname }); + + return ( + +
+ {/* */} + +
+
+ ); +}); + +Account.displayName = 'Account'; + +export default withRouter(Account); diff --git a/packages/account/src/Containers/Account/page-overlay-wrapper.tsx b/packages/account/src/Containers/Account/page-overlay-wrapper.tsx new file mode 100644 index 000000000000..e36e55d54e27 --- /dev/null +++ b/packages/account/src/Containers/Account/page-overlay-wrapper.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { useHistory } from 'react-router-dom'; +import { PageOverlay, VerticalTab } from '@deriv/components'; +import { TRoute, getSelectedRoute, getStaticUrl, routes as shared_routes } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; +import TradingHubLogout from './tradinghub-logout'; +import { Localize } from '@deriv/translations'; + +type RouteItems = React.ComponentProps['list']; +type RouteRef = Array; + +type PageOverlayWrapperProps = { + routes: RouteRef; + subroutes: RouteItems; +}; + +/** + * @name PageOverlayWrapper + * @param routes - routes object pased by react-router-dom + * @param subroutes - list of subroutes + */ +const PageOverlayWrapper = observer(({ routes, subroutes }: PageOverlayWrapperProps) => { + const history = useHistory(); + const { client, common, ui } = useStore(); + const { is_mobile } = ui; + const { logout } = client; + const { is_from_derivgo, routeBackInApp } = common; + + // const routeToPrevious = () => history.push(shared_routes.traders_hub); + + const list_groups = routes.map(route_group => ({ + icon: route_group.icon, + label: route_group.getTitle(), + subitems: route_group.subroutes.map(sub => subroutes.indexOf(sub)), + })); + + const onClickClose = React.useCallback(() => routeBackInApp(history), [routeBackInApp, history]); + + const selected_route = getSelectedRoute({ routes: subroutes as Array, pathname: location.pathname }); + + const onClickLogout = () => { + history.push(shared_routes.index); + logout().then(() => (window.location.href = getStaticUrl('/'))); + }; + + if (is_mobile && selected_route) { + const RouteComponent = selected_route.component as React.ElementType<{ component_icon: string | undefined }>; + return ( + + + + ); + } + return ( + } + onClickClose={onClickClose} + is_from_app={is_from_derivgo} + > + } + /> + + ); +}); + +PageOverlayWrapper.displayName = 'PageOverlayWrapper'; + +export default PageOverlayWrapper; diff --git a/packages/account/src/Containers/Account/tradinghub-logout.tsx b/packages/account/src/Containers/Account/tradinghub-logout.tsx new file mode 100644 index 000000000000..ce6942604339 --- /dev/null +++ b/packages/account/src/Containers/Account/tradinghub-logout.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Text, Icon } from '@deriv/components'; +import { Localize } from '@deriv/translations'; + +/** + * Content to be displayed in the side bar + * @name TradingHubLogout + * @param handleOnLogout - function to handle action when user click on logout + * @returns React Component + */ +const TradingHubLogout = ({ handleOnLogout }: { handleOnLogout: () => void }) => ( +
+
+ + + + +
+
+); + +export default TradingHubLogout; diff --git a/packages/account/src/Containers/account.jsx b/packages/account/src/Containers/account.jsx deleted file mode 100644 index a580baa1d4f9..000000000000 --- a/packages/account/src/Containers/account.jsx +++ /dev/null @@ -1,195 +0,0 @@ -import 'Styles/account.scss'; -import { - PlatformContext, - getSelectedRoute, - getStaticUrl, - isMobile, - matchRoute, - routes as shared_routes, -} from '@deriv/shared'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { withRouter } from 'react-router-dom'; -import { VerticalTab, FadeWrapper, PageOverlay, Loading, Text, Icon } from '@deriv/components'; -import { observer, useStore } from '@deriv/stores'; -import { flatten } from '../Helpers/flatten'; -import { localize } from '@deriv/translations'; - -const onClickLogout = (logout, history) => { - history.push(shared_routes.index); - logout().then(() => (window.location.href = getStaticUrl('/'))); -}; - -const AccountLogout = ({ logout, history }) => { - return ( -
onClickLogout(logout, history)}> -
- - {localize('Log out')} - -
-
- ); -}; - -const TradingHubLogout = ({ logout, history }) => { - return ( -
onClickLogout(logout, history)}> -
- - - {localize('Log out')} - -
-
- ); -}; - -const PageOverlayWrapper = ({ - is_from_derivgo, - is_appstore, - list_groups, - logout, - onClickClose, - selected_route, - subroutes, - history, -}) => { - const routeToPrevious = () => history.push(shared_routes.traders_hub); - - if (isMobile() && selected_route) { - return ( - - - - ); - } else if (is_appstore) { - return ( - } - /> - ); - } - - return ( - - } - /> - - ); -}; - -const Account = observer(({ history, location, routes }) => { - const { client, common, ui } = useStore(); - const { - is_virtual, - is_logged_in, - is_logging_in, - is_risky_client, - is_pending_proof_of_ownership, - landing_company_shortcode, - should_allow_authentication, - logout, - } = client; - const { is_from_derivgo, routeBackInApp, platform } = common; - const { toggleAccountSettings, is_account_settings_visible } = ui; - const { is_appstore } = React.useContext(PlatformContext); - const subroutes = flatten(routes.map(i => i.subroutes)); - let list_groups = [...routes]; - list_groups = list_groups.map(route_group => ({ - icon: route_group.icon, - label: route_group.getTitle(), - subitems: route_group.subroutes.map(sub => subroutes.indexOf(sub)), - })); - let selected_content = subroutes.find(r => matchRoute(r, location.pathname)); - const onClickClose = React.useCallback(() => routeBackInApp(history), [routeBackInApp, history]); - - React.useEffect(() => { - toggleAccountSettings(true); - }, [toggleAccountSettings]); - - routes.forEach(menu_item => { - menu_item.subroutes.forEach(route => { - if (route.path === shared_routes.financial_assessment) { - route.is_disabled = is_virtual || (landing_company_shortcode === 'maltainvest' && !is_risky_client); - } - - if (route.path === shared_routes.trading_assessment) { - route.is_disabled = is_virtual || landing_company_shortcode !== 'maltainvest'; - } - - if (route.path === shared_routes.proof_of_identity || route.path === shared_routes.proof_of_address) { - route.is_disabled = !should_allow_authentication; - } - - if (route.path === shared_routes.proof_of_ownership) { - route.is_disabled = is_virtual || !is_pending_proof_of_ownership; - } - }); - }); - - if (!selected_content) { - // fallback - selected_content = subroutes[0]; - history.push(shared_routes.personal_details); - } - - if (!is_logged_in && is_logging_in) { - return ; - } - - const selected_route = getSelectedRoute({ routes: subroutes, pathname: location.pathname }); - - return ( - -
- -
-
- ); -}); - -Account.propTypes = { - active_account_landing_company: PropTypes.string, - history: PropTypes.object, - location: PropTypes.object, - routes: PropTypes.arrayOf(PropTypes.object), -}; - -export default withRouter(Account); diff --git a/packages/account/src/Sections/index.js b/packages/account/src/Sections/index.js index 0326508f030b..f29be0ccb21d 100644 --- a/packages/account/src/Sections/index.js +++ b/packages/account/src/Sections/index.js @@ -9,7 +9,7 @@ import ProofOfOwnership from 'Sections/Verification/ProofOfOwnership'; import TwoFactorAuthentication from 'Sections/Security/TwoFactorAuthentication'; import ApiToken from 'Sections/Security/ApiToken'; import SelfExclusion from 'Sections/Security/SelfExclusion'; -import Account from 'Containers/account.jsx'; +import Account from 'Containers/Account/account.jsx'; import ClosingAccount from 'Sections/Security/ClosingAccount'; import ConnectedApps from 'Sections/Security/ConnectedApps'; import LoginHistory from 'Sections/Security/LoginHistory'; diff --git a/packages/components/src/components/vertical-tab/vertical-tab.tsx b/packages/components/src/components/vertical-tab/vertical-tab.tsx index 14722e85f493..ba870ca7e1f9 100644 --- a/packages/components/src/components/vertical-tab/vertical-tab.tsx +++ b/packages/components/src/components/vertical-tab/vertical-tab.tsx @@ -39,7 +39,7 @@ type TVerticalTab = { list_groups?: TItem[]; onClickClose?: () => void; setVerticalTabIndex?: (index: number) => void; - tab_headers_note: React.ReactNode | React.ReactNode[]; + tab_headers_note?: React.ReactNode | React.ReactNode[]; title?: string; vertical_tab_index?: number; }; diff --git a/packages/shared/src/utils/route/route.ts b/packages/shared/src/utils/route/route.ts index 905cb381e859..b5265c4a1b27 100644 --- a/packages/shared/src/utils/route/route.ts +++ b/packages/shared/src/utils/route/route.ts @@ -1,11 +1,11 @@ // Checks if pathname matches route. (Works even with query string /?) -import React from 'react'; + // TODO: Add test cases for this -type TRoute = { - component?: JSX.Element | null; +export type TRoute = { + component?: React.ElementType | null; default?: boolean; exact?: boolean; - getTitle?: () => string; + getTitle: () => string; icon_component?: string; id?: string; is_authenticated?: boolean; From 9efe2414c0486771e3dd7deba21efb2aefaaa0ad Mon Sep 17 00:00:00 2001 From: Likhith Kolayari Date: Mon, 28 Aug 2023 15:08:37 +0400 Subject: [PATCH 2/4] fix: :art: refactored code --- packages/shared/src/utils/route/route.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/utils/route/route.ts b/packages/shared/src/utils/route/route.ts index b5265c4a1b27..de927db7d182 100644 --- a/packages/shared/src/utils/route/route.ts +++ b/packages/shared/src/utils/route/route.ts @@ -5,7 +5,7 @@ export type TRoute = { component?: React.ElementType | null; default?: boolean; exact?: boolean; - getTitle: () => string; + getTitle?: () => string; icon_component?: string; id?: string; is_authenticated?: boolean; @@ -19,7 +19,8 @@ type TGetSelectedRoute = { pathname: string; }; -export const matchRoute = (route: TRoute, pathname: string) => new RegExp(`^${route.path}(/.*)?$`).test(pathname); +// @ts-expect-error as this is a utility function with dynamic types +export const matchRoute = (route: T, pathname: string) => new RegExp(`^${route?.path}(/.*)?$`).test(pathname); export const getSelectedRoute = ({ routes, pathname }: TGetSelectedRoute) => { const matching_route = routes.find(route => matchRoute(route, pathname)); From 64f2878e759a7ae8a07311a7aa594bd07b70785e Mon Sep 17 00:00:00 2001 From: Likhith Kolayari Date: Tue, 29 Aug 2023 13:47:45 +0400 Subject: [PATCH 3/4] refactor: :art: migrated account to tsx --- .../Account/__tests__/account.spec.tsx | 75 +++++++++ .../__tests__/tradinghub-logout.spec.tsx | 22 +++ .../src/Containers/Account/account.jsx | 148 ------------------ .../src/Containers/Account/account.tsx | 88 +++++++++++ .../Account/page-overlay-wrapper.tsx | 14 +- .../Containers/Account/tradinghub-logout.tsx | 2 +- packages/account/src/Sections/index.js | 2 +- .../account/src/Types/common-prop.type.ts | 3 +- packages/stores/src/mockStore.ts | 2 + packages/stores/types.ts | 2 + 10 files changed, 200 insertions(+), 158 deletions(-) create mode 100644 packages/account/src/Containers/Account/__tests__/account.spec.tsx create mode 100644 packages/account/src/Containers/Account/__tests__/tradinghub-logout.spec.tsx delete mode 100644 packages/account/src/Containers/Account/account.jsx create mode 100644 packages/account/src/Containers/Account/account.tsx diff --git a/packages/account/src/Containers/Account/__tests__/account.spec.tsx b/packages/account/src/Containers/Account/__tests__/account.spec.tsx new file mode 100644 index 000000000000..5d909690d309 --- /dev/null +++ b/packages/account/src/Containers/Account/__tests__/account.spec.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { MemoryRouter, BrowserRouter } from 'react-router-dom'; +import { render, screen } from '@testing-library/react'; +import Account from '../account'; +import { StoreProvider, mockStore } from '@deriv/stores'; +import { routes } from '@deriv/shared'; +import { TStores } from '@deriv/stores/types'; + +jest.mock('../../Account/page-overlay-wrapper', () => jest.fn(() =>
MockPageOverlayWrapper
)); + +jest.mock('@deriv/components', () => ({ + ...jest.requireActual('@deriv/components'), + Loading: () =>
MockLoading
, +})); + +describe('Account', () => { + const store = mockStore({ + ui: { + is_account_settings_visible: true, + }, + }); + + const route_list = [ + { + getTitle: () => 'Profile', + icon: 'mockIcon', + subroutes: [ + { + path: routes.personal_details, + component: () =>
MockPersonalDetails
, + getTitle: () => 'Personal details', + default: true, + }, + { + path: routes.trading_assessment, + component: () =>
MockTradeAssessment
, + getTitle: () => 'Trade assessment', + }, + ], + }, + ]; + + const mock_props: React.ComponentProps = { + routes: route_list, + }; + + const mock_route = routes.personal_details; + + const renderComponent = ({ store_config = store, route = mock_route, props = mock_props }) => + render( + + + + + + + + ); + + it('should render account page', () => { + renderComponent({}); + expect(screen.getByText('MockPageOverlayWrapper')).toBeInTheDocument(); + }); + + it('should render loader while the client is still logging in', () => { + const new_store_config: TStores = mockStore({ + client: { + is_logging_in: true, + }, + }); + + renderComponent({ store_config: new_store_config }); + expect(screen.getByText('MockLoading')).toBeInTheDocument(); + }); +}); diff --git a/packages/account/src/Containers/Account/__tests__/tradinghub-logout.spec.tsx b/packages/account/src/Containers/Account/__tests__/tradinghub-logout.spec.tsx new file mode 100644 index 000000000000..985f7a20ca8b --- /dev/null +++ b/packages/account/src/Containers/Account/__tests__/tradinghub-logout.spec.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import TradingHubLogout from '../tradinghub-logout'; + +describe('TradingHubLogout', () => { + const mock_props: React.ComponentProps = { + handleOnLogout: jest.fn(), + }; + + it('should render logout tab', () => { + render(); + expect(screen.getByText('Log out')).toBeInTheDocument(); + }); + + it('should invoke handleOnLogout when logout tab is clicked', () => { + render(); + const el_tab = screen.getByTestId('dt_logout_tab'); + userEvent.click(el_tab); + expect(mock_props.handleOnLogout).toBeCalledTimes(1); + }); +}); diff --git a/packages/account/src/Containers/Account/account.jsx b/packages/account/src/Containers/Account/account.jsx deleted file mode 100644 index 7ab146040dd1..000000000000 --- a/packages/account/src/Containers/Account/account.jsx +++ /dev/null @@ -1,148 +0,0 @@ -import React from 'react'; -import { withRouter } from 'react-router-dom'; -import { FadeWrapper, Loading } from '@deriv/components'; -import { matchRoute, routes as shared_routes } from '@deriv/shared'; -import { observer, useStore } from '@deriv/stores'; -import { flatten } from '../../Helpers/flatten'; -import PageOverlayWrapper from './page-overlay-wrapper'; -import 'Styles/account.scss'; - -// const onClickLogout = (logout, history) => { -// history.push(shared_routes.index); -// logout().then(() => (window.location.href = getStaticUrl('/'))); -// }; - -// const PageOverlayWrapper = ({ -// is_from_derivgo, -// is_appstore, -// list_groups, -// logout, -// onClickClose, -// selected_route, -// subroutes, -// history, -// }) => { -// const routeToPrevious = () => history.push(shared_routes.traders_hub); - -// if (isMobile() && selected_route) { -// return ( -// -// -// -// ); -// } -// return ( -// -// } -// /> -// -// ); -// }; - -/** - * Component that renders the account section - * @name Account - * @param history - history object passed from react-router-dom - * @param location - location object passed from react-router-dom - * @param routes - routes object passed from react-router-dom - * @returns React component - */ -const Account = observer(({ history, location, routes }) => { - const { client, ui } = useStore(); - const { - is_virtual, - is_logged_in, - is_logging_in, - is_risky_client, - is_pending_proof_of_ownership, - landing_company_shortcode, - should_allow_authentication, - // logout, - } = client; - // const { routeBackInApp } = common; - const { toggleAccountSettings, is_account_settings_visible } = ui; - // const { is_appstore } = React.useContext(PlatformContext); - const subroutes = flatten(routes.map(i => i.subroutes)); - // let list_groups = [...routes]; - // list_groups = list_groups.map(route_group => ({ - // icon: route_group.icon, - // label: route_group.getTitle(), - // subitems: route_group.subroutes.map(sub => subroutes.indexOf(sub)), - // })); - let selected_content = subroutes.find(r => matchRoute(r, location.pathname)); - // const onClickClose = React.useCallback(() => routeBackInApp(history), [routeBackInApp, history]); - - React.useEffect(() => { - toggleAccountSettings(true); - }, [toggleAccountSettings]); - - routes.forEach(menu_item => { - menu_item.subroutes.forEach(route => { - if (route.path === shared_routes.financial_assessment) { - route.is_disabled = is_virtual || (landing_company_shortcode === 'maltainvest' && !is_risky_client); - } - - if (route.path === shared_routes.trading_assessment) { - route.is_disabled = is_virtual || landing_company_shortcode !== 'maltainvest'; - } - - if (route.path === shared_routes.proof_of_identity || route.path === shared_routes.proof_of_address) { - route.is_disabled = !should_allow_authentication; - } - - if (route.path === shared_routes.proof_of_ownership) { - route.is_disabled = is_virtual || !is_pending_proof_of_ownership; - } - }); - }); - - if (!selected_content) { - // fallback - selected_content = subroutes[0]; - history.push(shared_routes.personal_details); - } - - if (!is_logged_in && is_logging_in) { - return ; - } - - // const selected_route = getSelectedRoute({ routes: subroutes, pathname: location.pathname }); - - return ( - -
- {/* */} - -
-
- ); -}); - -Account.displayName = 'Account'; - -export default withRouter(Account); diff --git a/packages/account/src/Containers/Account/account.tsx b/packages/account/src/Containers/Account/account.tsx new file mode 100644 index 000000000000..633ea715fcf6 --- /dev/null +++ b/packages/account/src/Containers/Account/account.tsx @@ -0,0 +1,88 @@ +import React from 'react'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; +import { FadeWrapper, Loading } from '@deriv/components'; +import { matchRoute, routes as shared_routes } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; +import { flatten } from '../../Helpers/flatten'; +import PageOverlayWrapper from './page-overlay-wrapper'; +import { TRoute } from '../../Types'; +import 'Styles/account.scss'; + +type TAccountProps = RouteComponentProps & { + routes: Array; +}; + +/** + * Component that renders the account section + * @name Account + * @param history - history object passed from react-router-dom + * @param location - location object passed from react-router-dom + * @param routes - routes object passed from react-router-dom + * @returns React component + */ +const Account = observer(({ history, location, routes }: TAccountProps) => { + const { client, ui } = useStore(); + const { + is_virtual, + is_logged_in, + is_logging_in, + is_pending_proof_of_ownership, + landing_company_shortcode, + should_allow_authentication, + } = client; + const { toggleAccountSettings, is_account_settings_visible } = ui; + const subroutes = flatten(routes.map(i => i.subroutes)); + let selected_content = subroutes.find(r => matchRoute(r, location.pathname)); + + React.useEffect(() => { + toggleAccountSettings(true); + }, [toggleAccountSettings]); + + routes.forEach(menu_item => { + if (menu_item?.subroutes?.length) { + menu_item.subroutes.forEach(route => { + if (route.path === shared_routes.financial_assessment) { + route.is_disabled = is_virtual || landing_company_shortcode === 'maltainvest'; + } + + if (route.path === shared_routes.trading_assessment) { + route.is_disabled = is_virtual || landing_company_shortcode !== 'maltainvest'; + } + + if (route.path === shared_routes.proof_of_identity || route.path === shared_routes.proof_of_address) { + route.is_disabled = !should_allow_authentication; + } + + if (route.path === shared_routes.proof_of_ownership) { + route.is_disabled = is_virtual || !is_pending_proof_of_ownership; + } + }); + } + }); + + if (!selected_content) { + // fallback + selected_content = subroutes[0]; + history.push(shared_routes.personal_details); + } + + if (!is_logged_in && is_logging_in) { + return ; + } + + return ( + +
+ +
+
+ ); +}); + +Account.displayName = 'Account'; + +export default withRouter(Account); diff --git a/packages/account/src/Containers/Account/page-overlay-wrapper.tsx b/packages/account/src/Containers/Account/page-overlay-wrapper.tsx index e36e55d54e27..088351f3cbd1 100644 --- a/packages/account/src/Containers/Account/page-overlay-wrapper.tsx +++ b/packages/account/src/Containers/Account/page-overlay-wrapper.tsx @@ -1,16 +1,16 @@ import React from 'react'; import { useHistory } from 'react-router-dom'; import { PageOverlay, VerticalTab } from '@deriv/components'; -import { TRoute, getSelectedRoute, getStaticUrl, routes as shared_routes } from '@deriv/shared'; +import { getSelectedRoute, getStaticUrl, routes as shared_routes } from '@deriv/shared'; import { observer, useStore } from '@deriv/stores'; -import TradingHubLogout from './tradinghub-logout'; import { Localize } from '@deriv/translations'; +import TradingHubLogout from './tradinghub-logout'; +import { TRoute } from '../../Types'; type RouteItems = React.ComponentProps['list']; -type RouteRef = Array; type PageOverlayWrapperProps = { - routes: RouteRef; + routes: Array; subroutes: RouteItems; }; @@ -30,8 +30,8 @@ const PageOverlayWrapper = observer(({ routes, subroutes }: PageOverlayWrapperPr const list_groups = routes.map(route_group => ({ icon: route_group.icon, - label: route_group.getTitle(), - subitems: route_group.subroutes.map(sub => subroutes.indexOf(sub)), + label: route_group?.getTitle(), + subitems: route_group?.subroutes?.length ? route_group.subroutes.map(sub => subroutes.indexOf(sub)) : [], })); const onClickClose = React.useCallback(() => routeBackInApp(history), [routeBackInApp, history]); @@ -46,7 +46,7 @@ const PageOverlayWrapper = observer(({ routes, subroutes }: PageOverlayWrapperPr if (is_mobile && selected_route) { const RouteComponent = selected_route.component as React.ElementType<{ component_icon: string | undefined }>; return ( - + ); diff --git a/packages/account/src/Containers/Account/tradinghub-logout.tsx b/packages/account/src/Containers/Account/tradinghub-logout.tsx index ce6942604339..208142984b18 100644 --- a/packages/account/src/Containers/Account/tradinghub-logout.tsx +++ b/packages/account/src/Containers/Account/tradinghub-logout.tsx @@ -9,7 +9,7 @@ import { Localize } from '@deriv/translations'; * @returns React Component */ const TradingHubLogout = ({ handleOnLogout }: { handleOnLogout: () => void }) => ( -
+
diff --git a/packages/account/src/Sections/index.js b/packages/account/src/Sections/index.js index f29be0ccb21d..e0f1bdd1814a 100644 --- a/packages/account/src/Sections/index.js +++ b/packages/account/src/Sections/index.js @@ -9,7 +9,7 @@ import ProofOfOwnership from 'Sections/Verification/ProofOfOwnership'; import TwoFactorAuthentication from 'Sections/Security/TwoFactorAuthentication'; import ApiToken from 'Sections/Security/ApiToken'; import SelfExclusion from 'Sections/Security/SelfExclusion'; -import Account from 'Containers/Account/account.jsx'; +import Account from 'Containers/Account/account'; import ClosingAccount from 'Sections/Security/ClosingAccount'; import ConnectedApps from 'Sections/Security/ConnectedApps'; import LoginHistory from 'Sections/Security/LoginHistory'; diff --git a/packages/account/src/Types/common-prop.type.ts b/packages/account/src/Types/common-prop.type.ts index 5298105baa8b..2717c3450461 100644 --- a/packages/account/src/Types/common-prop.type.ts +++ b/packages/account/src/Types/common-prop.type.ts @@ -65,8 +65,9 @@ export type TRoute = { icon?: string; default?: boolean; to?: string; - component?: ((cashier_routes?: TRoute[]) => JSX.Element) | typeof Redirect; + component?: ((routes?: TRoute[]) => JSX.Element) | typeof Redirect; getTitle?: () => string; + is_disabled?: boolean; subroutes?: TRoute[]; }; diff --git a/packages/stores/src/mockStore.ts b/packages/stores/src/mockStore.ts index da779c6c7307..f2ba74649e5d 100644 --- a/packages/stores/src/mockStore.ts +++ b/packages/stores/src/mockStore.ts @@ -279,6 +279,7 @@ const mock = (): TStores & { is_mock: boolean } => { current: null, }, current_focus: null, + is_account_settings_visible: false, is_loading: false, is_cashier_visible: false, is_app_disabled: false, @@ -296,6 +297,7 @@ const mock = (): TStores & { is_mock: boolean } => { enableApp: jest.fn(), setCurrentFocus: jest.fn(), toggleAccountsDialog: jest.fn(), + toggleAccountSettings: jest.fn(), toggleCashier: jest.fn(), togglePositionsDrawer: jest.fn(), setDarkMode: jest.fn(), diff --git a/packages/stores/types.ts b/packages/stores/types.ts index 20687872a115..b4d33c464ad7 100644 --- a/packages/stores/types.ts +++ b/packages/stores/types.ts @@ -437,6 +437,7 @@ type TUiStore = { disableApp: () => void; enableApp: () => void; has_real_account_signup_ended: boolean; + is_account_settings_visible: boolean; is_loading: boolean; is_cashier_visible: boolean; is_closing_create_real_account_modal: boolean; @@ -464,6 +465,7 @@ type TUiStore = { setSubSectionIndex: (index: number) => void; shouldNavigateAfterChooseCrypto: (value: Omit | TRoutes) => void; toggleAccountsDialog: () => void; + toggleAccountSettings: (props?: boolean) => void; toggleCashier: () => void; toggleLanguageSettingsModal: () => void; toggleLinkExpiredModal: (state_change: boolean) => void; From 972efd88ba3d55e543a30dfc6c5fbde6e8bcb563 Mon Sep 17 00:00:00 2001 From: Likhith Kolayari Date: Wed, 30 Aug 2023 13:06:27 +0400 Subject: [PATCH 4/4] fix: :art: incorporated review comments --- .../src/Containers/Account/__tests__/account.spec.tsx | 8 ++++---- packages/account/src/Containers/Account/account.tsx | 3 +-- .../src/Containers/Account/page-overlay-wrapper.tsx | 2 -- packages/account/src/Helpers/flatten.js | 1 - 4 files changed, 5 insertions(+), 9 deletions(-) delete mode 100644 packages/account/src/Helpers/flatten.js diff --git a/packages/account/src/Containers/Account/__tests__/account.spec.tsx b/packages/account/src/Containers/Account/__tests__/account.spec.tsx index 5d909690d309..984e4e37c1ca 100644 --- a/packages/account/src/Containers/Account/__tests__/account.spec.tsx +++ b/packages/account/src/Containers/Account/__tests__/account.spec.tsx @@ -1,10 +1,10 @@ import React from 'react'; import { MemoryRouter, BrowserRouter } from 'react-router-dom'; import { render, screen } from '@testing-library/react'; -import Account from '../account'; import { StoreProvider, mockStore } from '@deriv/stores'; import { routes } from '@deriv/shared'; -import { TStores } from '@deriv/stores/types'; +import { TRoute } from 'Types'; +import Account from '../account'; jest.mock('../../Account/page-overlay-wrapper', () => jest.fn(() =>
MockPageOverlayWrapper
)); @@ -20,7 +20,7 @@ describe('Account', () => { }, }); - const route_list = [ + const route_list: Array = [ { getTitle: () => 'Profile', icon: 'mockIcon', @@ -63,7 +63,7 @@ describe('Account', () => { }); it('should render loader while the client is still logging in', () => { - const new_store_config: TStores = mockStore({ + const new_store_config = mockStore({ client: { is_logging_in: true, }, diff --git a/packages/account/src/Containers/Account/account.tsx b/packages/account/src/Containers/Account/account.tsx index 633ea715fcf6..3883eaf8bc11 100644 --- a/packages/account/src/Containers/Account/account.tsx +++ b/packages/account/src/Containers/Account/account.tsx @@ -3,7 +3,6 @@ import { RouteComponentProps, withRouter } from 'react-router-dom'; import { FadeWrapper, Loading } from '@deriv/components'; import { matchRoute, routes as shared_routes } from '@deriv/shared'; import { observer, useStore } from '@deriv/stores'; -import { flatten } from '../../Helpers/flatten'; import PageOverlayWrapper from './page-overlay-wrapper'; import { TRoute } from '../../Types'; import 'Styles/account.scss'; @@ -31,7 +30,7 @@ const Account = observer(({ history, location, routes }: TAccountProps) => { should_allow_authentication, } = client; const { toggleAccountSettings, is_account_settings_visible } = ui; - const subroutes = flatten(routes.map(i => i.subroutes)); + const subroutes = routes.map(i => i.subroutes); let selected_content = subroutes.find(r => matchRoute(r, location.pathname)); React.useEffect(() => { diff --git a/packages/account/src/Containers/Account/page-overlay-wrapper.tsx b/packages/account/src/Containers/Account/page-overlay-wrapper.tsx index 088351f3cbd1..658edbe162bc 100644 --- a/packages/account/src/Containers/Account/page-overlay-wrapper.tsx +++ b/packages/account/src/Containers/Account/page-overlay-wrapper.tsx @@ -26,8 +26,6 @@ const PageOverlayWrapper = observer(({ routes, subroutes }: PageOverlayWrapperPr const { logout } = client; const { is_from_derivgo, routeBackInApp } = common; - // const routeToPrevious = () => history.push(shared_routes.traders_hub); - const list_groups = routes.map(route_group => ({ icon: route_group.icon, label: route_group?.getTitle(), diff --git a/packages/account/src/Helpers/flatten.js b/packages/account/src/Helpers/flatten.js deleted file mode 100644 index d9f0a696b24f..000000000000 --- a/packages/account/src/Helpers/flatten.js +++ /dev/null @@ -1 +0,0 @@ -export const flatten = arr => [].concat(...arr);