From 9a3da34be803a0afea4f1db143b1fc17930b9271 Mon Sep 17 00:00:00 2001 From: ameerul hady Date: Wed, 1 Mar 2023 14:50:50 +0800 Subject: [PATCH 1/7] chore: cherry picked Co-authored-by: Carol Sachdeva <58209918+carol-deriv@users.noreply.github.com> --- .../src/pages/p2p-cashier/p2p-cashier.tsx | 152 +-------- packages/p2p/@deriv-stores.d.ts | 10 + packages/p2p/package.json | 11 +- .../advertiser-page-adverts.jsx | 10 +- .../advertiser-page/advertiser-page-row.jsx | 6 +- .../advertiser-page/advertiser-page-stats.jsx | 9 +- packages/p2p/src/components/app-content.jsx | 2 +- packages/p2p/src/components/app.jsx | 139 ++++++-- .../components/buy-sell/buy-sell-modal.jsx | 2 +- .../src/components/buy-sell/buy-sell-row.jsx | 10 +- .../components/buy-sell/buy-sell-table.jsx | 12 +- .../components/buy-sell/rate-change-modal.jsx | 10 +- .../dp2p-blocked/dp2p-blocked-checklist.jsx | 3 +- .../floating-rate/floating-rate.jsx | 12 +- .../src/components/my-ads/create-ad-form.jsx | 7 +- .../components/my-ads/create-ad-summary.jsx | 10 +- .../src/components/my-ads/edit-ad-summary.jsx | 10 +- .../src/components/my-ads/my-ads-table.jsx | 15 +- .../my-profile-balance/my-profile-balance.jsx | 11 +- .../my-profile-details-table.jsx | 19 +- .../my-profile-stats-table.jsx | 18 +- .../order-details/order-details.jsx | 15 +- .../order-table/order-table-content.jsx | 8 +- .../orders/order-table/order-table-row.jsx | 14 +- packages/p2p/src/components/orders/popup.jsx | 316 +++++++++--------- .../components/verification/verification.jsx | 2 +- packages/p2p/src/declarations.d.ts | 2 + packages/p2p/src/stores/general-store.js | 63 ++-- packages/p2p/src/stores/index.js | 2 +- packages/p2p/src/stores/my-ads-store.js | 16 +- packages/p2p/src/stores/order-store.js | 12 +- packages/p2p/src/stores/sendbird-store.js | 6 +- packages/p2p/tsconfig.json | 2 +- 33 files changed, 463 insertions(+), 473 deletions(-) create mode 100644 packages/p2p/@deriv-stores.d.ts create mode 100644 packages/p2p/src/declarations.d.ts diff --git a/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx b/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx index 6cbfde472a07..8cde730a19b5 100644 --- a/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx +++ b/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx @@ -1,154 +1,16 @@ 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'; 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; - }; -}; +import { observer, useStore } from '@deriv/stores'; /* 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, - filterNotificationMessages, - refreshNotifications, - removeNotificationByKey, - removeNotificationMessage, - setP2POrderProps, - } = notifications; - const { balance, currency, local_currency_config, loginid, is_logging_in, is_virtual, residence } = 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 ; - } +const P2PCashier = observer(() => { + const { modules } = useStore(); + const { cashier } = modules; + const { general_store } = cashier; + const { setNotificationCount } = general_store; - return ( - - ); + return ; }); export default withRouter(P2PCashier); diff --git a/packages/p2p/@deriv-stores.d.ts b/packages/p2p/@deriv-stores.d.ts new file mode 100644 index 000000000000..845edd44fdb7 --- /dev/null +++ b/packages/p2p/@deriv-stores.d.ts @@ -0,0 +1,10 @@ +import type { TStores } from '@deriv/stores'; +import type RootStore from './src/stores/index'; + +declare module '@deriv/stores' { + export function useStore(): TStores & { + modules: { + p2p: RootStore; + }; + }; +} diff --git a/packages/p2p/package.json b/packages/p2p/package.json index 8ee8fcbbad50..aa8356480e30 100644 --- a/packages/p2p/package.json +++ b/packages/p2p/package.json @@ -32,10 +32,14 @@ "dependencies": { "@deriv/components": "^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": "^20.3.2", "lodash.debounce": "^4.0.8", "mobx": "^6.6.1", @@ -45,12 +49,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 +68,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/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 dc23925d59ec..6c0b39272550 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'; @@ -11,7 +11,9 @@ import './advertiser-page.scss'; const AdvertiserPageRow = ({ row: advert, showAdPopup }) => { 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 7e0c7b031559..c4c99bcf9de6 100644 --- a/packages/p2p/src/components/app-content.jsx +++ b/packages/p2p/src/components/app-content.jsx @@ -29,7 +29,7 @@ const AppContent = () => { return ; } - if (general_store.props.should_show_verification) { + if (/verification/.test(location.hash)) { return ; } diff --git a/packages/p2p/src/components/app.jsx b/packages/p2p/src/components/app.jsx index c718f88deef9..01f85e8cf502 100644 --- a/packages/p2p/src/components/app.jsx +++ b/packages/p2p/src/components/app.jsx @@ -1,8 +1,10 @@ -import classNames from 'classnames'; import * as React from 'react'; -import { observer } from 'mobx-react-lite'; +import { useHistory } from 'react-router-dom'; +import { useStore, observer } from '@deriv/stores'; +import { getLanguage } from '@deriv/translations'; import PropTypes from 'prop-types'; -import { routes } from '@deriv/shared'; +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,24 +13,27 @@ import { setLanguage } from './i18next'; import './app.scss'; const App = props => { + 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 { general_store, order_store } = useStores(); - const { - balance, - className, - history, - lang, - Notifications, - order_id, - server_time, - verification_action, - verification_code, - websocket_api, - setOnRemount, - } = props; + + const lang = getLanguage(); + + const [order_id, setOrderId] = React.useState(null); + const [action_param, setActionParam] = React.useState(); + const [code_param, setCodeParam] = React.useState(); 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. @@ -37,7 +42,7 @@ const App = props => { history.push(routes.cashier_p2p); } - ServerTime.init(server_time); + ServerTime.init(general_store.server_time); // force safari refresh on back/forward window.onpageshow = function (event) { @@ -58,6 +63,79 @@ 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]); @@ -67,7 +145,7 @@ const App = props => { general_store.redirectTo('orders'); order_store.setOrderId(order_id); } - general_store.props.setP2POrderProps({ + setP2POrderProps({ order_id, redirectToOrderDetails: general_store.redirectToOrderDetails, setIsRatingModalOpen: order_store.setIsRatingModalOpen, @@ -81,25 +159,25 @@ 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) { order_store.setIsLoadingModalOpen(true); - 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 ( -
+
@@ -111,13 +189,10 @@ App.propTypes = { 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, }; diff --git a/packages/p2p/src/components/buy-sell/buy-sell-modal.jsx b/packages/p2p/src/components/buy-sell/buy-sell-modal.jsx index 6ad831f5e84c..6964558c8cd8 100644 --- a/packages/p2p/src/components/buy-sell/buy-sell-modal.jsx +++ b/packages/p2p/src/components/buy-sell/buy-sell-modal.jsx @@ -294,7 +294,7 @@ const BuySellModal = ({ table_type, selected_ad, should_show_popup, setShouldSho width='456px' is_open={should_show_popup} title={generateModalTitle(formik_ref, my_profile_store, table_type, selected_ad)} - 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/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 2b8da108c4be..56c3a07b14fe 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'; @@ -27,7 +27,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( () => { @@ -95,10 +98,7 @@ const BuySellTable = ({ onScroll }) => { - + diff --git a/packages/p2p/src/components/buy-sell/rate-change-modal.jsx b/packages/p2p/src/components/buy-sell/rate-change-modal.jsx index 778fe8c92179..d44449555cd3 100644 --- a/packages/p2p/src/components/buy-sell/rate-change-modal.jsx +++ b/packages/p2p/src/components/buy-sell/rate-change-modal.jsx @@ -1,14 +1,18 @@ -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 './rate-change-modal.scss'; const RateChangeModal = ({ onMount }) => { - const { buy_sell_store, floating_rate_store, general_store } = useStores(); - const local_currency = general_store.client?.local_currency_config?.currency; + const { + client: { local_currency_config }, + } = useStore(); + + const { buy_sell_store, floating_rate_store } = useStores(); + const local_currency = local_currency_config?.currency; const is_mobile = isMobile(); const closeModal = () => { 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/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/my-ads/create-ad-form.jsx b/packages/p2p/src/components/my-ads/create-ad-form.jsx index de83c2069e6a..7cbec46e0476 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([]); 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 5502e2012c05..dea456bff47e 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, Modal, 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'; @@ -27,7 +27,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 ? ( @@ -38,7 +41,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 || '', }} /> @@ -52,6 +55,10 @@ const AdSwitchHintBox = () => { const MyAdsTable = () => { const { floating_rate_store, general_store, my_ads_store } = useStores(); + const { + client: { currency }, + } = useStore(); + const [selected_advert, setSelectedAdvert] = React.useState(undefined); React.useEffect(() => { @@ -113,7 +120,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 150b69fbbd37..689ecc7d13d6 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 @@ -2,13 +2,16 @@ import * as React from 'react'; import { Money, Table, Text } from '@deriv/components'; 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 } = useStores(); + const { + client: { currency }, + } = useStore(); const { daily_buy_limit, daily_sell_limit } = general_store.advertiser_info; - const { advertiser_buy_limit, advertiser_sell_limit, client } = general_store; + const { advertiser_buy_limit, advertiser_sell_limit } = general_store; return (
@@ -24,7 +27,7 @@ const MyProfileDetailsTable = () => { - + @@ -32,7 +35,7 @@ const MyProfileDetailsTable = () => { - + @@ -49,7 +52,7 @@ const MyProfileDetailsTable = () => { - + @@ -57,11 +60,7 @@ const MyProfileDetailsTable = () => { - + 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 1f0f729f825f..6862edeedbd2 100644 --- a/packages/p2p/src/components/order-details/order-details.jsx +++ b/packages/p2p/src/components/order-details/order-details.jsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import React from 'react'; 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 EmailVerificationModal from 'Components/email-verification-modal'; @@ -28,6 +28,9 @@ import './order-details.scss'; const OrderDetails = observer(() => { const { general_store, my_profile_store, order_store, sendbird_store } = useStores(); + const { + notifications: { removeNotificationByKey, removeNotificationMessage, setP2POrderProps }, + } = useStore(); const { account_currency, @@ -94,7 +97,7 @@ 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: order_store.setIsRatingModalOpen, @@ -129,8 +132,8 @@ const OrderDetails = observer(() => { onClickClearRecommendation={() => order_store.setIsRecommended(null)} onClickDone={() => { order_store.setOrderRating(id); - general_store.props.removeNotificationMessage({ key: `order-${id}` }); - general_store.props.removeNotificationByKey({ key: `order-${id}` }); + removeNotificationMessage({ key: `order-${id}` }); + removeNotificationByKey({ key: `order-${id}` }); }} onClickNotRecommended={() => order_store.setIsRecommended(0)} onClickRecommended={() => order_store.setIsRecommended(1)} @@ -326,8 +329,8 @@ const OrderDetails = observer(() => { onClickClearRecommendation={() => order_store.setIsRecommended(null)} onClickDone={() => { order_store.setOrderRating(id); - general_store.props.removeNotificationMessage({ key: `order-${id}` }); - general_store.props.removeNotificationByKey({ key: `order-${id}` }); + removeNotificationMessage({ key: `order-${id}` }); + removeNotificationByKey({ key: `order-${id}` }); }} onClickNotRecommended={() => order_store.setIsRecommended(0)} onClickRecommended={() => order_store.setIsRecommended(1)} 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 8a0a57784baf..e7f63fec10c5 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,5 +1,5 @@ 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 { secondsToTimer } from 'Utils/date-time'; @@ -34,6 +34,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); @@ -86,9 +91,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 { @@ -113,8 +117,8 @@ const OrderRow = ({ row: order }) => { setShouldShowRatingModal(false); 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 }); 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/declarations.d.ts b/packages/p2p/src/declarations.d.ts new file mode 100644 index 000000000000..2b3ddb5cf7c9 --- /dev/null +++ b/packages/p2p/src/declarations.d.ts @@ -0,0 +1,2 @@ +declare module '@deriv/p2p'; +declare module '@deriv/cashier'; diff --git a/packages/p2p/src/stores/general-store.js b/packages/p2p/src/stores/general-store.js index f6e161fc46af..43dac2232df1 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'; @@ -22,6 +23,7 @@ export default class GeneralStore extends BaseStore { balance; cancels_remaining = null; contact_info = ''; + external_stores = {}; feature_level = null; inactive_notification_count = 0; is_advertiser = false; @@ -60,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); @@ -73,6 +81,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, inactive_notification_count: observable, is_advertiser: observable, @@ -99,9 +108,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, - setCurrentFocus: computed, blocked_until_date_time: computed, is_active_tab: computed, is_barred: computed, @@ -126,7 +132,7 @@ export default class GeneralStore extends BaseStore { 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, setInactiveNotificationCount: action.bound, setIsAdvertiser: action.bound, @@ -161,18 +167,6 @@ export default class GeneralStore extends BaseStore { }); } - get client() { - return { ...this.props?.client } || {}; - } - - get current_focus() { - return this.props?.current_focus; - } - - get setCurrentFocus() { - return this.props?.setCurrentFocus; - } - get blocked_until_date_time() { return getFormattedDateString(new Date(convertToMillis(this.user_blocked_until)), false, true); } @@ -260,7 +254,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: [] }; @@ -285,11 +279,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; @@ -312,14 +309,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 { @@ -361,9 +358,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) { @@ -401,7 +398,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 @@ -476,11 +473,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] ), @@ -501,13 +498,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, @@ -531,8 +528,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() { @@ -608,6 +605,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; } @@ -851,7 +852,7 @@ 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)); 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 8e88dc497788..8af73b224314 100644 --- a/packages/p2p/src/stores/my-ads-store.js +++ b/packages/p2p/src/stores/my-ads-store.js @@ -642,7 +642,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), ], @@ -652,7 +652,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), ], @@ -663,7 +663,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), ], @@ -674,7 +674,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 @@ -800,7 +801,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), ], @@ -810,7 +811,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), ], @@ -821,7 +822,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/order-store.js b/packages/p2p/src/stores/order-store.js index c3c12e606272..32532731f35f 100644 --- a/packages/p2p/src/stores/order-store.js +++ b/packages/p2p/src/stores/order-store.js @@ -363,8 +363,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) { @@ -424,8 +424,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); @@ -455,8 +455,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 }); } } diff --git a/packages/p2p/src/stores/sendbird-store.js b/packages/p2p/src/stores/sendbird-store.js index d5e7f80a25b7..f032e3f0c27d 100644 --- a/packages/p2p/src/stores/sendbird-store.js +++ b/packages/p2p/src/stores/sendbird-store.js @@ -187,7 +187,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 || this.root_store.general_store.server_time.get().utc().valueOf(), is_inclusive_of_timestamp, result_size, reverse_results, @@ -212,7 +212,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({ @@ -385,7 +385,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: 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/tsconfig.json b/packages/p2p/tsconfig.json index 58be2aafccbe..a84acff353de 100644 --- a/packages/p2p/tsconfig.json +++ b/packages/p2p/tsconfig.json @@ -13,5 +13,5 @@ }, "outDir": "./lib" }, - "include": ["src", "../../utils.d.ts"] + "include": ["src", "../../utils.d.ts", "@deriv-stores.d.ts"] } From 634e42c03da8e10a46941f31c1d05245291b803d Mon Sep 17 00:00:00 2001 From: ameerul hady Date: Wed, 8 Mar 2023 15:45:32 +0800 Subject: [PATCH 2/7] chore: fixed issues with server time --- packages/p2p/src/stores/sendbird-store.js | 8 ++++---- packages/p2p/src/utils/orders.js | 2 +- packages/p2p/src/utils/server-time.js | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/p2p/src/stores/sendbird-store.js b/packages/p2p/src/stores/sendbird-store.js index f032e3f0c27d..b853eb242db9 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'; @@ -187,7 +187,7 @@ export default class SendbirdStore extends BaseStore { const custom_type = ''; this.active_chat_channel.getPreviousMessagesByTimestamp( - timestamp || this.root_store.general_store.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, @@ -224,7 +224,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); }); @@ -385,7 +385,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.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(); From 9c1424199ee3de6ee413589c9ee241dece4ffa27 Mon Sep 17 00:00:00 2001 From: ameerul hady Date: Wed, 8 Mar 2023 17:17:10 +0800 Subject: [PATCH 3/7] chore: replaced notifications with new hook and removed props from app --- .../src/pages/p2p-cashier/p2p-cashier.tsx | 9 ++------- packages/p2p/src/components/app-content.jsx | 14 ++++++++++---- packages/p2p/src/components/app.jsx | 16 +--------------- packages/p2p/src/stores/general-store.js | 19 ------------------- packages/p2p/src/stores/order-store.js | 6 ------ 5 files changed, 13 insertions(+), 51 deletions(-) diff --git a/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx b/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx index 8cde730a19b5..1388f8164d8d 100644 --- a/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx +++ b/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx @@ -1,16 +1,11 @@ import React from 'react'; import { withRouter } from 'react-router-dom'; import P2P from '@deriv/p2p'; -import { observer, useStore } from '@deriv/stores'; +import { observer } from '@deriv/stores'; /* P2P will use the same websocket connection as Deriv/Binary, we need to pass it as a prop */ const P2PCashier = observer(() => { - const { modules } = useStore(); - const { cashier } = modules; - const { general_store } = cashier; - const { setNotificationCount } = general_store; - - return ; + return ; }); export default withRouter(P2PCashier); diff --git a/packages/p2p/src/components/app-content.jsx b/packages/p2p/src/components/app-content.jsx index a2e288bffdaf..d5e3146a12fd 100644 --- a/packages/p2p/src/components/app-content.jsx +++ b/packages/p2p/src/components/app-content.jsx @@ -1,6 +1,8 @@ import * as React from 'react'; import { isMobile } from '@deriv/shared'; import { Loading, Tabs } from '@deriv/components'; +import { useP2PNotificationCount } from '@deriv/hooks'; +import { useStore } from '@deriv/stores'; import { isAction, reaction } from 'mobx'; import { observer } from 'mobx-react-lite'; import { useStores } from 'Stores'; @@ -19,13 +21,17 @@ import { useModalManagerContext } from 'Components/modal-manager/modal-manager-c const AppContent = ({ order_id }) => { const { buy_sell_store, general_store } = useStores(); const { showModal, hideModal } = useModalManagerContext(); + const notification_count = useP2PNotificationCount(); + 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 => { @@ -76,7 +82,7 @@ const AppContent = ({ order_id }) => {
-
+
diff --git a/packages/p2p/src/components/app.jsx b/packages/p2p/src/components/app.jsx index c5baec05cea0..0073dbfb9555 100644 --- a/packages/p2p/src/components/app.jsx +++ b/packages/p2p/src/components/app.jsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { useHistory } from 'react-router-dom'; import { useStore, observer } from '@deriv/stores'; import { getLanguage } from '@deriv/translations'; -import PropTypes from 'prop-types'; import { Loading } from '@deriv/components'; import { routes, WS } from '@deriv/shared'; import ServerTime from 'Utils/server-time'; @@ -13,7 +12,7 @@ import { setLanguage } from './i18next'; import { ModalManager, ModalManagerContextProvider } from './modal-manager'; import './app.scss'; -const App = props => { +const App = () => { const { notifications, client, ui, common, modules } = useStore(); const { balance, is_logging_in } = client; const { setOnRemount } = modules?.cashier?.general_store; @@ -32,7 +31,6 @@ const App = props => { const [code_param, setCodeParam] = React.useState(); React.useEffect(() => { - general_store.setAppProps(props); general_store.setExternalStores({ client, common, modules, notifications, ui }); general_store.setWebsocketInit(WS); general_store.getWebsiteStatus(); @@ -188,16 +186,4 @@ const App = props => { ); }; -App.propTypes = { - balance: PropTypes.string, - className: PropTypes.string, - history: PropTypes.object, - lang: PropTypes.string, - order_id: PropTypes.string, - server_time: PropTypes.object, - setNotificationCount: PropTypes.func, - setOnRemount: PropTypes.func, - websocket_api: PropTypes.object.isRequired, -}; - export default observer(App); diff --git a/packages/p2p/src/stores/general-store.js b/packages/p2p/src/stores/general-store.js index 8ad345b2188d..5251ce91a27f 100644 --- a/packages/p2p/src/stores/general-store.js +++ b/packages/p2p/src/stores/general-store.js @@ -40,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; @@ -98,12 +96,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, @@ -136,7 +132,6 @@ export default class GeneralStore extends BaseStore { setAdvertiserId: action.bound, setAdvertiserBuyLimit: action.bound, setAdvertiserSellLimit: action.bound, - setAppProps: action.bound, setExternalStores: action.bound, setFeatureLevel: action.bound, setFormikRef: action.bound, @@ -153,7 +148,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, @@ -606,10 +600,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; @@ -699,10 +689,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); @@ -887,13 +873,8 @@ export default class GeneralStore extends BaseStore { 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/order-store.js b/packages/p2p/src/stores/order-store.js index 361dede142c1..7f4f2795bf02 100644 --- a/packages/p2p/src/stores/order-store.js +++ b/packages/p2p/src/stores/order-store.js @@ -557,12 +557,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) { From b118b4308deccdbba903fb83ee9278acb184fa36 Mon Sep 17 00:00:00 2001 From: ameerul hady Date: Mon, 20 Mar 2023 17:14:36 +0800 Subject: [PATCH 4/7] chore: fixed history routing issue --- packages/p2p/webpack.config.js | 1 + 1 file changed, 1 insertion(+) 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), From f8186cfb27fae0a168e6c24eaa1dd14cc2aca985 Mon Sep 17 00:00:00 2001 From: ameerul hady Date: Thu, 23 Mar 2023 12:33:26 +0800 Subject: [PATCH 5/7] chore: removed p2p-cashier --- .../cashier/src/constants/routes-config.ts | 7 +- packages/cashier/src/pages/index.js | 3 +- .../__tests__/p2p-cashier.spec.tsx | 167 ------------------ .../cashier/src/pages/p2p-cashier/index.ts | 3 - .../src/pages/p2p-cashier/p2p-cashier.tsx | 11 -- 5 files changed, 5 insertions(+), 186 deletions(-) delete mode 100644 packages/cashier/src/pages/p2p-cashier/__tests__/p2p-cashier.spec.tsx delete mode 100644 packages/cashier/src/pages/p2p-cashier/index.ts delete mode 100644 packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx diff --git a/packages/cashier/src/constants/routes-config.ts b/packages/cashier/src/constants/routes-config.ts index d9f612a09571..ce7ab206efb8 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 1388f8164d8d..000000000000 --- a/packages/cashier/src/pages/p2p-cashier/p2p-cashier.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { withRouter } from 'react-router-dom'; -import P2P from '@deriv/p2p'; -import { observer } from '@deriv/stores'; - -/* P2P will use the same websocket connection as Deriv/Binary, we need to pass it as a prop */ -const P2PCashier = observer(() => { - return ; -}); - -export default withRouter(P2PCashier); From 0d30162a79a316cce789f4e14704c15c883772e7 Mon Sep 17 00:00:00 2001 From: ameerul hady Date: Thu, 23 Mar 2023 14:53:03 +0800 Subject: [PATCH 6/7] chore: fixed tests, added TODOs --- .../components/__tests__/app-content.spec.js | 35 +++++++++++-------- packages/p2p/src/components/app-content.jsx | 6 +--- packages/p2p/src/components/app.jsx | 2 ++ .../__test__/floating-rate.spec.js | 18 +++++++--- 4 files changed, 37 insertions(+), 24 deletions(-) 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/app-content.jsx b/packages/p2p/src/components/app-content.jsx index d5e3146a12fd..c9af5b1720ee 100644 --- a/packages/p2p/src/components/app-content.jsx +++ b/packages/p2p/src/components/app-content.jsx @@ -15,7 +15,6 @@ 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 }) => { @@ -45,6 +44,7 @@ const AppContent = ({ order_id }) => { } } ); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); if (general_store.is_loading) { @@ -59,10 +59,6 @@ const AppContent = ({ order_id }) => { return ; } - if (/verification/.test(location.hash)) { - 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 d917ebbf5cc1..f5a1ebe4ef56 100644 --- a/packages/p2p/src/components/app.jsx +++ b/packages/p2p/src/components/app.jsx @@ -12,6 +12,7 @@ import { setLanguage } from './i18next'; import { ModalManager, ModalManagerContextProvider } from './modal-manager'; import './app.scss'; +// 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; @@ -188,6 +189,7 @@ const App = () => { } return ( + // TODO Wrap components with StoreProvider during routing p2p card
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(); }); From c40edc703f24a1aa393c0c442bef49351f1cffae Mon Sep 17 00:00:00 2001 From: ameerul hady Date: Fri, 24 Mar 2023 09:40:55 +0800 Subject: [PATCH 7/7] chore: removed d.ts files --- packages/p2p/@deriv-stores.d.ts | 10 ---------- packages/p2p/src/declarations.d.ts | 2 -- packages/p2p/tsconfig.json | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 packages/p2p/@deriv-stores.d.ts delete mode 100644 packages/p2p/src/declarations.d.ts diff --git a/packages/p2p/@deriv-stores.d.ts b/packages/p2p/@deriv-stores.d.ts deleted file mode 100644 index 845edd44fdb7..000000000000 --- a/packages/p2p/@deriv-stores.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { TStores } from '@deriv/stores'; -import type RootStore from './src/stores/index'; - -declare module '@deriv/stores' { - export function useStore(): TStores & { - modules: { - p2p: RootStore; - }; - }; -} diff --git a/packages/p2p/src/declarations.d.ts b/packages/p2p/src/declarations.d.ts deleted file mode 100644 index 2b3ddb5cf7c9..000000000000 --- a/packages/p2p/src/declarations.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare module '@deriv/p2p'; -declare module '@deriv/cashier'; diff --git a/packages/p2p/tsconfig.json b/packages/p2p/tsconfig.json index e3c60c42100a..0aa196730570 100644 --- a/packages/p2p/tsconfig.json +++ b/packages/p2p/tsconfig.json @@ -13,5 +13,5 @@ }, "outDir": "./lib" }, - "include": ["src", "../../global.d.ts", "../../utils.d.ts", "@deriv-stores.d.ts"] + "include": ["src", "../../global.d.ts", "../../utils.d.ts"] }