From e47979ea5fead59f943922587f6977babf4d6ffb Mon Sep 17 00:00:00 2001 From: Farzin Mirzaie <72082844+farzin-deriv@users.noreply.github.com> Date: Fri, 21 Jul 2023 12:21:56 +0800 Subject: [PATCH] Farzin/Putting wallet behind feature flag [WIP] (#9362) * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up * refactor(appstore): :fire: clean-up --------- Co-authored-by: Farzin Mirzaie --- .../add-more-wallets/add-more-wallets.scss | 12 +- .../appstore/src/components/app-content.tsx | 26 ++++ packages/appstore/src/components/app.tsx | 51 ++----- .../src/components/containers/wallet.scss | 2 +- .../src/components/routes/routes-wrapper.tsx | 16 -- .../appstore/src/components/routes/routes.tsx | 35 +++-- .../__tests__/wallet-cards-carousel.spec.tsx | 144 +++++++++++++----- .../cards-slider-swiper.tsx | 67 ++++---- .../wallet-cards-carousel.scss | 12 ++ .../wallet-cards-carousel.tsx | 36 ++--- .../appstore/src/constants/routes-config.ts | 39 ----- .../traders-hub/account-with-wallets.tsx | 79 ---------- .../src/modules/traders-hub/index.tsx | 111 +++++++++----- .../src/modules/traders-hub/traders-hub.scss | 44 +++--- .../modules/wallets/desktop-wallets-list.tsx | 18 +++ .../appstore/src/modules/wallets/index.ts | 1 + .../wallets/mobile-wallets-carousel.tsx | 56 +++++++ .../appstore/src/modules/wallets/wallets.scss | 25 +++ .../appstore/src/modules/wallets/wallets.tsx | 38 +++++ packages/appstore/src/services/websocket.ts | 7 - packages/appstore/src/stores/base-store.ts | 9 -- packages/appstore/src/stores/config-store.ts | 47 ------ packages/appstore/src/stores/index.ts | 18 +-- packages/appstore/src/stores/root-store.ts | 23 --- packages/appstore/src/types/api.types.ts | 6 - packages/appstore/src/types/index.ts | 5 - packages/appstore/src/types/params.types.ts | 30 ---- packages/appstore/src/types/props.types.ts | 6 - packages/appstore/src/types/stores.types.ts | 11 -- packages/appstore/src/types/ws.types.ts | 2 - .../cfd/src/Stores/Modules/CFD/cfd-store.js | 2 +- packages/cfd/src/Utils/Validator/validator.js | 2 +- packages/core/src/Stores/client-store.js | 4 +- packages/hooks/src/useAuthorize.ts | 5 +- .../stores/src/stores/FeatureFlagsStore.ts | 2 + 35 files changed, 473 insertions(+), 518 deletions(-) create mode 100644 packages/appstore/src/components/app-content.tsx delete mode 100644 packages/appstore/src/components/routes/routes-wrapper.tsx delete mode 100644 packages/appstore/src/constants/routes-config.ts delete mode 100644 packages/appstore/src/modules/traders-hub/account-with-wallets.tsx create mode 100644 packages/appstore/src/modules/wallets/desktop-wallets-list.tsx create mode 100644 packages/appstore/src/modules/wallets/index.ts create mode 100644 packages/appstore/src/modules/wallets/mobile-wallets-carousel.tsx create mode 100644 packages/appstore/src/modules/wallets/wallets.scss create mode 100644 packages/appstore/src/modules/wallets/wallets.tsx delete mode 100644 packages/appstore/src/services/websocket.ts delete mode 100644 packages/appstore/src/stores/base-store.ts delete mode 100644 packages/appstore/src/stores/config-store.ts delete mode 100644 packages/appstore/src/stores/root-store.ts delete mode 100644 packages/appstore/src/types/api.types.ts delete mode 100644 packages/appstore/src/types/params.types.ts delete mode 100644 packages/appstore/src/types/props.types.ts delete mode 100644 packages/appstore/src/types/stores.types.ts delete mode 100644 packages/appstore/src/types/ws.types.ts diff --git a/packages/appstore/src/components/add-more-wallets/add-more-wallets.scss b/packages/appstore/src/components/add-more-wallets/add-more-wallets.scss index c4d181bae434..5bf9cbb47c25 100644 --- a/packages/appstore/src/components/add-more-wallets/add-more-wallets.scss +++ b/packages/appstore/src/components/add-more-wallets/add-more-wallets.scss @@ -1,6 +1,11 @@ .add-wallets { - padding: 2rem 0rem 4rem; - margin-top: 2.4rem; + display: flex; + padding-top: 2.4rem; + flex-direction: column; + align-items: flex-start; + gap: 1.6rem; + width: 100%; + &__title { @include mobile { font-size: var(--text-size-m); @@ -8,10 +13,9 @@ } &__content { background-color: var(--general-main-1); - height: 35.2rem; - margin-top: 1.6rem; border-radius: $BORDER_RADIUS; position: relative; + width: 100%; } &__card { width: 23rem; diff --git a/packages/appstore/src/components/app-content.tsx b/packages/appstore/src/components/app-content.tsx new file mode 100644 index 000000000000..292285f78090 --- /dev/null +++ b/packages/appstore/src/components/app-content.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { routes } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; +import Routes from 'Components/routes/routes'; +import classNames from 'classnames'; +import './app.scss'; + +const AppContent: React.FC = observer(() => { + const { ui } = useStore(); + + return ( +
+
+ +
+
+ ); +}); + +export default AppContent; diff --git a/packages/appstore/src/components/app.tsx b/packages/appstore/src/components/app.tsx index 1a9c0e436dfb..88996a0cfe80 100644 --- a/packages/appstore/src/components/app.tsx +++ b/packages/appstore/src/components/app.tsx @@ -1,45 +1,24 @@ -import classNames from 'classnames'; -import * as React from 'react'; -import { setWebsocket, routes } from '@deriv/shared'; -import { StoreProvider, observer } from '@deriv/stores'; +import React from 'react'; 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'; +import { StoreProvider } from '@deriv/stores'; +import AppContent from './app-content'; import './app.scss'; -type TAppProps = { +type TProps = { passthrough: { - root_store: TRootStore; - WS: Record; + root_store: React.ComponentProps['store']; }; }; -const App = ({ passthrough: { WS, root_store } }: TAppProps) => { - initContext(root_store, WS); - setWebsocket(WS); - const { ui }: TRootStore = useStores(); +const App: React.FC = ({ passthrough: { root_store } }) => ( + + + + + + + +); - return ( - - - -
-
- -
-
-
-
-
- ); -}; - -export default observer(App); +export default App; diff --git a/packages/appstore/src/components/containers/wallet.scss b/packages/appstore/src/components/containers/wallet.scss index f7339292dcdd..bfe0a1d9cc50 100644 --- a/packages/appstore/src/components/containers/wallet.scss +++ b/packages/appstore/src/components/containers/wallet.scss @@ -1,7 +1,7 @@ .wallet { - margin-block-start: 2.4rem; background-color: var(--general-main-1); border-radius: $BORDER_RADIUS * 4; + align-self: stretch; &__demo { background-color: var(--wallet-demo-bg-color); diff --git a/packages/appstore/src/components/routes/routes-wrapper.tsx b/packages/appstore/src/components/routes/routes-wrapper.tsx deleted file mode 100644 index 8092cd5b2913..000000000000 --- a/packages/appstore/src/components/routes/routes-wrapper.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from 'react'; -import { BrowserRouter as Router } from 'react-router-dom'; - -const RoutesWrapper: React.FC = ({ has_router, children }) => { - if (has_router) { - return {children}; - } - - return {children}; -}; - -type TRoutesWrapperProps = React.PropsWithChildren<{ - has_router: boolean; -}>; - -export default RoutesWrapper; diff --git a/packages/appstore/src/components/routes/routes.tsx b/packages/appstore/src/components/routes/routes.tsx index ae42a5553c55..22a497488fc7 100644 --- a/packages/appstore/src/components/routes/routes.tsx +++ b/packages/appstore/src/components/routes/routes.tsx @@ -1,14 +1,16 @@ import * as React from 'react'; +import { useFeatureFlags } from '@deriv/hooks'; +import { observer } from '@deriv/stores'; +import { Localize, localize } from '@deriv/translations'; +import Onboarding from 'Modules/onboarding'; +import TradersHub from 'Modules/traders-hub'; +import { WalletsModule } from 'Modules/wallets'; import { Switch } from 'react-router-dom'; import RouteWithSubroutes from './route-with-sub-routes.jsx'; -import { Localize } from '@deriv/translations'; -import { observer } from 'mobx-react-lite'; -import getRoutesConfig from 'Constants/routes-config'; -import { useStores } from 'Stores'; -import { TRoute } from 'Types'; -const Routes: React.FC = () => { - const { config } = useStores(); +const Routes: React.FC = observer(() => { + const { is_wallet_enabled } = useFeatureFlags(); + return ( { } > - {getRoutesConfig({ - consumer_routes: config.routes, - }).map((route: TRoute, idx: number) => ( - - ))} + localize('TradersHub')} + /> + localize('Onboarding')} + /> ); -}; +}); -export default observer(Routes); +export default Routes; diff --git a/packages/appstore/src/components/wallet-cards-carousel/__tests__/wallet-cards-carousel.spec.tsx b/packages/appstore/src/components/wallet-cards-carousel/__tests__/wallet-cards-carousel.spec.tsx index b395777b0a30..0e053cd81dce 100644 --- a/packages/appstore/src/components/wallet-cards-carousel/__tests__/wallet-cards-carousel.spec.tsx +++ b/packages/appstore/src/components/wallet-cards-carousel/__tests__/wallet-cards-carousel.spec.tsx @@ -3,56 +3,117 @@ import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import { mockStore, StoreProvider } from '@deriv/stores'; import WalletCardsCarousel from '..'; -import { TWalletAccount } from 'Types'; +import { APIProvider } from '@deriv/api'; -const mockedRootStore = mockStore({}); +jest.mock('@deriv/api', () => ({ + ...jest.requireActual('@deriv/api'), + useFetch: jest.fn((name: string) => { + if (name === 'authorize') { + return { + data: { + authorize: { + account_list: [ + { + account_category: 'wallet', + currency: 'USD', + is_virtual: 0, + loginid: 'CRW10001', + }, + { + account_category: 'trading', + currency: 'USD', + is_virtual: 0, + loginid: 'CRW10002', + }, + { + account_category: 'wallet', + currency: 'UST', + is_virtual: 0, + loginid: 'CRW10003', + }, + { + account_category: 'wallet', + currency: 'BTC', + is_virtual: 1, + loginid: 'VRW10001', + }, + { + account_category: 'wallet', + currency: 'AUD', + is_virtual: 0, + loginid: 'CRW10004', + }, + { + account_category: 'wallet', + currency: 'ETH', + is_virtual: 0, + loginid: 'CRW10005', + }, + ], + }, + }, + }; + } else if (name === 'balance') { + return { + data: { + balance: { + accounts: { + CRW909900: { + balance: 0, + }, + }, + }, + }, + }; + } else if (name === 'website_status') { + return { + data: { + website_status: { + currencies_config: { + AUD: { type: 'fiat' }, + BTC: { type: 'crypto' }, + ETH: { type: 'crypto' }, + UST: { type: 'crypto' }, + USD: { type: 'fiat' }, + }, + }, + }, + }; + } + + return undefined; + }), +})); jest.mock('./../cards-slider-swiper', () => jest.fn(() =>
slider
)); describe('', () => { - const items: TWalletAccount[] = [ - { - name: 'USD', - currency: 'USD', - icon: '', - balance: 10784, - icon_type: 'fiat', - landing_company_name: 'svg', - is_disabled: 0, - is_demo: false, - loginid: 'CRW10001', - }, - { - name: 'Demo USD', - currency: 'USD', - icon: '', - balance: 100000, - icon_type: 'fiat', - landing_company_name: 'svg', - is_disabled: 0, - is_demo: true, - loginid: 'CRW10002', - }, - ]; - it('Should render slider', () => { - render( - - - + const mock = mockStore({ client: { accounts: { CRW909900: { token: '12345' } }, loginid: 'CRW909900' } }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + + {children} + ); + + render(, { wrapper }); const slider = screen.queryByText('slider'); expect(slider).toBeInTheDocument(); }); it('Should render buttons for REAL', () => { - render( - - - + const mock = mockStore({ client: { accounts: { CRW909900: { token: '12345' } }, loginid: 'CRW909900' } }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + + {children} + ); + render(, { wrapper }); + const btn1 = screen.queryByText(/Deposit/i); const btn2 = screen.queryByText(/Withdraw/i); const btn3 = screen.queryByText(/Transfer/i); @@ -65,13 +126,16 @@ describe('', () => { }); it('Should render buttons for DEMO', () => { - mockedRootStore.client.loginid = 'CRW10002'; - render( - - - + const mock = mockStore({ client: { accounts: { VRW10001: { token: '12345' } }, loginid: 'VRW10001' } }); + + const wrapper = ({ children }: { children: JSX.Element }) => ( + + {children} + ); + render(, { wrapper }); + const btn1 = screen.queryByText(/Transfer/i); const btn2 = screen.queryByText(/Transactions/i); const btn3 = screen.queryByText(/Reset balance/i); diff --git a/packages/appstore/src/components/wallet-cards-carousel/cards-slider-swiper.tsx b/packages/appstore/src/components/wallet-cards-carousel/cards-slider-swiper.tsx index c7421be0f881..322fe860bcef 100644 --- a/packages/appstore/src/components/wallet-cards-carousel/cards-slider-swiper.tsx +++ b/packages/appstore/src/components/wallet-cards-carousel/cards-slider-swiper.tsx @@ -1,46 +1,49 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { TWalletAccount } from 'Types'; import { WalletCard, ProgressBarOnboarding } from '@deriv/components'; import { formatMoney } from '@deriv/shared'; -import useEmblaCarousel, { EmblaOptionsType } from 'embla-carousel-react'; +import { observer, useStore } from '@deriv/stores'; +import useEmblaCarousel from 'embla-carousel-react'; import { getAccountName } from 'Constants/utils'; import './wallet-cards-carousel.scss'; +import { useWalletsList } from '@deriv/hooks'; -type TProps = { - readonly items: TWalletAccount[]; - setActivePage: React.Dispatch>; - active_page: number; -}; +const CardsSliderSwiper = observer(() => { + const { client } = useStore(); + const { switchAccount } = client; + const { data } = useWalletsList(); -const CardsSliderSwiper = ({ items, setActivePage, active_page }: TProps) => { - const OPTIONS: EmblaOptionsType = { skipSnaps: true, containScroll: false }; - const [emblaRef, emblaApi] = useEmblaCarousel(OPTIONS); + const [active_index, setActiveIndex] = useState(1); + const [emblaRef, emblaApi] = useEmblaCarousel({ skipSnaps: true }); - const steps = items.map((_, idx) => idx.toString()); + const active_wallet_index = data.findIndex(item => item?.is_selected) || 0; - const scrollTo = React.useCallback( - (index: number) => { - if (emblaApi) emblaApi.scrollTo(index - 1); - setActivePage(index - 1); - }, - [emblaApi, setActivePage] - ); + const steps = data.map((_, idx) => idx.toString()); + + useEffect(() => { + emblaApi?.on('select', () => { + const index = emblaApi?.selectedScrollSnap() || 0; + setActiveIndex(index + 1); + }); + }, [emblaApi]); - const onSelect = React.useCallback(() => { - if (emblaApi) setActivePage(emblaApi.selectedScrollSnap()); - }, [emblaApi, setActivePage]); + useEffect(() => { + emblaApi?.scrollTo(active_index - 1); + }, [active_index, emblaApi]); - React.useEffect(() => { - if (!emblaApi) return; + useEffect(() => { + setTimeout(() => { + if (!data[active_index - 1]?.is_selected) switchAccount(data[active_index - 1]?.loginid); + }, 1000); + }, [active_index, data, switchAccount]); - onSelect(); - emblaApi.on('reInit', onSelect); - emblaApi.on('select', onSelect); - }, [emblaApi, onSelect]); + useEffect(() => { + setActiveIndex(active_wallet_index + 1); + }, [active_wallet_index]); const slider = React.useMemo( () => - items?.map((item: TWalletAccount) => ( + data?.map((item: TWalletAccount) => (
{ />
)), - [items.length] + [data] ); return ( @@ -69,14 +72,14 @@ const CardsSliderSwiper = ({ items, setActivePage, active_page }: TProps) => {
); -}; +}); export default CardsSliderSwiper; diff --git a/packages/appstore/src/components/wallet-cards-carousel/wallet-cards-carousel.scss b/packages/appstore/src/components/wallet-cards-carousel/wallet-cards-carousel.scss index 03d2f2546477..9279aafa264b 100644 --- a/packages/appstore/src/components/wallet-cards-carousel/wallet-cards-carousel.scss +++ b/packages/appstore/src/components/wallet-cards-carousel/wallet-cards-carousel.scss @@ -22,3 +22,15 @@ gap: 0.8rem; } } + +.wallet-carousel-content-container { + display: flex; + padding: 1.6rem; + flex-direction: column; + align-items: center; + background-color: var(--general-main-1); + + &-demo { + background-color: var(--wallet-demo-bg-color); + } +} diff --git a/packages/appstore/src/components/wallet-cards-carousel/wallet-cards-carousel.tsx b/packages/appstore/src/components/wallet-cards-carousel/wallet-cards-carousel.tsx index b4973d6878a2..f9bae9cd3a74 100644 --- a/packages/appstore/src/components/wallet-cards-carousel/wallet-cards-carousel.tsx +++ b/packages/appstore/src/components/wallet-cards-carousel/wallet-cards-carousel.tsx @@ -1,46 +1,28 @@ import React from 'react'; -import { getWalletHeaderButtons } from 'Constants/utils'; -import { TWalletAccount } from 'Types'; +import { useActiveWallet } from '@deriv/hooks'; +import { observer, useStore } from '@deriv/stores'; import WalletButton from 'Components/wallet-button'; +import { getWalletHeaderButtons } from 'Constants/utils'; import CardsSliderSwiper from './cards-slider-swiper'; -import { observer, useStore } from '@deriv/stores'; import './wallet-cards-carousel.scss'; -type TProps = { - readonly items: TWalletAccount[]; -}; - -const WalletCardsCarousel = observer(({ items }: TProps) => { - const { client, ui, traders_hub } = useStore(); +const WalletCardsCarousel = observer(() => { + const { ui, traders_hub } = useStore(); const { setIsWalletModalVisible } = ui; const { setWalletModalActiveWalletID, setWalletModalActiveTab } = traders_hub; - const { loginid, switchAccount } = client; - - const [active_page, setActivePage] = React.useState( - items.findIndex(item => item?.loginid === loginid) === -1 - ? 0 - : items.findIndex(item => item?.loginid === loginid) - ); - - React.useEffect(() => { - const switchWallet = async () => { - if (loginid !== items[active_page]?.loginid) await switchAccount(items[active_page]?.loginid); - }; - - switchWallet(); - }, [active_page, items, loginid, switchAccount]); + const active_wallet = useActiveWallet(); - const wallet_buttons = getWalletHeaderButtons(items[active_page]?.is_demo); + const wallet_buttons = getWalletHeaderButtons(active_wallet?.is_demo || false); return (
- +
{wallet_buttons.map(button => { button.action = async () => { setWalletModalActiveTab(button.name); setIsWalletModalVisible(true); - setWalletModalActiveWalletID(items[active_page]?.loginid); + setWalletModalActiveWalletID(active_wallet?.loginid); }; return ; diff --git a/packages/appstore/src/constants/routes-config.ts b/packages/appstore/src/constants/routes-config.ts deleted file mode 100644 index 0cc6824d683c..000000000000 --- a/packages/appstore/src/constants/routes-config.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { localize } from '@deriv/translations'; -import TradersHub from 'Modules/traders-hub'; -import ConfigStore from 'Stores/config-store'; -import { TRoute } from 'Types'; -import Onboarding from 'Modules/onboarding'; - -type TRoutesConfig = { - consumer_routes: ConfigStore['routes']; -}; - -// 1. Order matters! Put more specific consumer_routes at the top. -// 2. Don't use `Localize` component since native html tag like `option` cannot render them -const initRoutesConfig = ({ consumer_routes }: TRoutesConfig): TRoute[] => [ - { - path: consumer_routes.traders_hub, - component: TradersHub, - getTitle: () => localize('TradersHub'), - }, - { - path: consumer_routes.onboarding, - component: Onboarding, - getTitle: () => localize('Onboarding'), - }, -]; - -let routes_config: Array; - -const getRoutesConfig = ({ consumer_routes }: TRoutesConfig): TRoute[] => { - // For default page route if page/path is not found, must be kept at the end of routes_config array. - if (!routes_config) { - const route_default = { getTitle: () => localize('Error 404') }; - - routes_config = initRoutesConfig({ consumer_routes }); - routes_config.push(route_default); - } - - return routes_config; -}; -export default getRoutesConfig; diff --git a/packages/appstore/src/modules/traders-hub/account-with-wallets.tsx b/packages/appstore/src/modules/traders-hub/account-with-wallets.tsx deleted file mode 100644 index 156f4aa6f5a8..000000000000 --- a/packages/appstore/src/modules/traders-hub/account-with-wallets.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import Wallet from 'Components/containers/wallet'; -import { observer, useStore } from '@deriv/stores'; -import WalletCardsCarousel from 'Components/wallet-cards-carousel'; -import { useContentFlag, useWalletsList } from '@deriv/hooks'; -import { ButtonToggle } from '@deriv/components'; -import ButtonToggleLoader from 'Components/pre-loader/button-toggle-loader'; -import { routes } from '@deriv/shared'; -import WalletOptionsAndMultipliersListing from 'Components/wallet-content/wallet-option-multipliers-listing'; -import WalletCFDsListing from 'Components/wallet-content/wallet-cfds-listing'; - -const AccountWithWallets = observer(() => { - const { - ui: { is_mobile }, - client: { is_landing_company_loaded }, - traders_hub: { selected_platform_type, setTogglePlatformType, is_eu_user }, - } = useStore(); - - const { is_eu_demo, is_eu_real } = useContentFlag(); - const eu_title = is_eu_demo || is_eu_real || is_eu_user; - - const { data: wallet_accounts } = useWalletsList(); - - const platform_toggle_options = [ - { text: 'CFDs', value: 'cfd' }, - { text: eu_title ? 'Multipliers' : 'Options & Multipliers', value: 'options' }, - ]; - - const platformTypeChange = (event: { - target: { - value: string; - name: string; - }; - }) => { - setTogglePlatformType(event.target.value); - }; - - const desktopWalletsComponent = React.useMemo( - () => - wallet_accounts?.map(wallet => { - // TODO: We have to create hook for 'switchAccount' with useFetch() to use cache in the future - return ; - }), - [wallet_accounts] - ); - - React.useEffect(() => { - setTogglePlatformType('cfd'); - }, [setTogglePlatformType]); - - return ( - - {is_mobile ? ( - - - {is_landing_company_loaded ? ( - - ) : ( - - )} - {selected_platform_type === 'cfd' && } - {selected_platform_type === 'options' && } - - ) : ( - {desktopWalletsComponent} - )} - - ); -}); - -export default AccountWithWallets; diff --git a/packages/appstore/src/modules/traders-hub/index.tsx b/packages/appstore/src/modules/traders-hub/index.tsx index 6b6416083a3b..1e58c29973b7 100644 --- a/packages/appstore/src/modules/traders-hub/index.tsx +++ b/packages/appstore/src/modules/traders-hub/index.tsx @@ -1,38 +1,26 @@ import React from 'react'; -import classNames from 'classnames'; -import { isDesktop } from '@deriv/shared'; -import { Div100vhContainer } from '@deriv/components'; -import { useStore, observer } from '@deriv/stores'; -import { useContentFlag } from '@deriv/hooks'; +import { ButtonToggle, DesktopWrapper, Div100vhContainer, MobileWrapper, Text } from '@deriv/components'; +import { ContentFlag, isDesktop, isMobile, routes } from '@deriv/shared'; +import { useStore } from '@deriv/stores'; +import { Localize } from '@deriv/translations'; +import CFDsListing from 'Components/cfds-listing'; +import MainTitleBar from 'Components/main-title-bar'; import ModalManager from 'Components/modals/modal-manager'; +import OptionsAndMultipliersListing from 'Components/options-multipliers-listing'; +import ButtonToggleLoader from 'Components/pre-loader/button-toggle-loader'; import TourGuide from 'Modules/tour-guide/tour-guide'; -import AccountWithWallets from './account-with-wallets'; -import AccountWithoutWallets from './account-without-wallets'; -import EUDisclaimer from 'Components/eu-disclaimer'; -import AddMoreWallets from 'Components/add-more-wallets'; +import classNames from 'classnames'; +import { observer } from 'mobx-react-lite'; import './traders-hub.scss'; const TradersHub = observer(() => { const { traders_hub, client, ui } = useStore(); const { notification_messages_ui: Notifications } = ui; - const { - is_landing_company_loaded, - is_logged_in, - is_switching, - is_logging_in, - is_account_setting_loaded, - accounts, - loginid, - } = client; - const { is_tour_open, is_eu_user } = traders_hub; + const { is_landing_company_loaded, is_logged_in, is_switching, is_logging_in, is_account_setting_loaded } = client; + const { selected_platform_type, setTogglePlatformType, is_tour_open, content_flag, is_eu_user } = traders_hub; const traders_hub_ref = React.useRef() as React.MutableRefObject; - const can_show_notify = - !is_switching && - !is_logging_in && - is_account_setting_loaded && - is_landing_company_loaded && - Notifications !== null; + const can_show_notify = !is_switching && !is_logging_in && is_account_setting_loaded && is_landing_company_loaded; const [scrolled, setScrolled] = React.useState(false); @@ -52,40 +40,79 @@ const TradersHub = observer(() => { }, 100); }, [is_tour_open]); - const { is_low_risk_cr_eu } = useContentFlag(); + const eu_title = content_flag === ContentFlag.EU_DEMO || content_flag === ContentFlag.EU_REAL || is_eu_user; + + const is_eu_low_risk = content_flag === ContentFlag.LOW_RISK_CR_EU; + const platform_toggle_options = [ + { text: `${eu_title ? 'Multipliers' : 'Options & Multipliers'}`, value: 'options' }, + { text: 'CFDs', value: 'cfd' }, + ]; + + const platformTypeChange = (event: { + target: { + value: string; + name: string; + }; + }) => { + setTogglePlatformType(event.target.value); + }; if (!is_logged_in) return null; - // TODO: change it when 'wallet' property will be in authorize response - const is_wallet_account = Object.keys(accounts).some(key => accounts[key]?.account_category === 'wallet'); + const EUDisclamer = () => { + return ( +
+ + ]} + /> + +
+ ); + }; return ( - + <> {can_show_notify && } -
- {is_wallet_account ? : } - +
+ + +
+ + +
+
+ + {is_landing_company_loaded ? ( + + ) : ( + + )} + {selected_platform_type === 'options' && } + {selected_platform_type === 'cfd' && } + {scrolled && }
- {is_low_risk_cr_eu && } - + {is_eu_low_risk && } + ); }); diff --git a/packages/appstore/src/modules/traders-hub/traders-hub.scss b/packages/appstore/src/modules/traders-hub/traders-hub.scss index 4ff6454c1656..ab9fd05592b9 100644 --- a/packages/appstore/src/modules/traders-hub/traders-hub.scss +++ b/packages/appstore/src/modules/traders-hub/traders-hub.scss @@ -1,30 +1,13 @@ .traders-hub { max-width: 123.2rem; margin: auto; - padding: 2.4rem 0; + padding: 5rem 0; @include mobile { padding: 2rem; width: 100%; } - &__wallets { - @include mobile { - padding: 1.6rem; - background-color: var(--general-main-1); - } - - &-bg { - background-color: var(--general-section-1); - } - - &-demo-bg { - @include mobile { - background-color: var(--wallet-demo-bg-color); - } - } - } - &__main-container { display: flex; flex-direction: column; @@ -52,3 +35,28 @@ } } } + +.disclamer { + position: fixed; + bottom: 3.6rem; + width: 100%; + height: 5rem; + z-index: 3; + display: flex; + align-items: center; + backface-visibility: hidden; + background: var(--icon-grey-background); + + @include mobile { + height: 8rem; + border: 1px solid var(--icon-grey-background); + } + + &-text { + padding: 0 3rem; + + @include mobile { + padding: 0 1.5rem; + } + } +} diff --git a/packages/appstore/src/modules/wallets/desktop-wallets-list.tsx b/packages/appstore/src/modules/wallets/desktop-wallets-list.tsx new file mode 100644 index 000000000000..3f73ece0fef8 --- /dev/null +++ b/packages/appstore/src/modules/wallets/desktop-wallets-list.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { useWalletsList } from '@deriv/hooks'; +import { observer } from '@deriv/stores'; +import Wallet from 'Components/containers/wallet'; + +const DesktopWalletsList = observer(() => { + const { data } = useWalletsList(); + + return ( + <> + {data?.map(wallet => ( + + ))} + + ); +}); + +export default DesktopWalletsList; diff --git a/packages/appstore/src/modules/wallets/index.ts b/packages/appstore/src/modules/wallets/index.ts new file mode 100644 index 000000000000..b8cb10bdc8c3 --- /dev/null +++ b/packages/appstore/src/modules/wallets/index.ts @@ -0,0 +1 @@ +export { default as WalletsModule } from './wallets'; diff --git a/packages/appstore/src/modules/wallets/mobile-wallets-carousel.tsx b/packages/appstore/src/modules/wallets/mobile-wallets-carousel.tsx new file mode 100644 index 000000000000..bc92679498c8 --- /dev/null +++ b/packages/appstore/src/modules/wallets/mobile-wallets-carousel.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { ButtonToggle } from '@deriv/components'; +import { useActiveWallet, useContentFlag } from '@deriv/hooks'; +import { observer, useStore } from '@deriv/stores'; +import ButtonToggleLoader from 'Components/pre-loader/button-toggle-loader'; +import WalletCardsCarousel from 'Components/wallet-cards-carousel'; +import WalletCFDsListing from 'Components/wallet-content/wallet-cfds-listing'; +import WalletOptionsAndMultipliersListing from 'Components/wallet-content/wallet-option-multipliers-listing'; +import classNames from 'classnames'; + +const MobileWalletsCarousel = observer(() => { + const { client, traders_hub } = useStore(); + const { is_landing_company_loaded } = client; + const { selected_platform_type, setTogglePlatformType, is_eu_user } = traders_hub; + const { is_eu_demo, is_eu_real } = useContentFlag(); + const eu_title = is_eu_demo || is_eu_real || is_eu_user; + const active_wallet = useActiveWallet(); + + const platform_toggle_options = [ + { text: 'CFDs', value: 'cfd' }, + { text: eu_title ? 'Multipliers' : 'Options & Multipliers', value: 'options' }, + ]; + + const platformTypeChange = (event: { target: { value: string; name: string } }) => { + setTogglePlatformType(event.target.value); + }; + + return ( + <> + +
+ {is_landing_company_loaded ? ( + + ) : ( + + )} + {selected_platform_type === 'cfd' && } + {selected_platform_type === 'options' && } +
+ + ); +}); + +export default MobileWalletsCarousel; diff --git a/packages/appstore/src/modules/wallets/wallets.scss b/packages/appstore/src/modules/wallets/wallets.scss new file mode 100644 index 000000000000..d8db8f5d55c7 --- /dev/null +++ b/packages/appstore/src/modules/wallets/wallets.scss @@ -0,0 +1,25 @@ +.wallets-module { + display: flex; + min-height: 92.8vh; + background-color: var(--general-section-1); + + @include mobile { + min-height: 100vh; + } + + &__content { + width: 100%; + max-width: 131.2rem; + margin: auto; + display: flex; + padding: 4rem; + flex-direction: column; + align-items: center; + gap: 2.4rem; + align-self: stretch; + + @include mobile { + padding: 2.4rem 0; + } + } +} diff --git a/packages/appstore/src/modules/wallets/wallets.tsx b/packages/appstore/src/modules/wallets/wallets.tsx new file mode 100644 index 000000000000..c1e9fb0506bf --- /dev/null +++ b/packages/appstore/src/modules/wallets/wallets.tsx @@ -0,0 +1,38 @@ +import React, { useEffect } from 'react'; +import { Loading, ThemedScrollbars } from '@deriv/components'; +import { useActiveWallet, useWalletsList } from '@deriv/hooks'; +import { observer, useStore } from '@deriv/stores'; +import AddMoreWallets from 'Components/add-more-wallets'; +import ModalManager from 'Components/modals/modal-manager'; +import DesktopWalletsList from './desktop-wallets-list'; +import MobileWalletsCarousel from './mobile-wallets-carousel'; +import './wallets.scss'; + +const Wallets = observer(() => { + const { client, ui } = useStore(); + const { switchAccount, is_authorize } = client; + const { is_mobile } = ui; + const { data } = useWalletsList(); + const active_wallet = useActiveWallet(); + + useEffect(() => { + if (!active_wallet && data && data?.length) { + switchAccount(data[0].loginid); + } + }, [active_wallet, data, switchAccount]); + + return ( + + {!is_authorize && } + {is_authorize && ( +
+ {is_mobile ? : } + +
+ )} + +
+ ); +}); + +export default Wallets; diff --git a/packages/appstore/src/services/websocket.ts b/packages/appstore/src/services/websocket.ts deleted file mode 100644 index b2ac6e22830e..000000000000 --- a/packages/appstore/src/services/websocket.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { DerivWS } from 'Types'; - -let ws: DerivWS = null; - -export const useWs = (): DerivWS => ws; - -export const initWs = (ws_instance: DerivWS): void => (ws = ws_instance); diff --git a/packages/appstore/src/stores/base-store.ts b/packages/appstore/src/stores/base-store.ts deleted file mode 100644 index b24a80ad456d..000000000000 --- a/packages/appstore/src/stores/base-store.ts +++ /dev/null @@ -1,9 +0,0 @@ -import RootStore from './root-store'; - -export default class BaseStore { - public root_store: RootStore; - - public constructor(root_store: RootStore) { - this.root_store = root_store; - } -} diff --git a/packages/appstore/src/stores/config-store.ts b/packages/appstore/src/stores/config-store.ts deleted file mode 100644 index abe3d633621e..000000000000 --- a/packages/appstore/src/stores/config-store.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { TConfigProps } from 'Types'; -import BaseStore from './base-store'; - -export default class ConfigStore extends BaseStore { - public has_router = true; - public routes = { - traders_hub: '/appstore/traders-hub', - onboarding: '/appstore/onboarding', - - my_apps: '/my-apps', - explore: '/explore', - about_us: '/about-us', - resources: '/resources', - - market_commodities: '/markets/commodities', - market_forex: '/markets/forex', - market_stock: '/markets/stock', - market_synthetic: '/markets/synthetic', - markets: '/markets', - - platform_binary_bot: '/platforms/binary-bot', - platform_dbot: '/platforms/dbot', - platform_dmt5: '/platforms/dmt5', - platform_dmt5_financial: '/platforms/dmt5-financial', - platform_dmt5_financial_stp: '/platforms/dmt5-financial-stp', - platform_dmt5_synthetic: '/platforms/dmt5-synthetic', - platform_dtrader: '/platforms/dtrader', - platform_smarttrader: '/platforms/smarttrader', - platforms: '/platforms', - - trade_type_cfds: '/trade-types/cfds', - trade_type_multipliers: '/trade-types/multipliers', - trade_type_options: '/trade-types/options', - trade_types: '/trade-types', - - wallet_bank_wire: '/wallets/bank-wire', - wallet_cards: '/wallets/cards', - wallet_crypto: '/wallets/crypto', - wallet_ewallet: '/wallets/ewallet', - wallets: '/wallets', - }; - - public setConfig(config: TConfigProps): void { - this.has_router = config.has_router; - this.routes = config.routes; - } -} diff --git a/packages/appstore/src/stores/index.ts b/packages/appstore/src/stores/index.ts index 7f15b07398b9..86259b611fcd 100644 --- a/packages/appstore/src/stores/index.ts +++ b/packages/appstore/src/stores/index.ts @@ -1,18 +1,4 @@ -import * as React from 'react'; -import { initWs } from 'Services/websocket'; -import { TRootStore } from 'Types'; -import RootStore from './root-store'; - -let stores_context: React.Context; - -export const initContext = (core_store: TRootStore, websocket: Record): void => { - if (!stores_context) { - const root_store = new RootStore(core_store); - stores_context = React.createContext(root_store); - - initWs(websocket); - } -}; +import { useStore } from '@deriv/stores'; /** @deprecated Use `useStore` from `@deriv/stores` package instead. */ -export const useStores = (): TRootStore => React.useContext(stores_context); +export const useStores: () => any = useStore; diff --git a/packages/appstore/src/stores/root-store.ts b/packages/appstore/src/stores/root-store.ts deleted file mode 100644 index 471185b72deb..000000000000 --- a/packages/appstore/src/stores/root-store.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { TRootStore } from 'Types'; -import ConfigStore from './config-store'; - -export default class RootStore { - public config: ConfigStore; - public ws: unknown; - public client: Record; - public common: Record; - public ui: Record; - public modules: Record; - public notifications: Record; - public traders_hub: Record; - - public constructor(core_store: TRootStore) { - this.config = new ConfigStore(this); - this.client = core_store.client; - this.common = core_store.common; - this.ui = core_store.ui; - this.modules = core_store.modules; - this.notifications = core_store.notifications; - this.traders_hub = core_store.traders_hub; - } -} diff --git a/packages/appstore/src/types/api.types.ts b/packages/appstore/src/types/api.types.ts deleted file mode 100644 index 90ebe40a82b9..000000000000 --- a/packages/appstore/src/types/api.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type TErrorResponse = - | { - message: string; - code: string; - } - | undefined; diff --git a/packages/appstore/src/types/index.ts b/packages/appstore/src/types/index.ts index edc109feef38..237db8bfebe2 100644 --- a/packages/appstore/src/types/index.ts +++ b/packages/appstore/src/types/index.ts @@ -1,6 +1 @@ -export * from './props.types'; -export * from './stores.types'; -export * from './params.types'; -export * from './api.types'; -export * from './ws.types'; export * from './common.types'; diff --git a/packages/appstore/src/types/params.types.ts b/packages/appstore/src/types/params.types.ts deleted file mode 100644 index 182bbc23e79d..000000000000 --- a/packages/appstore/src/types/params.types.ts +++ /dev/null @@ -1,30 +0,0 @@ -export type TRoute = { - component?: any; - default?: boolean; - exact?: boolean; - getTitle?: () => string; - icon?: string; - is_authenticated?: boolean; - is_routed?: boolean; - is_modal?: boolean; - label?: string; - path?: string; - routes?: TRoute[]; - subroutes?: TRoute[]; - to?: string; - is_logged_in?: boolean; - is_logging_in?: boolean; -}; - -export type TRouteGroup = { - default?: boolean; - icon?: string; - getTitle?: () => string; - path?: string; - subitems?: number[]; -}; -export type TRouteConfig = TRoute & { - is_modal?: boolean; - is_authenticated?: boolean; - routes?: TRoute[]; -}; diff --git a/packages/appstore/src/types/props.types.ts b/packages/appstore/src/types/props.types.ts deleted file mode 100644 index ed94bb03b11d..000000000000 --- a/packages/appstore/src/types/props.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import ConfigStore from 'Stores/config-store'; - -export type TConfigProps = { - has_router: boolean; - routes: ConfigStore['routes']; -}; diff --git a/packages/appstore/src/types/stores.types.ts b/packages/appstore/src/types/stores.types.ts deleted file mode 100644 index 690863da4f7e..000000000000 --- a/packages/appstore/src/types/stores.types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import ConfigStore from 'Stores/config-store'; - -export type TRootStore = { - ui: Record; - common: Record; - client: Record; - config: ConfigStore; - modules: Record; - notifications: Record; - traders_hub: Record; -}; diff --git a/packages/appstore/src/types/ws.types.ts b/packages/appstore/src/types/ws.types.ts deleted file mode 100644 index 8dc541ad5384..000000000000 --- a/packages/appstore/src/types/ws.types.ts +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type DerivWS = any; diff --git a/packages/cfd/src/Stores/Modules/CFD/cfd-store.js b/packages/cfd/src/Stores/Modules/CFD/cfd-store.js index 9680f5742435..cb91c49a0338 100644 --- a/packages/cfd/src/Stores/Modules/CFD/cfd-store.js +++ b/packages/cfd/src/Stores/Modules/CFD/cfd-store.js @@ -1,6 +1,6 @@ import { action, computed, observable, reaction, runInAction, makeObservable, override } from 'mobx'; import { getAccountListKey, getAccountTypeFields, CFD_PLATFORMS, WS, Jurisdiction } from '@deriv/shared'; -import BaseStore from 'Stores/base-store'; +import BaseStore from '../../base-store'; import { getDxCompanies, getMtCompanies, getDerivezCompanies } from './Helpers/cfd-config'; export default class CFDStore extends BaseStore { diff --git a/packages/cfd/src/Utils/Validator/validator.js b/packages/cfd/src/Utils/Validator/validator.js index c8aa2ce59dff..f6249ab21610 100644 --- a/packages/cfd/src/Utils/Validator/validator.js +++ b/packages/cfd/src/Utils/Validator/validator.js @@ -1,4 +1,4 @@ -import { template } from '_common/utility'; +import { template } from '../../_common/utility'; import { getPreBuildDVRs } from '@deriv/shared'; import Error from './errors'; diff --git a/packages/core/src/Stores/client-store.js b/packages/core/src/Stores/client-store.js index 50f815b8c278..1008a28fae1c 100644 --- a/packages/core/src/Stores/client-store.js +++ b/packages/core/src/Stores/client-store.js @@ -1556,7 +1556,7 @@ export default class ClientStore extends BaseStore { this.setIsLoggingIn(true); this.root_store.notifications.removeNotifications(true); this.root_store.notifications.removeAllNotificationMessages(true); - if (!this.is_virtual && /VRTC/.test(loginid)) { + if (!this.is_virtual && /VRTC|VRW/.test(loginid)) { this.setPrevRealAccountLoginid(this.loginid); } this.setSwitched(loginid); @@ -1956,7 +1956,7 @@ export default class ClientStore extends BaseStore { // if real to virtual --> switch to blue // if virtual to real --> switch to green // else keep the existing connection - const should_switch_socket_connection = this.is_virtual || /VRTC/.test(from_login_id); + const should_switch_socket_connection = this.is_virtual || /VRTC|VRW/.test(from_login_id); if (should_switch_socket_connection) { BinarySocket.closeAndOpenNewConnection(); diff --git a/packages/hooks/src/useAuthorize.ts b/packages/hooks/src/useAuthorize.ts index 727e826a0a6d..7f3d3b9e0408 100644 --- a/packages/hooks/src/useAuthorize.ts +++ b/packages/hooks/src/useAuthorize.ts @@ -8,10 +8,7 @@ const useAuthorize = (token?: string) => { const { accounts, loginid = '' } = client; const current_token = accounts[loginid || ''].token; - const { data, ...rest } = useFetch('authorize', { - payload: { authorize: token || current_token }, - options: { keepPreviousData: true }, - }); + const { data, ...rest } = useFetch('authorize', { payload: { authorize: token || current_token } }); // Add additional information to the authorize response. const modified_authorize = useMemo(() => ({ ...data?.authorize }), [data?.authorize]); diff --git a/packages/stores/src/stores/FeatureFlagsStore.ts b/packages/stores/src/stores/FeatureFlagsStore.ts index ca6a85211c28..904120a3b464 100644 --- a/packages/stores/src/stores/FeatureFlagsStore.ts +++ b/packages/stores/src/stores/FeatureFlagsStore.ts @@ -24,5 +24,7 @@ export default class FeatureFlagsStore extends BaseStore<{ [k in keyof typeof FL }); } }); + + this.data = FLAGS; } }