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"] }