diff --git a/packages/cashier/src/constants/routes-config.ts b/packages/cashier/src/constants/routes-config.ts index 7ca18542942e..0a864ca73d22 100644 --- a/packages/cashier/src/constants/routes-config.ts +++ b/packages/cashier/src/constants/routes-config.ts @@ -1,8 +1,9 @@ import React from 'react'; +import P2P from '@deriv/p2p'; import { routes, moduleLoader } from '@deriv/shared'; import { localize } from '@deriv/translations'; import { Cashier } from '../containers'; -import { AccountTransfer, Deposit, OnRamp, P2PCashier, PaymentAgent, PaymentAgentTransfer, Withdrawal } from '../pages'; +import { AccountTransfer, Deposit, OnRamp, PaymentAgent, PaymentAgentTransfer, Withdrawal } from '../pages'; import { TRouteConfig, TRoute } from '../types'; // Error Routes @@ -52,13 +53,13 @@ const initRoutesConfig = (): TRouteConfig[] => [ }, { path: routes.cashier_p2p, - component: P2PCashier, + component: P2P, getTitle: () => localize('Deriv P2P'), icon_component: 'IcDp2p', }, { path: routes.cashier_p2p_verification, - component: P2PCashier, + component: P2P, getTitle: () => localize('Deriv P2P'), icon_component: 'IcDp2p', is_invisible: true, diff --git a/packages/cashier/src/pages/index.js b/packages/cashier/src/pages/index.js index 621c185b33c3..3c23a1220c01 100644 --- a/packages/cashier/src/pages/index.js +++ b/packages/cashier/src/pages/index.js @@ -1,9 +1,8 @@ import AccountTransfer from './account-transfer'; import Deposit from './deposit'; import OnRamp from './on-ramp'; -import P2PCashier from './p2p-cashier'; import PaymentAgent from './payment-agent'; import PaymentAgentTransfer from './payment-agent-transfer'; import Withdrawal from './withdrawal'; -export { AccountTransfer, Deposit, OnRamp, P2PCashier, PaymentAgent, PaymentAgentTransfer, Withdrawal }; +export { AccountTransfer, Deposit, OnRamp, PaymentAgent, PaymentAgentTransfer, Withdrawal }; diff --git a/packages/cashier/src/pages/p2p-cashier/__tests__/p2p-cashier.spec.tsx b/packages/cashier/src/pages/p2p-cashier/__tests__/p2p-cashier.spec.tsx deleted file mode 100644 index a0092ee1f0e3..000000000000 --- a/packages/cashier/src/pages/p2p-cashier/__tests__/p2p-cashier.spec.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import P2PCashier from '../p2p-cashier'; -import { createBrowserHistory } from 'history'; -import { Router } from 'react-router'; -import { routes } from '@deriv/shared'; -import { TRootStore } from 'Types'; -import CashierProviders from '../../../cashier-providers'; - -jest.mock('@deriv/components', () => ({ - ...jest.requireActual('@deriv/components'), - Loading: () =>
Loading
, -})); - -jest.mock('@deriv/p2p', () => jest.fn(() => 'P2P')); - -describe('', () => { - const history = createBrowserHistory(); - - it('should render component', () => { - const mockRootStore: DeepPartial = { - notifications: { - addNotificationMessage: jest.fn(), - filterNotificationMessages: jest.fn(), - refreshNotifications: jest.fn(), - removeNotificationByKey: jest.fn(), - removeNotificationMessage: jest.fn(), - setP2POrderProps: jest.fn(), - }, - client: { - balance: '', - currency: '', - local_currency_config: {}, - loginid: '', - is_logging_in: true, - is_virtual: false, - residence: '', - }, - ui: { - notification_messages_ui: null, - is_dark_mode_on: false, - is_mobile: false, - setCurrentFocus: jest.fn(), - current_focus: '', - }, - common: { - platform: '', - }, - modules: { - cashier: { - general_store: { - setNotificationCount: jest.fn(), - setOnRemount: jest.fn(), - }, - }, - }, - }; - - render( - - - , - { wrapper: ({ children }) => {children} } - ); - - expect(screen.getByText('Loading')).toBeInTheDocument(); - }); - - it('should render component', () => { - const mockRootStore: DeepPartial = { - notifications: { - addNotificationMessage: jest.fn(), - filterNotificationMessages: jest.fn(), - refreshNotifications: jest.fn(), - removeNotificationByKey: jest.fn(), - removeNotificationMessage: jest.fn(), - setP2POrderProps: jest.fn(), - }, - client: { - balance: '', - currency: '', - local_currency_config: {}, - loginid: '', - is_logging_in: false, - is_virtual: false, - residence: '', - }, - ui: { - notification_messages_ui: null, - is_dark_mode_on: false, - is_mobile: false, - setCurrentFocus: jest.fn(), - current_focus: '', - }, - common: { - platform: '', - }, - modules: { - cashier: { - general_store: { - setNotificationCount: jest.fn(), - setOnRemount: jest.fn(), - }, - }, - }, - }; - - render( - - - , - { wrapper: ({ children }) => {children} } - ); - - expect(screen.getByText('P2P')).toBeInTheDocument(); - }); - - it('should redirect to "/cashier/p2p" page with "?order=1" query parameter', () => { - const history_copy = { ...history, location: { ...history.location, search: 'order=1' } }; - const mockRootStore: DeepPartial = { - notifications: { - addNotificationMessage: jest.fn(), - filterNotificationMessages: jest.fn(), - refreshNotifications: jest.fn(), - removeNotificationByKey: jest.fn(), - removeNotificationMessage: jest.fn(), - setP2POrderProps: jest.fn(), - }, - client: { - balance: '', - currency: '', - local_currency_config: {}, - loginid: '', - is_logging_in: false, - is_virtual: false, - residence: '', - }, - ui: { - notification_messages_ui: null, - is_dark_mode_on: false, - is_mobile: false, - setCurrentFocus: jest.fn(), - current_focus: '', - }, - common: { - platform: '', - }, - modules: { - cashier: { - general_store: { - setNotificationCount: jest.fn(), - setOnRemount: jest.fn(), - }, - }, - }, - }; - - render( - - - , - { wrapper: ({ children }) => {children} } - ); - - expect(history.location.pathname).toBe(routes.cashier_p2p); - }); -}); diff --git a/packages/cashier/src/pages/p2p-cashier/index.ts b/packages/cashier/src/pages/p2p-cashier/index.ts deleted file mode 100644 index 4682987fd223..000000000000 --- a/packages/cashier/src/pages/p2p-cashier/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import P2PCashier from './p2p-cashier'; - -export default P2PCashier; diff --git a/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx b/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx deleted file mode 100644 index ef2dcaf0eb48..000000000000 --- a/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import React from 'react'; -import { RouteComponentProps } from 'react-router'; -import { withRouter } from 'react-router-dom'; -import { getLanguage } from '@deriv/translations'; -import { routes, WS } from '@deriv/shared'; -import { Loading } from '@deriv/components'; -import { observer, useStore } from '@deriv/stores'; -// TODO: Remove this ignorance after migrate p2p to TS and update the main file in package.json -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import P2P from '@deriv/p2p'; -import { get, init, timePromise } from 'Utils/server_time'; -import { useCashierStore } from '../../stores/useCashierStores'; - -type TP2PCashierProps = RouteComponentProps & { - history: History; - location: { - search: string; - hash: string; - }; -}; - -/* P2P will use the same websocket connection as Deriv/Binary, we need to pass it as a prop */ -const P2PCashier = observer(({ history, location }: TP2PCashierProps) => { - const { notifications, client, ui, common } = useStore(); - const { - addNotificationMessage, - client_notifications, - filterNotificationMessages, - refreshNotifications, - removeNotificationByKey, - removeNotificationMessage, - setP2POrderProps, - setP2PRedirectTo, - } = notifications; - const { - balance, - currency, - local_currency_config, - loginid, - is_logging_in, - is_virtual, - residence, - setP2pAdvertiserInfo, - } = client; - const { notification_messages_ui: Notifications, is_dark_mode_on, is_mobile, setCurrentFocus, current_focus } = ui; - const { platform } = common; - const { general_store } = useCashierStore(); - const { setNotificationCount, setOnRemount } = general_store; - const [order_id, setOrderId] = React.useState(null); - const [action_param, setActionParam] = React.useState(null); - const [code_param, setCodeParam] = React.useState(null); - const url_params = new URLSearchParams(location.search); - const server_time = { - get, - init, - timePromise, - }; - - const setQueryOrder = React.useCallback( - (input_order_id: string | null) => { - if (is_mobile) { - url_params.delete('action'); - url_params.delete('code'); - } - - if (url_params.has('order_id') || url_params.has('order')) { - url_params.delete('order'); - url_params.delete('order_id'); - } - - if (input_order_id) { - url_params.append('order', input_order_id); - } - - if (!input_order_id) { - history.replace({ - search: '', - hash: location.hash, - }); - - setOrderId(null); - } else if (order_id !== input_order_id) { - // Changing query params - history.push({ - pathname: routes.cashier_p2p, - search: url_params.toString(), - hash: location.hash, - }); - url_params.delete('action'); - url_params.delete('code'); - setOrderId(input_order_id); - } - }, - - // eslint-disable-next-line react-hooks/exhaustive-deps - [history, location.hash, location.search] - ); - - React.useEffect(() => { - let passed_order_id; - - setActionParam(url_params.get('action')); - if (is_mobile) { - setCodeParam(localStorage.getItem('verification_code.p2p_order_confirm')); - } else if (!code_param) { - if (url_params.has('code')) { - setCodeParam(url_params.get('code')); - } else if (localStorage.getItem('verification_code.p2p_order_confirm')) { - setCodeParam(localStorage.getItem('verification_code.p2p_order_confirm')); - } - } - - // Different emails give us different params (order / order_id), - // don't remove order_id since it's consistent for mobile and web for 2FA - if (url_params.has('order_id')) { - passed_order_id = url_params.get('order_id'); - } else if (url_params.has('order')) { - passed_order_id = url_params.get('order'); - } - - if (passed_order_id) { - setQueryOrder(passed_order_id); - } - - return () => setQueryOrder(null); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - if (is_logging_in) { - return ; - } - - return ( - - ); -}); - -export default withRouter(P2PCashier); diff --git a/packages/core/src/Stores/notification-store.js b/packages/core/src/Stores/notification-store.js index 4ac60715f603..56493a150f33 100644 --- a/packages/core/src/Stores/notification-store.js +++ b/packages/core/src/Stores/notification-store.js @@ -872,24 +872,24 @@ export default class NotificationStore extends BaseStore { }, p2p_daily_limit_increase: (currency, max_daily_buy, max_daily_sell) => { return { - action: - routes.cashier_p2p === window.location.pathname - ? { - onClick: () => { - this.p2p_redirect_to.redirectTo('my_profile'); - if (this.is_notifications_visible) this.toggleNotificationsModal(); - - this.removeNotificationMessage({ - key: 'p2p_daily_limit_increase', - should_show_again: false, - }); - }, - text: localize('Yes, increase my limits'), - } - : { - route: routes.cashier_p2p_profile, - text: localize('Yes, increase my limits'), + action: window.location.pathname.includes(routes.cashier_p2p) + ? { + onClick: () => { + this.p2p_redirect_to.redirectTo('my_profile'); + if (this.is_notifications_visible) this.toggleNotificationsModal(); + + this.removeNotificationMessage({ + key: 'p2p_daily_limit_increase', + should_show_again: false, + }); }, + text: localize('Yes, increase my limits'), + } + : { + // TODO: replace this with proper when fixing routes in p2p + route: routes.cashier_p2p_profile, + text: localize('Yes, increase my limits'), + }, header: , key: 'p2p_daily_limit_increase', message: ( diff --git a/packages/p2p/package.json b/packages/p2p/package.json index df517006fa68..a85e3b78b412 100644 --- a/packages/p2p/package.json +++ b/packages/p2p/package.json @@ -31,11 +31,16 @@ "license": "ISC", "dependencies": { "@deriv/components": "^1.0.0", + "@deriv/hooks": "^1.0.0", "@deriv/shared": "^1.0.0", + "@deriv/stores": "^1.0.0", + "@deriv/translations": "^1.0.0", "@testing-library/react": "^12.0.0", "classnames": "^2.2.6", + "commander": "^3.0.2", "crc-32": "^1.2.0", "formik": "^2.1.4", + "glob": "^7.1.5", "i18next": "^22.4.6", "lodash.debounce": "^4.0.8", "mobx": "^6.6.1", @@ -45,12 +50,11 @@ "react-content-loader": "^6.2.0", "react-dom": "^17.0.2", "react-i18next": "^11.11.0", + "react-router-dom": "^5.2.0", "react-simple-star-rating": "4.0.4", "react-svg-loader": "^3.0.3", "react-transition-group": "4.4.2", - "sendbird": "~3.0.137", - "glob": "^7.1.5", - "commander": "^3.0.2" + "sendbird": "~3.0.137" }, "devDependencies": { "@babel/eslint-parser": "^7.17.0", @@ -65,9 +69,9 @@ "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/preset-env": "^7.12.11", "@babel/preset-react": "^7.16.7", + "@deriv/publisher": "0.0.1-beta4", "@types/react": "^18.0.7", "@types/react-dom": "^18.0.0", - "@deriv/publisher": "0.0.1-beta4", "babel-core": "^6.26.3", "babel-loader": "^8.1.0", "copy-webpack-plugin": "^9.0.1", diff --git a/packages/p2p/src/components/__tests__/app-content.spec.js b/packages/p2p/src/components/__tests__/app-content.spec.js index 6b64a0dccd36..7a731b60fd3a 100644 --- a/packages/p2p/src/components/__tests__/app-content.spec.js +++ b/packages/p2p/src/components/__tests__/app-content.spec.js @@ -2,6 +2,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { useStores } from 'Stores'; import { useModalManagerContext } from 'Components/modal-manager/modal-manager-context'; +import { mockStore, StoreProvider } from '@deriv/stores'; import AppContent from '../app-content.jsx'; jest.mock('Stores', () => ({ @@ -49,7 +50,10 @@ describe('', () => { showModal: () => {}, hideModal: () => {}, })); - render(); + render(, { + // TODO: remove StoreProvider Wrappers when we fix routing for p2p + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('Tabs')).toBeInTheDocument(); expect(screen.queryByTestId('my_profile')).not.toBeInTheDocument(); @@ -59,7 +63,9 @@ describe('', () => { useStores.mockImplementation(() => ({ general_store: { ...mocked_store_values, is_loading: true }, })); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('Loading')).toBeInTheDocument(); }); @@ -68,7 +74,9 @@ describe('', () => { useStores.mockImplementation(() => ({ general_store: { ...mocked_store_values, should_show_dp2p_blocked: true }, })); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('Dp2pBlocked')).toBeInTheDocument(); }); @@ -77,25 +85,20 @@ describe('', () => { useStores.mockImplementation(() => ({ general_store: { ...mocked_store_values, should_show_popup: true }, })); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('NicknameForm')).toBeInTheDocument(); }); - it('should render verification component when should_show_verification state is true', () => { - useStores.mockImplementation(() => ({ - general_store: { ...mocked_store_values, props: { should_show_verification: true } }, - })); - render(); - - expect(screen.getByText('Verification')).toBeInTheDocument(); - }); - it('should render only the first notification component when multiple error status is set', () => { useStores.mockImplementation(() => ({ general_store: { ...mocked_store_values, should_show_popup: true, should_show_dp2p_blocked: true }, })); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.queryByText('NicknameForm')).not.toBeInTheDocument(); expect(screen.getByText('Dp2pBlocked')).toBeInTheDocument(); @@ -105,7 +108,9 @@ describe('', () => { useStores.mockImplementation(() => ({ general_store: { ...mocked_store_values, is_advertiser: true }, })); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByTestId('my_profile')).toBeInTheDocument(); }); diff --git a/packages/p2p/src/components/advertiser-page/advertiser-page-adverts.jsx b/packages/p2p/src/components/advertiser-page/advertiser-page-adverts.jsx index 098e8803d90a..92f7cb4a77b1 100644 --- a/packages/p2p/src/components/advertiser-page/advertiser-page-adverts.jsx +++ b/packages/p2p/src/components/advertiser-page/advertiser-page-adverts.jsx @@ -2,7 +2,7 @@ import React from 'react'; import classNames from 'classnames'; import { InfiniteDataList, Loading, Table, Tabs } from '@deriv/components'; import { isDesktop, isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { useStore, observer } from '@deriv/stores'; import { localize, Localize } from 'Components/i18next'; import { useStores } from 'Stores'; import Empty from 'Components/empty/empty.jsx'; @@ -10,7 +10,11 @@ import AdvertiserPageRow from './advertiser-page-row.jsx'; import './advertiser-page.scss'; const AdvertiserPageAdverts = () => { - const { advertiser_page_store, general_store } = useStores(); + const { + client: { currency }, + } = useStore(); + + const { advertiser_page_store } = useStores(); const AdvertiserPageRowRenderer = row_props => ( @@ -43,7 +47,7 @@ const AdvertiserPageAdverts = () => { {localize('Limits')} {localize('Rate (1 {{currency}})', { - currency: general_store.client.currency, + currency, })} diff --git a/packages/p2p/src/components/advertiser-page/advertiser-page-row.jsx b/packages/p2p/src/components/advertiser-page/advertiser-page-row.jsx index 569d2d377e32..2924093f038c 100644 --- a/packages/p2p/src/components/advertiser-page/advertiser-page-row.jsx +++ b/packages/p2p/src/components/advertiser-page/advertiser-page-row.jsx @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Button, Table, Text } from '@deriv/components'; import { isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { useStores } from 'Stores'; import { buy_sell } from 'Constants/buy-sell'; import { localize, Localize } from 'Components/i18next'; @@ -12,7 +12,9 @@ import './advertiser-page.scss'; const AdvertiserPageRow = ({ row: advert }) => { const { advertiser_page_store, buy_sell_store, floating_rate_store, general_store } = useStores(); - const { currency } = general_store.client; + const { + client: { currency }, + } = useStore(); const { effective_rate, local_currency, diff --git a/packages/p2p/src/components/advertiser-page/advertiser-page-stats.jsx b/packages/p2p/src/components/advertiser-page/advertiser-page-stats.jsx index 5abbbf6f6d71..f0afa51e934a 100644 --- a/packages/p2p/src/components/advertiser-page/advertiser-page-stats.jsx +++ b/packages/p2p/src/components/advertiser-page/advertiser-page-stats.jsx @@ -1,13 +1,16 @@ import React from 'react'; import { Money, Table, Text } from '@deriv/components'; import { isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { localize, Localize } from 'Components/i18next'; import { useStores } from 'Stores'; import './advertiser-page.scss'; const AdvertiserPageStats = () => { const { advertiser_page_store, general_store } = useStores(); + const { + client: { currency }, + } = useStore(); const is_my_advert = advertiser_page_store.advertiser_details_id === general_store.advertiser_id; // Use general_store.advertiser_info since resubscribing to the same id from advertiser page returns error @@ -140,7 +143,7 @@ const AdvertiserPageStats = () => { {buy_orders_amount && sell_orders_amount ? ( ) : ( @@ -223,7 +226,7 @@ const AdvertiserPageStats = () => { {buy_orders_amount && sell_orders_amount ? ( ) : ( diff --git a/packages/p2p/src/components/app-content.jsx b/packages/p2p/src/components/app-content.jsx index 9ad3a3815b52..161be9565f95 100644 --- a/packages/p2p/src/components/app-content.jsx +++ b/packages/p2p/src/components/app-content.jsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { isMobile } from '@deriv/shared'; import { Loading, Tabs } from '@deriv/components'; +import { useStore } from '@deriv/stores'; import { isAction, reaction } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useStores } from 'Stores'; @@ -13,19 +14,21 @@ import MyProfile from './my-profile'; import NicknameForm from './nickname-form'; import Orders from './orders/orders.jsx'; import TemporarilyBarredHint from './temporarily-barred-hint'; -import Verification from './verification/verification.jsx'; import { useModalManagerContext } from 'Components/modal-manager/modal-manager-context'; const AppContent = ({ order_id }) => { const { buy_sell_store, general_store } = useStores(); const { showModal, hideModal } = useModalManagerContext(); + const { + notifications: { setP2POrderProps }, + } = useStore(); React.useEffect(() => { return reaction( - () => general_store.props.setP2POrderProps, + () => setP2POrderProps, () => { - if (isAction(general_store.props.setP2POrderProps)) { - general_store.props.setP2POrderProps({ + if (isAction(setP2POrderProps)) { + setP2POrderProps({ order_id, redirectToOrderDetails: general_store.redirectToOrderDetails, setIsRatingModalOpen: is_open => { @@ -39,6 +42,7 @@ const AppContent = ({ order_id }) => { } } ); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); if (general_store.is_loading) { @@ -53,10 +57,6 @@ const AppContent = ({ order_id }) => { return ; } - if (general_store.props.should_show_verification) { - return ; - } - if (buy_sell_store?.show_advertiser_page && !buy_sell_store.should_show_verification) { return ; } diff --git a/packages/p2p/src/components/app.jsx b/packages/p2p/src/components/app.jsx index 708a4252df8a..f5a1ebe4ef56 100644 --- a/packages/p2p/src/components/app.jsx +++ b/packages/p2p/src/components/app.jsx @@ -1,8 +1,9 @@ -import classNames from 'classnames'; import * as React from 'react'; -import { observer } from 'mobx-react-lite'; -import PropTypes from 'prop-types'; -import { routes } from '@deriv/shared'; +import { useHistory, useLocation } from 'react-router-dom'; +import { useStore, observer } from '@deriv/stores'; +import { getLanguage } from '@deriv/translations'; +import { Loading } from '@deriv/components'; +import { routes, WS } from '@deriv/shared'; import ServerTime from 'Utils/server-time'; import { waitWS } from 'Utils/websocket'; import { useStores } from 'Stores'; @@ -11,26 +12,30 @@ import { setLanguage } from './i18next'; import { ModalManager, ModalManagerContextProvider } from './modal-manager'; import './app.scss'; -const App = props => { +// TODO: Add back props to get root_store to pass to StoreProvider component +const App = () => { + const { notifications, client, ui, common, modules } = useStore(); + const { balance, is_logging_in } = client; + const { setOnRemount } = modules?.cashier?.general_store; + + const { notification_messages_ui: Notifications, is_mobile } = ui; + const { setP2POrderProps } = notifications; + + const history = useHistory(); + const location = useLocation(); + const { general_store, order_store } = useStores(); + + const lang = getLanguage(); + + const [order_id, setOrderId] = React.useState(null); + const [action_param, setActionParam] = React.useState(); + const [code_param, setCodeParam] = React.useState(); const [should_show_profile, setShouldShowProfile] = React.useState(false); - const { - balance, - className, - history, - lang, - Notifications, - order_id, - server_time, - verification_action, - verification_code, - websocket_api, - setOnRemount, - } = props; React.useEffect(() => { - general_store.setAppProps(props); - general_store.setWebsocketInit(websocket_api); + general_store.setExternalStores({ client, common, modules, notifications, ui }); + general_store.setWebsocketInit(WS); general_store.getWebsiteStatus(); // Redirect back to /p2p, this was implemented for the mobile team. Do not remove. @@ -44,7 +49,7 @@ const App = props => { setShouldShowProfile(true); } - ServerTime.init(server_time); + ServerTime.init(general_store.server_time); // force safari refresh on back/forward window.onpageshow = function (event) { @@ -65,6 +70,80 @@ const App = props => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + React.useEffect(() => { + const url_params = new URLSearchParams(location.search); + + let passed_order_id; + + setActionParam(url_params.get('action')); + if (is_mobile) { + setCodeParam(localStorage.getItem('verification_code.p2p_order_confirm')); + } else if (!code_param) { + if (url_params.has('code')) { + setCodeParam(url_params.get('code')); + } else if (localStorage.getItem('verification_code.p2p_order_confirm')) { + setCodeParam(localStorage.getItem('verification_code.p2p_order_confirm')); + } + } + + // Different emails give us different params (order / order_id), + // don't remove order_id since it's consistent for mobile and web for 2FA + if (url_params.has('order_id')) { + passed_order_id = url_params.get('order_id'); + } else if (url_params.has('order')) { + passed_order_id = url_params.get('order'); + } + + if (passed_order_id) { + setQueryOrder(passed_order_id); + } + + return () => setQueryOrder(null); + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [setQueryOrder]); + + const setQueryOrder = React.useCallback( + input_order_id => { + const current_query_params = new URLSearchParams(location.search); + + if (is_mobile) { + current_query_params.delete('action'); + current_query_params.delete('code'); + } + + if (current_query_params.has('order_id') || current_query_params.has('order')) { + current_query_params.delete('order'); + current_query_params.delete('order_id'); + } + + if (input_order_id) { + current_query_params.append('order', input_order_id); + } + + if (!input_order_id) { + history.replace({ + search: '', + hash: location.hash, + }); + + setOrderId(null); + } else if (order_id !== input_order_id) { + // Changing query params + history.push({ + pathname: routes.cashier_p2p, + search: current_query_params.toString(), + hash: location.hash, + }); + + setOrderId(input_order_id); + } + }, + + // eslint-disable-next-line react-hooks/exhaustive-deps + [history, location.hash, location.search] + ); + React.useEffect(() => { setLanguage(lang); }, [lang]); @@ -78,6 +157,11 @@ const App = props => { general_store.redirectTo('orders'); order_store.setOrderId(order_id); } + setP2POrderProps({ + order_id, + redirectToOrderDetails: general_store.redirectToOrderDetails, + setIsRatingModalOpen: order_store.setIsRatingModalOpen, + }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [order_id]); @@ -87,25 +171,26 @@ const App = props => { }, [balance]); React.useEffect(() => { - setLanguage(lang); - }, [lang]); - - React.useEffect(() => { - if (verification_code) { + if (code_param) { // We need an extra state since we delete the code from the query params. // Do not remove. - order_store.setVerificationCode(verification_code); + order_store.setVerificationCode(code_param); } - if (verification_action && verification_code) { + if (action_param && code_param) { general_store.showModal({ key: 'LoadingModal', props: {} }); - order_store.verifyEmailVerificationCode(verification_action, verification_code); + order_store.verifyEmailVerificationCode(action_param, code_param); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [verification_action, verification_code]); + }, [action_param, code_param]); + + if (is_logging_in) { + return ; + } return ( -
+ // TODO Wrap components with StoreProvider during routing p2p card +
@@ -115,19 +200,4 @@ const App = props => { ); }; -App.propTypes = { - balance: PropTypes.string, - className: PropTypes.string, - history: PropTypes.object, - lang: PropTypes.string, - modal_root_id: PropTypes.string.isRequired, - order_id: PropTypes.string, - server_time: PropTypes.object, - setNotificationCount: PropTypes.func, - setOnRemount: PropTypes.func, - verification_action: PropTypes.string, - verification_code: PropTypes.string, - websocket_api: PropTypes.object.isRequired, -}; - export default observer(App); diff --git a/packages/p2p/src/components/buy-sell/buy-sell-row.jsx b/packages/p2p/src/components/buy-sell/buy-sell-row.jsx index 663d1960f055..d1da36a7d8ac 100644 --- a/packages/p2p/src/components/buy-sell/buy-sell-row.jsx +++ b/packages/p2p/src/components/buy-sell/buy-sell-row.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { Table, Text, Button, Icon } from '@deriv/components'; import { isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { buy_sell } from 'Constants/buy-sell'; import { Localize, localize } from 'Components/i18next'; import { OnlineStatusAvatar } from 'Components/online-status'; @@ -15,6 +15,9 @@ import './buy-sell-row.scss'; const BuySellRow = ({ row: advert }) => { const { buy_sell_store, floating_rate_store, general_store } = useStores(); + const { + client: { currency }, + } = useStore(); if (advert.id === 'WATCH_THIS_SPACE') { // This allows for the sliding animation on the Buy/Sell toggle as it pushes @@ -116,10 +119,7 @@ const BuySellRow = ({ row: advert }) => {
- + {display_effective_rate} {local_currency} diff --git a/packages/p2p/src/components/buy-sell/buy-sell-table.jsx b/packages/p2p/src/components/buy-sell/buy-sell-table.jsx index 848bb54b36b6..7f5c6ccda4fc 100644 --- a/packages/p2p/src/components/buy-sell/buy-sell-table.jsx +++ b/packages/p2p/src/components/buy-sell/buy-sell-table.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { InfiniteDataList, Loading, Modal, RadioGroup, Table, Text } from '@deriv/components'; import { isDesktop } from '@deriv/shared'; import { reaction } from 'mobx'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { Localize } from 'Components/i18next'; import { TableError } from 'Components/table/table-error.jsx'; import { useStores } from 'Stores'; @@ -26,7 +26,10 @@ const BuySellRowRendererComponent = row_props => { const BuySellRowRenderer = observer(BuySellRowRendererComponent); const BuySellTable = ({ onScroll }) => { - const { buy_sell_store, general_store, my_profile_store } = useStores(); + const { buy_sell_store, my_profile_store } = useStores(); + const { + client: { currency }, + } = useStore(); React.useEffect( () => { @@ -93,10 +96,7 @@ const BuySellTable = ({ onScroll }) => { - + diff --git a/packages/p2p/src/components/daily-limit-modal/daily-limit-modal.jsx b/packages/p2p/src/components/daily-limit-modal/daily-limit-modal.jsx index ef87459edaca..a431a8cbd2fd 100644 --- a/packages/p2p/src/components/daily-limit-modal/daily-limit-modal.jsx +++ b/packages/p2p/src/components/daily-limit-modal/daily-limit-modal.jsx @@ -1,14 +1,16 @@ import React from 'react'; -import { observer } from 'mobx-react-lite'; import { Button, Loading, Modal, Text } from '@deriv/components'; import { formatMoney } from '@deriv/shared'; import { Localize, localize } from 'Components/i18next'; import { useStores } from 'Stores'; +import { observer, useStore } from '@deriv/stores'; const DailyLimitModal = () => { const { my_profile_store, general_store } = useStores(); const { daily_buy_limit, daily_sell_limit } = general_store.advertiser_info; - const { currency } = general_store.client; + const { + client: { currency }, + } = useStore(); const getModalHeaderTitle = () => { if (my_profile_store.is_loading_modal_open) { diff --git a/packages/p2p/src/components/dp2p-blocked/dp2p-blocked-checklist.jsx b/packages/p2p/src/components/dp2p-blocked/dp2p-blocked-checklist.jsx index 8875156d2d22..6da39a0ecd44 100644 --- a/packages/p2p/src/components/dp2p-blocked/dp2p-blocked-checklist.jsx +++ b/packages/p2p/src/components/dp2p-blocked/dp2p-blocked-checklist.jsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { useHistory } from 'react-router-dom'; import { Checklist } from '@deriv/components'; import { routes } from '@deriv/shared'; import { observer } from 'mobx-react-lite'; @@ -7,7 +8,7 @@ import { localize } from '../i18next'; const Dp2pBlockedChecklist = () => { const { general_store } = useStores(); - const { history } = general_store.props; + const history = useHistory(); if (general_store.is_high_risk_fully_authed_without_fa && !general_store.is_p2p_blocked_for_pa) { const checklist_items = [ diff --git a/packages/p2p/src/components/floating-rate/__test__/floating-rate.spec.js b/packages/p2p/src/components/floating-rate/__test__/floating-rate.spec.js index 313ab9ea3fea..079044df621f 100644 --- a/packages/p2p/src/components/floating-rate/__test__/floating-rate.spec.js +++ b/packages/p2p/src/components/floating-rate/__test__/floating-rate.spec.js @@ -1,6 +1,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import FloatingRate from '../floating-rate.jsx'; +import { mockStore, StoreProvider } from '@deriv/stores'; jest.mock('Stores', () => ({ ...jest.requireActual('Stores'), @@ -18,26 +19,35 @@ jest.mock('Stores', () => ({ describe('', () => { it('should render default state of the component with hint message and increment, decrement buttons', () => { - render(); + render(, { + // TODO: remove StoreProvider Wrappers when we fix routing for p2p + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('of the market rate')).toBeInTheDocument(); expect(screen.getAllByRole('button').length).toBe(2); }); it('should display error messages when error is passed as props', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('Floating rate error')).toBeInTheDocument(); }); it('should render market rate feed based on the floating rate value passed', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('Your rate is = 102.00')).toBeInTheDocument(); }); it('should render the exchange rate in hint', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('1 AED = 100.00')).toBeInTheDocument(); }); diff --git a/packages/p2p/src/components/floating-rate/floating-rate.jsx b/packages/p2p/src/components/floating-rate/floating-rate.jsx index 7128e5ed78c9..a9147d9e9d58 100644 --- a/packages/p2p/src/components/floating-rate/floating-rate.jsx +++ b/packages/p2p/src/components/floating-rate/floating-rate.jsx @@ -1,9 +1,9 @@ import classNames from 'classnames'; -import { observer } from 'mobx-react-lite'; import PropTypes from 'prop-types'; import React from 'react'; import { InputField, Text } from '@deriv/components'; import { formatMoney, isMobile, mobileOSDetect } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; import { localize } from 'Components/i18next'; import { useStores } from 'Stores'; import { setDecimalPlaces, removeTrailingZeros, percentOf, roundOffDecimal } from 'Utils/format-value'; @@ -20,7 +20,11 @@ const FloatingRate = ({ data_testid, ...props }) => { - const { floating_rate_store, general_store } = useStores(); + const { + ui: { current_focus, setCurrentFocus }, + } = useStore(); + + const { floating_rate_store } = useStores(); const os = mobileOSDetect(); const { name, value, required } = props; const market_feed = value ? percentOf(floating_rate_store.market_rate, value) : floating_rate_store.market_rate; @@ -54,7 +58,7 @@ const FloatingRate = ({ })} classNameDynamicSuffix='dc-input-suffix' classNameWrapper={classNames({ 'dc-input-wrapper--error': error_messages })} - current_focus={general_store.current_focus} + current_focus={current_focus} decimal_point_change={2} id='floating_rate_input' inline_prefix='%' @@ -66,7 +70,7 @@ const FloatingRate = ({ name={name} onBlur={onBlurHandler} onChange={change_handler} - setCurrentFocus={general_store.setCurrentFocus} + setCurrentFocus={setCurrentFocus} required={required} type={isMobile() && os !== 'iOS' ? 'tel' : 'number'} value={value} diff --git a/packages/p2p/src/components/modal-manager/modals/buy-sell-modal/buy-sell-modal.jsx b/packages/p2p/src/components/modal-manager/modals/buy-sell-modal/buy-sell-modal.jsx index a0c5db7443b5..161781377d6a 100644 --- a/packages/p2p/src/components/modal-manager/modals/buy-sell-modal/buy-sell-modal.jsx +++ b/packages/p2p/src/components/modal-manager/modals/buy-sell-modal/buy-sell-modal.jsx @@ -286,7 +286,7 @@ const BuySellModal = () => { width='456px' is_open={is_modal_open} title={} - portalId={general_store.props.modal_root_id} + portalId='modal_root' toggleModal={onCancel} > {/* Parent height - Modal.Header height - Modal.Footer height */} diff --git a/packages/p2p/src/components/modal-manager/modals/rate-change-modal/rate-change-modal.jsx b/packages/p2p/src/components/modal-manager/modals/rate-change-modal/rate-change-modal.jsx index 04cfd5eefd38..766bbc5fd109 100644 --- a/packages/p2p/src/components/modal-manager/modals/rate-change-modal/rate-change-modal.jsx +++ b/packages/p2p/src/components/modal-manager/modals/rate-change-modal/rate-change-modal.jsx @@ -1,15 +1,19 @@ -import { observer } from 'mobx-react-lite'; import React from 'react'; import { Button, Modal, Text } from '@deriv/components'; import { isMobile } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; import { localize, Localize } from 'Components/i18next'; import { useStores } from 'Stores'; import { useModalManagerContext } from 'Components/modal-manager/modal-manager-context'; import './rate-change-modal.scss'; const RateChangeModal = ({ currency }) => { - const { floating_rate_store, general_store } = useStores(); - const local_currency = currency ?? general_store.client?.local_currency_config?.currency; + const { + client: { local_currency_config }, + } = useStore(); + + const { floating_rate_store } = useStores(); + const local_currency = currency ?? local_currency_config?.currency; const { hideModal, is_modal_open } = useModalManagerContext(); const closeModal = () => { diff --git a/packages/p2p/src/components/my-ads/create-ad-form.jsx b/packages/p2p/src/components/my-ads/create-ad-form.jsx index 75faaa039769..9d22a2506f4e 100644 --- a/packages/p2p/src/components/my-ads/create-ad-form.jsx +++ b/packages/p2p/src/components/my-ads/create-ad-form.jsx @@ -11,8 +11,8 @@ import { ThemedScrollbars, } from '@deriv/components'; import { formatMoney, isDesktop, isMobile } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; import { reaction } from 'mobx'; -import { observer } from 'mobx-react-lite'; import FloatingRate from 'Components/floating-rate'; import { Localize, localize } from 'Components/i18next'; import { buy_sell } from 'Constants/buy-sell'; @@ -31,9 +31,12 @@ const CreateAdFormWrapper = ({ children }) => { }; const CreateAdForm = () => { + const { + client: { currency, local_currency_config }, + } = useStore(); + const { buy_sell_store, floating_rate_store, general_store, my_ads_store, my_profile_store } = useStores(); - const { currency, local_currency_config } = general_store.client; const should_not_show_auto_archive_message_again = React.useRef(false); const [selected_methods, setSelectedMethods] = React.useState([]); const { useRegisterModalProps } = useModalManagerContext(); diff --git a/packages/p2p/src/components/my-ads/create-ad-summary.jsx b/packages/p2p/src/components/my-ads/create-ad-summary.jsx index c83fb16cea20..b1a8de47c2e2 100644 --- a/packages/p2p/src/components/my-ads/create-ad-summary.jsx +++ b/packages/p2p/src/components/my-ads/create-ad-summary.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { formatMoney } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { Text } from '@deriv/components'; import { buy_sell } from 'Constants/buy-sell'; import { Localize } from 'Components/i18next'; @@ -10,8 +10,12 @@ import { useStores } from 'Stores'; import { removeTrailingZeros, roundOffDecimal, percentOf } from 'Utils/format-value'; const CreateAdSummary = ({ offer_amount, price_rate, type }) => { - const { floating_rate_store, general_store } = useStores(); - const { currency, local_currency_config } = general_store.client; + const { + client: { currency, local_currency_config }, + } = useStore(); + + const { floating_rate_store } = useStores(); + const market_feed = floating_rate_store.rate_type === ad_type.FLOAT ? floating_rate_store.market_rate : null; const display_offer_amount = offer_amount ? formatMoney(currency, offer_amount, true) : ''; diff --git a/packages/p2p/src/components/my-ads/edit-ad-summary.jsx b/packages/p2p/src/components/my-ads/edit-ad-summary.jsx index 85eabdebc855..c98d02d77b25 100644 --- a/packages/p2p/src/components/my-ads/edit-ad-summary.jsx +++ b/packages/p2p/src/components/my-ads/edit-ad-summary.jsx @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { formatMoney } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { Text } from '@deriv/components'; import { buy_sell } from 'Constants/buy-sell'; import { Localize } from 'Components/i18next'; @@ -10,8 +10,12 @@ import { useStores } from 'Stores'; import { removeTrailingZeros, roundOffDecimal, percentOf } from 'Utils/format-value'; const EditAdSummary = ({ offer_amount, price_rate, type }) => { - const { floating_rate_store, general_store, my_ads_store } = useStores(); - const { currency, local_currency_config } = general_store.client; + const { + client: { currency, local_currency_config }, + } = useStore(); + + const { floating_rate_store, my_ads_store } = useStores(); + const display_offer_amount = offer_amount ? formatMoney(currency, offer_amount, true) : ''; const market_feed = my_ads_store.required_ad_type === ad_type.FLOAT ? floating_rate_store.market_rate : null; diff --git a/packages/p2p/src/components/my-ads/my-ads-table.jsx b/packages/p2p/src/components/my-ads/my-ads-table.jsx index 82e0a59a26b9..a7218c4c93ac 100644 --- a/packages/p2p/src/components/my-ads/my-ads-table.jsx +++ b/packages/p2p/src/components/my-ads/my-ads-table.jsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import React from 'react'; import { Button, HintBox, InfiniteDataList, Loading, Table, Text } from '@deriv/components'; import { isDesktop, isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { localize, Localize } from 'Components/i18next'; import Empty from 'Components/empty/empty.jsx'; import ToggleAds from 'Components/my-ads/toggle-ads.jsx'; @@ -22,7 +22,10 @@ const getHeaders = offered_currency => [ ]; const AdSwitchHintBox = () => { - const { floating_rate_store, general_store } = useStores(); + const { floating_rate_store } = useStores(); + const { + client: { local_currency_config }, + } = useStore(); if (floating_rate_store.rate_type === ad_type.FLOAT) { return floating_rate_store.reached_target_date ? ( @@ -33,7 +36,7 @@ const AdSwitchHintBox = () => { 'Floating rates are enabled for {{local_currency}}. Ads with fixed rates will be deactivated. Switch to floating rates by {{end_date}}.' } values={{ - local_currency: general_store.client.local_currency_config.currency || '', + local_currency: local_currency_config.currency || '', end_date: floating_rate_store.fixed_rate_adverts_end_date || '', }} /> @@ -47,6 +50,9 @@ const AdSwitchHintBox = () => { const MyAdsTable = () => { const { floating_rate_store, general_store, my_ads_store } = useStores(); + const { + client: { currency }, + } = useStore(); React.useEffect(() => { my_ads_store.setAdverts([]); @@ -105,7 +111,7 @@ const MyAdsTable = () => { {isDesktop() && ( - {getHeaders(general_store.client.currency).map(header => ( + {getHeaders(currency).map(header => ( {header.text} ))} diff --git a/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-balance/my-profile-balance.jsx b/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-balance/my-profile-balance.jsx index 689b73cd1c89..d9c9856a2ccc 100644 --- a/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-balance/my-profile-balance.jsx +++ b/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-balance/my-profile-balance.jsx @@ -1,12 +1,15 @@ import * as React from 'react'; import { Button, Icon, Modal, Money, Text } from '@deriv/components'; import { isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { Localize, localize } from 'Components/i18next'; import { useStores } from 'Stores'; const MyProfileBalance = () => { const { general_store } = useStores(); + const { + client: { currency }, + } = useStore(); const [is_balance_tooltip_open, setIsBalanceTooltipOpen] = React.useState(false); return ( @@ -45,11 +48,7 @@ const MyProfileBalance = () => { />
- +
diff --git a/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-details-table/my-profile-details-table.jsx b/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-details-table/my-profile-details-table.jsx index 8816938eb075..aecf7e730fe7 100644 --- a/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-details-table/my-profile-details-table.jsx +++ b/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-details-table/my-profile-details-table.jsx @@ -3,13 +3,16 @@ import { Button, Money, Table, Text } from '@deriv/components'; import { formatMoney } from '@deriv/shared'; import { useStores } from 'Stores'; import { Localize } from 'Components/i18next'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; const MyProfileDetailsTable = () => { const { general_store, my_profile_store } = useStores(); + const { + client: { currency }, + } = useStore(); const { daily_buy_limit, daily_sell_limit, upgradable_daily_limits } = general_store.advertiser_info; - const { advertiser_buy_limit, advertiser_sell_limit, client } = general_store; + const { advertiser_buy_limit, advertiser_sell_limit } = general_store; return (
@@ -26,7 +29,7 @@ const MyProfileDetailsTable = () => { - + @@ -34,7 +37,7 @@ const MyProfileDetailsTable = () => { - + @@ -51,7 +54,7 @@ const MyProfileDetailsTable = () => { - + @@ -59,11 +62,7 @@ const MyProfileDetailsTable = () => { - + @@ -76,17 +75,9 @@ const MyProfileDetailsTable = () => { i18n_default_text='Want to increase your daily limits to <0>{{max_daily_buy}} {{currency}} (buy) and <1>{{max_daily_sell}} {{currency}} (sell)?' components={[, ]} values={{ - currency: client.currency, - max_daily_buy: formatMoney( - client.currency, - upgradable_daily_limits.max_daily_buy, - true - ), - max_daily_sell: formatMoney( - client.currency, - upgradable_daily_limits.max_daily_sell, - true - ), + currency, + max_daily_buy: formatMoney(currency, upgradable_daily_limits.max_daily_buy, true), + max_daily_sell: formatMoney(currency, upgradable_daily_limits.max_daily_sell, true), }} /> diff --git a/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-stats-table/my-profile-stats-table.jsx b/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-stats-table/my-profile-stats-table.jsx index 049c6ecc4d56..3d735d9f6731 100644 --- a/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-stats-table/my-profile-stats-table.jsx +++ b/packages/p2p/src/components/my-profile/my-profile-stats/my-profile-stats-table/my-profile-stats-table.jsx @@ -1,11 +1,15 @@ import * as React from 'react'; import { Money, Table, Text } from '@deriv/components'; import { isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { Localize, localize } from 'Components/i18next'; import { useStores } from 'Stores'; const MyProfileStatsTable = () => { + const { + client: { currency }, + } = useStore(); + const { general_store } = useStores(); const { @@ -141,15 +145,11 @@ const MyProfileStatsTable = () => { {show_lifetime_turnover_value ? ( - + ) : ( )} @@ -311,11 +311,11 @@ const MyProfileStatsTable = () => { {show_lifetime_turnover_value ? ( - + ) : ( )} diff --git a/packages/p2p/src/components/order-details/order-details.jsx b/packages/p2p/src/components/order-details/order-details.jsx index 5174003142f3..dc7d912c6463 100644 --- a/packages/p2p/src/components/order-details/order-details.jsx +++ b/packages/p2p/src/components/order-details/order-details.jsx @@ -1,8 +1,9 @@ import classNames from 'classnames'; import React from 'react'; +import { useHistory } from 'react-router-dom'; import { Button, HintBox, Icon, Text, ThemedScrollbars } from '@deriv/components'; import { formatMoney, isDesktop, isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { useStore, observer } from '@deriv/stores'; import { Localize, localize } from 'Components/i18next'; import Chat from 'Components/orders/chat/chat.jsx'; import StarRating from 'Components/star-rating'; @@ -23,7 +24,10 @@ import { useModalManagerContext } from 'Components/modal-manager/modal-manager-c import 'Components/order-details/order-details.scss'; const OrderDetails = observer(() => { - const { general_store, my_profile_store, order_store, sendbird_store, buy_sell_store } = useStores(); + const { buy_sell_store, general_store, my_profile_store, order_store, sendbird_store } = useStores(); + const { + notifications: { removeNotificationByKey, removeNotificationMessage, setP2POrderProps }, + } = useStore(); const { hideModal, showModal, useRegisterModalProps } = useModalManagerContext(); const { @@ -63,6 +67,8 @@ const OrderDetails = observer(() => { const [should_expand_all, setShouldExpandAll] = React.useState(false); const [remaining_review_time, setRemainingReviewTime] = React.useState(null); + const history = useHistory(); + const page_title = is_buy_order_for_user ? localize('Buy {{offered_currency}} order', { offered_currency: account_currency }) : localize('Sell {{offered_currency}} order', { offered_currency: account_currency }); @@ -109,11 +115,15 @@ const OrderDetails = observer(() => { order_store.setOrderPaymentMethodDetails(undefined); order_store.setOrderId(null); order_store.setActiveOrder(null); - general_store.props.setP2POrderProps({ + setP2POrderProps({ order_id: order_store.order_id, redirectToOrderDetails: general_store.redirectToOrderDetails, setIsRatingModalOpen: is_open => (is_open ? showRatingModal : hideModal), }); + history.replace({ + search: '', + hash: location.hash, + }); buy_sell_store.setIsCreateOrderSubscribed(false); buy_sell_store.unsubscribeCreateOrder(); }; @@ -134,10 +144,10 @@ const OrderDetails = observer(() => { is_user_recommended_previously, onClickDone: () => { order_store.setOrderRating(id); - general_store.props.removeNotificationMessage({ + removeNotificationMessage({ key: `order-${id}`, }); - general_store.props.removeNotificationByKey({ + removeNotificationByKey({ key: `order-${id}`, }); }, diff --git a/packages/p2p/src/components/orders/order-table/order-table-content.jsx b/packages/p2p/src/components/orders/order-table/order-table-content.jsx index f41b64562564..fb32f6d336d3 100644 --- a/packages/p2p/src/components/orders/order-table/order-table-content.jsx +++ b/packages/p2p/src/components/orders/order-table/order-table-content.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { Loading, Button, InfiniteDataList, Div100vhContainer } from '@deriv/components'; import { reaction } from 'mobx'; import { isMobile } from '@deriv/shared'; -import { observer } from 'mobx-react-lite'; +import { observer, useStore } from '@deriv/stores'; import { Localize, localize } from 'Components/i18next'; import { TableError } from 'Components/table/table-error.jsx'; import Empty from 'Components/empty/empty.jsx'; @@ -21,6 +21,9 @@ const ContentWrapper = ({ children }) => { const OrderTableContent = () => { const { general_store, order_store } = useStores(); + const { + client: { loginid }, + } = useStore(); React.useEffect( () => @@ -45,9 +48,8 @@ const OrderTableContent = () => { } if (order_store.orders.length) { - const { client, props } = general_store; const modified_list = order_store.orders - .map(order => createExtendedOrderDetails(order, client.loginid, props.server_time)) + .map(order => createExtendedOrderDetails(order, loginid, general_store.server_time)) // TODO: Get rid of this filter if confirmed that BE is sending correct data. .filter(order => (general_store.is_active_tab ? order.is_active_order : order.is_inactive_order)); diff --git a/packages/p2p/src/components/orders/order-table/order-table-row.jsx b/packages/p2p/src/components/orders/order-table/order-table-row.jsx index fe076edad526..42724f80531e 100644 --- a/packages/p2p/src/components/orders/order-table/order-table-row.jsx +++ b/packages/p2p/src/components/orders/order-table/order-table-row.jsx @@ -1,13 +1,14 @@ import React from 'react'; -import { observer } from 'mobx-react-lite'; +import { useStore, observer } from '@deriv/stores'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import { useHistory } from 'react-router-dom'; import { secondsToTimer } from 'Utils/date-time'; import { createExtendedOrderDetails } from 'Utils/orders'; import ServerTime from 'Utils/server-time'; import { useStores } from 'Stores'; import { DesktopWrapper, Icon, MobileWrapper, Table, Text } from '@deriv/components'; -import { formatMoney } from '@deriv/shared'; +import { formatMoney, routes } from '@deriv/shared'; import { localize } from 'Components/i18next'; import RatingCellRenderer from 'Components/rating-cell-renderer'; import { useModalManagerContext } from 'Components/modal-manager/modal-manager-context'; @@ -34,6 +35,11 @@ const OrderRow = ({ row: order }) => { }; }; const { general_store, order_store, sendbird_store } = useStores(); + const { + notifications: { removeNotificationByKey, removeNotificationMessage }, + client: { loginid }, + } = useStore(); + const [order_state, setOrderState] = React.useState(order); // Use separate state to force refresh when (FE-)expired. const [is_timer_visible, setIsTimerVisible] = React.useState(); const should_show_order_details = React.useRef(true); @@ -68,6 +74,8 @@ const OrderRow = ({ row: order }) => { const [remaining_time, setRemainingTime] = React.useState(getTimeLeft(order_expiry_milliseconds).label); const interval = React.useRef(null); + const history = useHistory(); + const isOrderSeen = order_id => { const { notifications } = general_store.getLocalStorageSettingsForLoginId(); return notifications.some(notification => notification.order_id === order_id && notification.is_seen === true); @@ -75,6 +83,16 @@ const OrderRow = ({ row: order }) => { const onRowClick = () => { if (should_show_order_details.current) { + const current_query_params = new URLSearchParams(location.search); + + current_query_params.append('order', order.id); + + history.replace({ + pathname: routes.cashier_p2p, + search: current_query_params.toString(), + hash: location.hash, + }); + return order_store.setOrderId(order.id); } @@ -92,8 +110,8 @@ const OrderRow = ({ row: order }) => { hideModal(); should_show_order_details.current = true; order_store.setRatingValue(0); - general_store.props.removeNotificationMessage({ key: `order-${id}` }); - general_store.props.removeNotificationByKey({ key: `order-${id}` }); + removeNotificationMessage({ key: `order-${id}` }); + removeNotificationByKey({ key: `order-${id}` }); order_store.setIsLoading(true); order_store.setOrders([]); order_store.loadMoreOrders({ startIndex: 0 }); @@ -112,9 +130,8 @@ const OrderRow = ({ row: order }) => { const { distance, label } = getTimeLeft(order_expiry_milliseconds); if (distance < 0) { - const { client, props } = general_store; setRemainingTime(label); - setOrderState(createExtendedOrderDetails(order.order_details, client.loginid, props.server_time)); + setOrderState(createExtendedOrderDetails(order.order_details, loginid, general_store.server_time)); clearInterval(interval.current); setIsTimerVisible(false); } else { diff --git a/packages/p2p/src/components/orders/popup.jsx b/packages/p2p/src/components/orders/popup.jsx index 3fb7f5d07ab1..4ac36e9b2d7b 100644 --- a/packages/p2p/src/components/orders/popup.jsx +++ b/packages/p2p/src/components/orders/popup.jsx @@ -3,180 +3,172 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import { Formik, Field, Form } from 'formik'; import { Button, Checkbox, Modal, Text, useSafeState } from '@deriv/components'; -import { observer } from 'mobx-react-lite'; -import { useStores } from 'Stores'; import { localize } from '../i18next'; import FormError from '../form/error.jsx'; -const FormWithConfirmation = observer( - ({ - cancel_text, - className, - has_cancel, - message, - onCancel, - onClickConfirm, - order_information, - setShouldShowPopup, - should_show_popup, - title, - width, - }) => { - const { general_store } = useStores(); - const handleSubmit = (values, { setStatus }) => onClickConfirm(setStatus); +const FormWithConfirmation = ({ + cancel_text, + className, + has_cancel, + message, + onCancel, + onClickConfirm, + order_information, + setShouldShowPopup, + should_show_popup, + title, + width, +}) => { + const handleSubmit = (values, { setStatus }) => onClickConfirm(setStatus); - return ( - - {({ isSubmitting, setFieldValue, values, status, submitForm }) => ( -
- ( - - {title} + return ( + + {({ isSubmitting, setFieldValue, values, status, submitForm }) => ( + + ( + + {title} + + )} + toggleModal={() => setShouldShowPopup(false)} + width={width} + > + +
+ + {message} - )} - toggleModal={() => setShouldShowPopup(false)} - width={width} - > - -
- - {message} - -
- - {({ field }) => ( - - setFieldValue('need_confirmation', !values.need_confirmation) - } - defaultChecked={values.need_confirmation} - label={localize("I've received {{amount}} {{currency}}.", { - amount: order_information.amount * order_information.rate, - currency: order_information.local_currency, - })} - classNameLabel='orders__popup-field_text' - /> - )} - -
+
+ + {({ field }) => ( + + setFieldValue('need_confirmation', !values.need_confirmation) + } + defaultChecked={values.need_confirmation} + label={localize("I've received {{amount}} {{currency}}.", { + amount: order_information.amount * order_information.rate, + currency: order_information.local_currency, + })} + classNameLabel='orders__popup-field_text' + /> + )} +
- - - {status?.error_message && } - - {has_cancel && ( - - )} -
+
+ + {status?.error_message && } + + {has_cancel && ( + - - - - - )} - - ); - } -); + )} + + + + + + )} + + ); +}; -const FormWithoutConfirmation = observer( - ({ - cancel_text, - className, - confirm_text, - has_cancel, - message, - onCancel, - onClickConfirm, - order_information, - setShouldShowPopup, - should_confirm_payment, - should_show_popup, - title, - width, - }) => { - const [should_disable_confirm, setShouldDisableConfirm] = useSafeState(true); - const [api_error_message, setApiErrorMessage] = useSafeState(null); - const { general_store } = useStores(); +const FormWithoutConfirmation = ({ + cancel_text, + className, + confirm_text, + has_cancel, + message, + onCancel, + onClickConfirm, + order_information, + setShouldShowPopup, + should_confirm_payment, + should_show_popup, + title, + width, +}) => { + const [should_disable_confirm, setShouldDisableConfirm] = useSafeState(true); + const [api_error_message, setApiErrorMessage] = useSafeState(null); - React.useEffect(() => { - setApiErrorMessage(null); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [should_show_popup]); + React.useEffect(() => { + setApiErrorMessage(null); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [should_show_popup]); - return ( - ( - - {title} + return ( + ( + + {title} + + )} + toggleModal={() => setShouldShowPopup(false)} + width={width} + > + +
+ + {message} - )} - toggleModal={() => setShouldShowPopup(false)} - width={width} - > - -
- - {message} - - {should_confirm_payment && ( -
- setShouldDisableConfirm(!should_disable_confirm)} - defaultChecked={!should_disable_confirm} - label={localize('I have paid {{amount}} {{currency}}.', { - amount: order_information.amount * order_information.rate, - currency: order_information.local_currency, - })} - /> -
- )} -
-
- - {api_error_message?.error_message && } - - {has_cancel && ( - - )} -
+
+ + {api_error_message?.error_message && } + + {has_cancel && ( + - - -
- ); - } -); + )} + + + +
+ ); +}; const Popup = props => { const { className, need_confirmation } = props; diff --git a/packages/p2p/src/components/verification/verification.jsx b/packages/p2p/src/components/verification/verification.jsx index abc3bbeb2c0e..e22da19d614b 100644 --- a/packages/p2p/src/components/verification/verification.jsx +++ b/packages/p2p/src/components/verification/verification.jsx @@ -47,7 +47,7 @@ const Verification = ({ should_wrap }) => { general_store.poi_status === 'verified' ? () => {} : () => { - window.location.href = `${general_store.props.poi_url}?ext_platform_url=${routes.cashier_p2p}`; + window.location.href = `${routes.proof_of_identity}?ext_platform_url=${routes.cashier_p2p}`; }, }, ]; diff --git a/packages/p2p/src/stores/general-store.js b/packages/p2p/src/stores/general-store.js index 222d1339377c..1ad4ea83a6c9 100644 --- a/packages/p2p/src/stores/general-store.js +++ b/packages/p2p/src/stores/general-store.js @@ -1,5 +1,6 @@ import React from 'react'; import { action, computed, observable, reaction, makeObservable } from 'mobx'; +import { get, init, timePromise } from '../../../cashier/src/utils/server_time'; import { isEmptyObject, isMobile, toMoment } from '@deriv/shared'; import BaseStore from 'Stores/base_store'; import { localize, Localize } from 'Components/i18next'; @@ -8,7 +9,7 @@ import { createExtendedOrderDetails } from 'Utils/orders'; import { init as WebsocketInit, requestWS, subscribeWS } from 'Utils/websocket'; import { order_list } from 'Constants/order-list'; import { buy_sell } from 'Constants/buy-sell'; -import { api_error_codes } from '../constants/api-error-codes'; +import { api_error_codes } from 'Constants/api-error-codes'; export default class GeneralStore extends BaseStore { active_index = 0; @@ -22,6 +23,7 @@ export default class GeneralStore extends BaseStore { balance; cancels_remaining = null; contact_info = ''; + external_stores = {}; feature_level = null; formik_ref = null; inactive_notification_count = 0; @@ -38,13 +40,11 @@ export default class GeneralStore extends BaseStore { is_restricted = false; nickname = null; nickname_error = ''; - notification_count = 0; order_table_type = order_list.ACTIVE; orders = []; parameters = null; payment_info = ''; poi_status = null; - props = {}; review_period; saved_form_state = null; should_show_real_name = false; @@ -62,6 +62,12 @@ export default class GeneralStore extends BaseStore { ws_subscriptions = {}; service_token_timeout; + server_time = { + get, + init, + timePromise, + }; + constructor(root_store) { // TODO: [mobx-undecorate] verify the constructor arguments and the arguments of this automatically generated super call super(root_store); @@ -76,6 +82,7 @@ export default class GeneralStore extends BaseStore { advertiser_relations_response: observable, //TODO: Remove this when backend has fixed is_blocked flag issue block_unblock_user_error: observable, balance: observable, + external_stores: observable, feature_level: observable, formik_ref: observable, inactive_notification_count: observable, @@ -90,12 +97,10 @@ export default class GeneralStore extends BaseStore { is_restricted: observable, nickname: observable, nickname_error: observable, - notification_count: observable, order_table_type: observable, orders: observable, parameters: observable, poi_status: observable, - props: observable.ref, review_period: observable, saved_form_state: observable, should_show_real_name: observable, @@ -104,10 +109,6 @@ export default class GeneralStore extends BaseStore { user_blocked_until: observable, is_high_risk_fully_authed_without_fa: observable, is_modal_open: observable, - client: computed, - current_focus: computed, - form_state: computed, - setCurrentFocus: computed, blocked_until_date_time: computed, is_active_tab: computed, is_barred: computed, @@ -132,8 +133,7 @@ export default class GeneralStore extends BaseStore { setAdvertiserId: action.bound, setAdvertiserBuyLimit: action.bound, setAdvertiserSellLimit: action.bound, - setAppProps: action.bound, - setAdvertiserRelationsResponse: action.bound, //TODO: Remove this when backend has fixed is_blocked flag issue + setExternalStores: action.bound, setFeatureLevel: action.bound, setFormikRef: action.bound, setSavedFormState: action.bound, @@ -149,7 +149,6 @@ export default class GeneralStore extends BaseStore { setIsModalOpen: action.bound, setNickname: action.bound, setNicknameError: action.bound, - setNotificationCount: action.bound, setOrderTableType: action.bound, setP2PConfig: action.bound, setP2pOrderList: action.bound, @@ -171,22 +170,6 @@ export default class GeneralStore extends BaseStore { }); } - get client() { - return { ...this.props?.client } || {}; - } - - get current_focus() { - return this.props?.current_focus; - } - - get form_state() { - return this.formik_ref; - } - - get setCurrentFocus() { - return this.props?.setCurrentFocus; - } - get blocked_until_date_time() { return getFormattedDateString(new Date(convertToMillis(this.user_blocked_until)), false, true); } @@ -289,7 +272,7 @@ export default class GeneralStore extends BaseStore { }; getLocalStorageSettingsForLoginId() { - const local_storage_settings = this.getLocalStorageSettings()[this.client.loginid]; + const local_storage_settings = this.getLocalStorageSettings()[this.external_stores.client.loginid]; if (isEmptyObject(local_storage_settings)) { return { is_cached: false, notifications: [] }; @@ -314,11 +297,14 @@ export default class GeneralStore extends BaseStore { handleNotifications(old_orders, new_orders) { const { order_store } = this.root_store; - const { client, props } = this; const { is_cached, notifications } = this.getLocalStorageSettingsForLoginId(); new_orders.forEach(new_order => { - const order_info = createExtendedOrderDetails(new_order, client.loginid, props.server_time); + const order_info = createExtendedOrderDetails( + new_order, + this.external_stores.client.loginid, + this.server_time + ); const notification = notifications.find(n => n.order_id === new_order.id); const old_order = old_orders.find(o => o.id === new_order.id); const is_current_order = new_order.id === order_store.order_id; @@ -341,14 +327,14 @@ export default class GeneralStore extends BaseStore { if ( type === buy_sell.BUY && status === 'completed' && - client_details.loginid === client.loginid + client_details.loginid === this.external_stores.client.loginid ) this.showCompletedOrderNotification(advertiser_details.name, id); if ( type === buy_sell.SELL && status === 'completed' && - advertiser_details.loginid === client.loginid + advertiser_details.loginid === this.external_stores.client.loginid ) this.showCompletedOrderNotification(client_details.name, id); } else { @@ -390,9 +376,9 @@ export default class GeneralStore extends BaseStore { const notification_key = `order-${order_id}`; // we need to refresh notifications in notifications-store in the case of a bug when user closes the notification, the notification count is not synced up with the closed notification - this.props.refreshNotifications(); + this.external_stores?.notifications.refreshNotifications(); - this.props.addNotificationMessage({ + this.external_stores?.notifications.addNotificationMessage({ action: { onClick: () => { if (order_store.order_id === order_id) { @@ -418,13 +404,10 @@ export default class GeneralStore extends BaseStore { showDailyLimitIncreaseNotification() { const { upgradable_daily_limits } = this.advertiser_info; const { max_daily_buy, max_daily_sell } = upgradable_daily_limits; + const { client, notifications } = this.external_stores; - this.props.addNotificationMessage( - this.props.client_notifications.p2p_daily_limit_increase( - this.client.currency, - max_daily_buy, - max_daily_sell - ) + notifications.addNotificationMessage( + notifications.client_notifications.p2p_daily_limit_increase(client.currency, max_daily_buy, max_daily_sell) ); } @@ -443,7 +426,7 @@ export default class GeneralStore extends BaseStore { () => this.user_blocked_until, blocked_until => { if (typeof blocked_until === 'number') { - const server_time = this.props.server_time.get(); + const server_time = this.server_time.get(); const blocked_until_moment = toMoment(blocked_until); // Need isAfter instead of setTimeout as setTimeout has a max delay of 24.8 days @@ -518,11 +501,11 @@ export default class GeneralStore extends BaseStore { exchange_rate_subscription: subscribeWS( { exchange_rates: 1, - base_currency: this.client.currency, + base_currency: this.external_stores.client.currency, subscribe: 1, target_currency: this.root_store.buy_sell_store.selected_local_currency ?? - this.client.local_currency_config?.currency, + this.external_stores.client.local_currency_config?.currency, }, [this.root_store.floating_rate_store.fetchExchangeRate] ), @@ -539,7 +522,7 @@ export default class GeneralStore extends BaseStore { this.setIsLoading(false); } - this.props.setP2PRedirectTo({ + this.external_stores.notifications.setP2PRedirectTo({ redirectTo: this.redirectTo, }); }); @@ -547,13 +530,13 @@ export default class GeneralStore extends BaseStore { subscribeToLocalCurrency() { const { floating_rate_store, buy_sell_store } = this.root_store; - const client_currency = this.client.local_currency_config?.currency; + const client_currency = this.external_stores.client.local_currency_config?.currency; this.ws_subscriptions?.exchange_rate_subscription?.unsubscribe?.(); this.ws_subscriptions.exchange_rate_subscription = subscribeWS( { exchange_rates: 1, - base_currency: this.client.currency, + base_currency: this.external_stores.client.currency, subscribe: 1, target_currency: this.active_index > 0 ? client_currency : buy_sell_store.local_currency ?? client_currency, @@ -577,8 +560,8 @@ export default class GeneralStore extends BaseStore { } this.setActiveIndex(0); - this.props.refreshNotifications(); - this.props.filterNotificationMessages(); + this.external_stores?.notifications.refreshNotifications(); + this.external_stores?.notifications.filterNotificationMessages(); } onNicknamePopupClose() { @@ -633,10 +616,6 @@ export default class GeneralStore extends BaseStore { this.advertiser_sell_limit = advertiser_sell_limit; } - setAppProps(props) { - this.props = props; - } - //TODO: Remove this when backend has fixed is_blocked flag issue setAdvertiserRelationsResponse(advertiser_relations_response) { this.advertiser_relations_response = advertiser_relations_response; @@ -654,6 +633,10 @@ export default class GeneralStore extends BaseStore { this.default_advert_description = default_advert_description; } + setExternalStores(external_stores) { + this.external_stores = external_stores; + } + setFeatureLevel(feature_level) { this.feature_level = feature_level; } @@ -722,10 +705,6 @@ export default class GeneralStore extends BaseStore { this.nickname_error = nickname_error; } - setNotificationCount(notification_count) { - this.notification_count = notification_count; - } - setOrderTableType(order_table_type) { const { order_store } = this.root_store; order_store.setIsLoading(true); @@ -908,18 +887,13 @@ export default class GeneralStore extends BaseStore { user_settings.notifications = notifications; const p2p_settings = this.getLocalStorageSettings(); - p2p_settings[this.client.loginid] = user_settings; + p2p_settings[this.external_stores.client.loginid] = user_settings; localStorage.setItem('p2p_settings', JSON.stringify(p2p_settings)); window.dispatchEvent(new Event('storage')); - this.setNotificationCount(notification_count); this.setActiveNotificationCount(active_notification_count); this.setInactiveNotificationCount(inactive_notification_count); - - if (typeof this.props?.setNotificationCount === 'function') { - this.props.setNotificationCount(notification_count); - } } validatePopup = values => { diff --git a/packages/p2p/src/stores/index.js b/packages/p2p/src/stores/index.js index 805c441d10dd..bfcc986d90f8 100644 --- a/packages/p2p/src/stores/index.js +++ b/packages/p2p/src/stores/index.js @@ -9,7 +9,7 @@ import OrderStore from './order-store'; import OrderDetailsStore from './order-details-store'; import SendbirdStore from './sendbird-store'; -class RootStore { +export default class RootStore { constructor() { this.general_store = new GeneralStore(this); // Leave at the top! this.advertiser_page_store = new AdvertiserPageStore(this); diff --git a/packages/p2p/src/stores/my-ads-store.js b/packages/p2p/src/stores/my-ads-store.js index 5cb2448f2824..9f8b0f1cdb33 100644 --- a/packages/p2p/src/stores/my-ads-store.js +++ b/packages/p2p/src/stores/my-ads-store.js @@ -626,7 +626,7 @@ export default class MyAdsStore extends BaseStore { v => v > 0 && decimalValidator(v) && - countDecimalPlaces(v) <= getDecimalPlaces(general_store.client.currency), + countDecimalPlaces(v) <= getDecimalPlaces(general_store.external_stores.client.currency), v => (values.offer_amount ? +v <= values.offer_amount : true), v => (values.min_transaction ? +v >= values.min_transaction : true), ], @@ -636,7 +636,7 @@ export default class MyAdsStore extends BaseStore { v => v > 0 && decimalValidator(v) && - countDecimalPlaces(v) <= getDecimalPlaces(general_store.client.currency), + countDecimalPlaces(v) <= getDecimalPlaces(general_store.external_stores.client.currency), v => (values.offer_amount ? +v <= values.offer_amount : true), v => (values.max_transaction ? +v <= values.max_transaction : true), ], @@ -646,7 +646,7 @@ export default class MyAdsStore extends BaseStore { v => v > 0 && decimalValidator(v) && - countDecimalPlaces(v) <= getDecimalPlaces(general_store.client.currency), + countDecimalPlaces(v) <= getDecimalPlaces(general_store.external_stores.client.currency), v => (values.min_transaction ? +v >= values.min_transaction : true), v => (values.max_transaction ? +v >= values.max_transaction : true), ], @@ -657,7 +657,8 @@ export default class MyAdsStore extends BaseStore { floating_rate_store.rate_type === ad_type.FIXED ? v > 0 && decimalValidator(v) && - countDecimalPlaces(v) <= general_store.client.local_currency_config.decimal_places + countDecimalPlaces(v) <= + general_store.external_stores.client.local_currency_config.decimal_places : true, v => floating_rate_store.rate_type === ad_type.FLOAT @@ -782,7 +783,7 @@ export default class MyAdsStore extends BaseStore { v => v > 0 && decimalValidator(v) && - countDecimalPlaces(v) <= getDecimalPlaces(general_store.client.currency), + countDecimalPlaces(v) <= getDecimalPlaces(general_store.external_stores.client.currency), v => (values.offer_amount ? +v <= values.offer_amount : true), v => (values.min_transaction ? +v >= values.min_transaction : true), ], @@ -792,7 +793,7 @@ export default class MyAdsStore extends BaseStore { v => v > 0 && decimalValidator(v) && - countDecimalPlaces(v) <= getDecimalPlaces(general_store.client.currency), + countDecimalPlaces(v) <= getDecimalPlaces(general_store.external_stores.client.currency), v => (values.offer_amount ? +v <= values.offer_amount : true), v => (values.max_transaction ? +v <= values.max_transaction : true), ], @@ -803,7 +804,8 @@ export default class MyAdsStore extends BaseStore { this.required_ad_type === ad_type.FIXED ? v > 0 && decimalValidator(v) && - countDecimalPlaces(v) <= general_store.client.local_currency_config.decimal_places + countDecimalPlaces(v) <= + general_store.external_stores.client.local_currency_config.decimal_places : true, v => this.required_ad_type === ad_type.FLOAT diff --git a/packages/p2p/src/stores/my-profile-store.js b/packages/p2p/src/stores/my-profile-store.js index 7e4ecc58201f..f1f2339d02f6 100644 --- a/packages/p2p/src/stores/my-profile-store.js +++ b/packages/p2p/src/stores/my-profile-store.js @@ -912,12 +912,12 @@ export default class MyProfileStore extends BaseStore { if (response.error) this.setIsErrorModalOpen(true); else this.setIsDailyLimitSuccessModalOpen(true); - general_store.props.removeNotificationByKey({ + general_store.external_stores.notifications.removeNotificationByKey({ key: 'p2p_daily_limit_increase', should_show_again: false, }); - general_store.client.setP2pAdvertiserInfo(false); + general_store.external_stores.client.setP2pAdvertiserInfo(false); } }); } diff --git a/packages/p2p/src/stores/order-store.js b/packages/p2p/src/stores/order-store.js index 839f320aa33e..1542f34ccc65 100644 --- a/packages/p2p/src/stores/order-store.js +++ b/packages/p2p/src/stores/order-store.js @@ -359,8 +359,8 @@ export default class OrderStore { const { general_store } = this.root_store; const order_information = createExtendedOrderDetails( input_order, - general_store.client.loginid, - general_store.props.server_time + general_store.external_stores.client.loginid, + general_store.server_time ); this.setOrderId(order_information.id); // Sets the id in URL if (order_information.is_active_order) { @@ -420,8 +420,8 @@ export default class OrderStore { const get_order_status = createExtendedOrderDetails( p2p_order_info, - general_store.client.loginid, - general_store.props.server_time + general_store.external_stores.client.loginid, + general_store.server_time ); const order_idx = this.orders.findIndex(order => order.id === p2p_order_info.id); @@ -451,8 +451,8 @@ export default class OrderStore { if (get_order_status.is_completed_order && !get_order_status.is_reviewable) { // Remove notification once order review period is finished const notification_key = `order-${p2p_order_info.id}`; - general_store.props.removeNotificationMessage({ key: notification_key }); - general_store.props.removeNotificationByKey({ key: notification_key }); + general_store.external_stores?.notifications.removeNotificationMessage({ key: notification_key }); + general_store.external_stores?.notifications.removeNotificationByKey({ key: notification_key }); } } @@ -563,12 +563,6 @@ export default class OrderStore { setOrderId(order_id) { this.order_id = order_id; - - const { general_store } = this.root_store; - - if (typeof general_store.props.setOrderId === 'function') { - general_store.props.setOrderId(order_id); - } } setOrderPaymentMethodDetails(order_payment_method_details) { diff --git a/packages/p2p/src/stores/sendbird-store.js b/packages/p2p/src/stores/sendbird-store.js index 450c720f88cd..7ccbc313bf3d 100644 --- a/packages/p2p/src/stores/sendbird-store.js +++ b/packages/p2p/src/stores/sendbird-store.js @@ -1,5 +1,5 @@ import SendBird from 'sendbird'; -import { epochToMoment } from '@deriv/shared'; +import { epochToMoment, toMoment } from '@deriv/shared'; import { action, computed, observable, reaction, makeObservable } from 'mobx'; import BaseStore from 'Stores/base_store'; import ChatMessage, { convertFromChannelMessage } from 'Utils/chat-message'; @@ -188,7 +188,7 @@ export default class SendbirdStore extends BaseStore { const custom_type = ''; this.active_chat_channel.getPreviousMessagesByTimestamp( - timestamp || this.root_store.general_store.props.server_time.get().utc().valueOf(), + timestamp || toMoment(this.root_store.general_store.server_time.get()).utc().valueOf(), is_inclusive_of_timestamp, result_size, reverse_results, @@ -213,7 +213,7 @@ export default class SendbirdStore extends BaseStore { requestWS({ service: 'sendbird', service_token: 1 }).then(service_token_response => { if (service_token_response.error) return; - const { server_time } = this.root_store.general_store.props; + const { server_time } = this.root_store.general_store; const { service_token } = service_token_response; this.setChatInfo({ @@ -225,7 +225,7 @@ export default class SendbirdStore extends BaseStore { // Refresh chat token ±1 hour before it expires (BE will refresh the token // when we request within 2 hours of the token expiring) const expiry_moment = epochToMoment(service_token.sendbird.expiry_time); - const delay_ms = expiry_moment.diff(server_time.get().clone().subtract(1, 'hour')); + const delay_ms = expiry_moment.diff(toMoment(server_time.get()).clone().subtract(1, 'hour')); this.service_token_timeout = setTimeout(() => getSendbirdServiceToken(), delay_ms); }); @@ -386,7 +386,7 @@ export default class SendbirdStore extends BaseStore { // Add a placeholder message with a pending indicator const placeholder_msg_options = { - created_at: this.root_store.general_store.props.server_time.get().utc(), + created_at: toMoment(this.root_store.general_store.server_time.get()).utc(), chat_channel_url: this.active_chat_channel.url, message, id: msg_identifier, diff --git a/packages/p2p/src/utils/orders.js b/packages/p2p/src/utils/orders.js index 8d1965713348..b8e03db4a10f 100644 --- a/packages/p2p/src/utils/orders.js +++ b/packages/p2p/src/utils/orders.js @@ -115,7 +115,7 @@ export default class ExtendedOrderDetails { // orders as active when they're actually expired. This boolean is used // as an extra check to ensure orders look expired on FE. get has_timer_expired() { - const server_time_moment = this.server_time.get(); + const server_time_moment = toMoment(this.server_time.get()); const expiry_time_moment = toMoment(this.order_details.expiry_time); return server_time_moment.isAfter(expiry_time_moment); } diff --git a/packages/p2p/src/utils/server-time.js b/packages/p2p/src/utils/server-time.js index b573a66fffd6..cb73b00c57ab 100644 --- a/packages/p2p/src/utils/server-time.js +++ b/packages/p2p/src/utils/server-time.js @@ -1,4 +1,5 @@ import { convertToMillis } from 'Utils/date-time'; +import { toMoment } from '@deriv/shared'; let server_time; @@ -6,7 +7,7 @@ const init = server_time_payload => { server_time = server_time_payload; }; -const get = () => (server_time ? convertToMillis(server_time.get().utc().unix()) : server_time); +const get = () => (server_time ? convertToMillis(toMoment(server_time.get()).unix()) : server_time); const getDistanceToServerTime = compare_millis_time => { const now_millis = get(); diff --git a/packages/p2p/webpack.config.js b/packages/p2p/webpack.config.js index f901d211ca7d..0648ab3b4c7e 100644 --- a/packages/p2p/webpack.config.js +++ b/packages/p2p/webpack.config.js @@ -146,6 +146,7 @@ module.exports = function (env) { { react: 'react', 'react-dom': 'react-dom', + 'react-router-dom': 'react-router-dom', 'prop-types': 'prop-types', ...(is_publishing ? {} : { 'lodash.debounce': 'lodash.debounce', formik: 'formik' }), ...publisher_utils.getLocalDerivPackageExternals(__dirname, is_publishing),