Skip to content

Commit

Permalink
[TRAH] george / TRAH-5131 / Payment Agents and Deriv P2P Options are …
Browse files Browse the repository at this point in the history
…Intermittently unavailable after login. (#17921)

* fix(client-store): fix language key handling, fix p2p and pa availability check

* refactor(cashier): reorganize imports and enhance payment agent handling

* fix(client-store): handle undefined currencies_config in available_onramp_currencies method
  • Loading branch information
heorhi-deriv authored Jan 15, 2025
1 parent e489a4f commit 19e27b4
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 75 deletions.
51 changes: 13 additions & 38 deletions packages/cashier/src/containers/cashier/__tests__/cashier.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import { BrowserHistory, createBrowserHistory } from 'history';
import { Router } from 'react-router';
import { BrowserHistory, createBrowserHistory } from 'history';

import { APIProvider } from '@deriv/api';
import { routes } from '@deriv/shared';
import { mockStore, P2PSettingsProvider } from '@deriv/stores';
import { fireEvent, render, screen } from '@testing-library/react';

import getRoutesConfig from 'Constants/routes-config';
import Cashier from '../cashier';
import { P2PSettingsProvider, mockStore } from '@deriv/stores';

import CashierProviders from '../../../cashier-providers';
import { routes } from '@deriv/shared';
import { APIProvider } from '@deriv/api';
import Cashier from '../cashier';

jest.mock('@deriv-com/ui', () => ({
...jest.requireActual('@deriv-com/ui'),
Expand All @@ -19,38 +22,6 @@ jest.mock('@deriv/p2p', () => jest.fn(() => <div>P2P</div>));
jest.mock('@deriv/hooks', () => {
return {
...jest.requireActual('@deriv/hooks'),
usePaymentAgentList: jest.fn(() => ({
data: [
{
currencies: 'USD',
email: '[email protected]',
further_information: 'Further information',
max_withdrawal: '2000',
min_withdrawal: '10',
name: 'PA',
paymentagent_loginid: 'CR9999999',
phone_numbers: [
{
phone_number: '+987654321',
},
],
summary: '',
supported_payment_methods: [
{
payment_method: 'Visa',
},
],
urls: [
{
url: 'https://test.test',
},
],
withdrawal_commission: '0',
},
],
isLoading: false,
isSuccess: true,
})),
usePaymentAgentTransferVisible: jest.fn(() => ({
data: true,
isLoading: false,
Expand Down Expand Up @@ -141,6 +112,9 @@ describe('<Cashier />', () => {
transaction_history: {
is_transactions_crypto_visible: false,
},
payment_agent: {
is_payment_agent_visible: false,
},
},
},
});
Expand Down Expand Up @@ -186,6 +160,7 @@ describe('<Cashier />', () => {
mockRootStore.client.is_logged_in = true;
mockRootStore.client.is_logging_in = false;
mockRootStore.modules.cashier.general_store.is_cashier_onboarding = true;
mockRootStore.modules.cashier.payment_agent.is_payment_agent_visible = true;

renderWithRouter(<Cashier routes={getRoutesConfig()[0].routes || []} />, mockRootStore);

Expand Down
32 changes: 14 additions & 18 deletions packages/cashier/src/containers/cashier/cashier.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import React, { useCallback, useEffect, useMemo } from 'react';
import { RouteComponentProps } from 'react-router';
import { withRouter } from 'react-router-dom';
import { Div100vhContainer, FadeWrapper, PageOverlay, VerticalTab, Loading } from '@deriv/components';

import { Div100vhContainer, FadeWrapper, Loading, PageOverlay, VerticalTab } from '@deriv/components';
import {
useAuthorize,
useOnrampVisible,
useAccountTransferVisible,
useAuthorize,
useIsP2PEnabled,
usePaymentAgentList,
usePaymentAgentTransferVisible,
useOnrampVisible,
useP2PNotificationCount,
useP2PSettings,
usePaymentAgentTransferVisible,
} from '@deriv/hooks';
import { getSelectedRoute, routes, setPerformanceValue, WS, matchRoute } from '@deriv/shared';
import { localize } from '@deriv/translations';
import { getSelectedRoute, matchRoute, routes, setPerformanceValue, WS } from '@deriv/shared';
import { observer, useStore } from '@deriv/stores';
import type { TCoreStores } from '@deriv/stores/types';
import { localize } from '@deriv/translations';
import { useDevice } from '@deriv-com/ui';

import ErrorDialog from '../../components/error-dialog';
import { TRoute } from '../../types';
import { useCashierStore } from '../../stores/useCashierStores';
import { TRoute } from '../../types';

import './cashier.scss';

type TCashierProps = RouteComponentProps & {
Expand All @@ -45,7 +47,7 @@ type TCashierOptions = {
const Cashier = observer(({ history, location, routes: routes_config }: TCashierProps) => {
const { common, ui, client } = useStore();
const { isDesktop, isMobile } = useDevice();
const { withdraw, general_store } = useCashierStore();
const { withdraw, general_store, payment_agent } = useCashierStore();
const { error } = withdraw;
const {
is_cashier_onboarding,
Expand All @@ -56,6 +58,8 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
cashier_route_tab_index: tab_index,
setActiveTab,
} = general_store;
// We should use this computed property instead of the hook, to prevent the hook's data from becoming stale after a WebSocket reconnection during the first login.
const { is_payment_agent_visible } = payment_agent;
const {
data: is_payment_agent_transfer_visible,
isLoading: is_payment_agent_transfer_checking,
Expand All @@ -65,12 +69,6 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
const { is_cashier_visible: is_visible, toggleCashier, toggleReadyToDepositModal } = ui;
const { account_settings, currency, is_account_setting_loaded, is_logged_in, is_logging_in, is_svg, is_virtual } =
client;
const {
data: paymentAgentList,
isLoading: is_payment_agent_list_loading,
isSuccess: is_payment_agent_list_success,
} = usePaymentAgentList(currency);
const is_payment_agent_visible = paymentAgentList && paymentAgentList.length > 0;
const is_account_transfer_visible = useAccountTransferVisible();
const is_onramp_visible = useOnrampVisible();
const p2p_notification_count = useP2PNotificationCount();
Expand Down Expand Up @@ -238,13 +236,11 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
]);

const is_p2p_loading = is_p2p_enabled_loading && !is_p2p_enabled_success;
const is_payment_agent_loading = is_payment_agent_list_loading && !is_payment_agent_list_success;
const is_cashier_loading =
((!is_logged_in || isMobile) && is_logging_in) ||
!is_account_setting_loaded ||
is_payment_agent_transfer_checking ||
is_p2p_loading ||
is_payment_agent_loading;
is_p2p_loading;

if (is_cashier_loading) {
return <Loading is_fullscreen />;
Expand Down
21 changes: 14 additions & 7 deletions packages/cashier/src/stores/general-store.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { action, computed, observable, reaction, makeObservable } from 'mobx';
import { action, computed, makeObservable, observable, reaction } from 'mobx';

import { isCryptocurrency, routes } from '@deriv/shared';

import Constants from 'Constants/constants';

import type { TRootStore, TWebSocket } from '../types';

import BaseStore from './base-store';
import PaymentAgentStore from './payment-agent-store';
import type { TRootStore, TWebSocket } from '../types';

export default class GeneralStore extends BaseStore {
constructor(
Expand Down Expand Up @@ -41,11 +45,14 @@ export default class GeneralStore extends BaseStore {
});

reaction(
() => [
this.root_store.client.switched,
this.root_store.client.is_logged_in,
this.root_store.client.currency,
],
() => {
return [
this.root_store.common.current_language,
this.root_store.client.switched,
this.root_store.client.is_logged_in,
this.root_store.client.currency,
];
},
() => {
this.init();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import React from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import classNames from 'classnames';

import { useRemoteConfig } from '@deriv/api';
import { Analytics } from '@deriv-com/analytics';
import { Div100vhContainer, Icon, MobileDrawer, ToggleSwitch } from '@deriv/components';
import {
useAccountTransferVisible,
useAuthorize,
useIsP2PEnabled,
useOauth2,
useOnrampVisible,
usePaymentAgentTransferVisible,
useP2PSettings,
useOauth2,
usePaymentAgentTransferVisible,
} from '@deriv/hooks';
import { getOSNameWithUAParser, getStaticUrl, routes } from '@deriv/shared';
import { observer, useStore } from '@deriv/stores';
import { localize } from '@deriv/translations';
import NetworkStatus from 'App/Components/Layout/Footer';
import ServerTime from 'App/Containers/server-time.jsx';
import getRoutesConfig from 'App/Constants/routes-config';
import { Analytics } from '@deriv-com/analytics';

import LiveChat from 'App/Components/Elements/LiveChat';
import WhatsApp from 'App/Components/Elements/WhatsApp';
import NetworkStatus from 'App/Components/Layout/Footer';
import getRoutesConfig from 'App/Constants/routes-config';
import ServerTime from 'App/Containers/server-time.jsx';

import { MenuTitle, MobileLanguageMenu } from './Components/ToggleMenu';
import MenuLink from './menu-link';
import PlatformSwitcher from './platform-switcher';
Expand Down Expand Up @@ -53,6 +55,8 @@ const ToggleMenuDrawer = observer(({ platform_config }) => {
is_proof_of_ownership_enabled,
is_eu,
is_passkey_supported,
// We should use this computed property instead of the hook, to prevent the hook's data from becoming stale after a WebSocket reconnection during the first login.
is_p2p_available,
} = client;
const { cashier } = modules;
const { payment_agent } = cashier;
Expand All @@ -62,7 +66,6 @@ const ToggleMenuDrawer = observer(({ platform_config }) => {
const { isSuccess } = useAuthorize();
const is_onramp_visible = useOnrampVisible();
const { data: is_payment_agent_transfer_visible } = usePaymentAgentTransferVisible();
const { is_p2p_enabled } = useIsP2PEnabled();

const { pathname: route } = useLocation();

Expand Down Expand Up @@ -125,7 +128,7 @@ const ToggleMenuDrawer = observer(({ platform_config }) => {
is_trading_hub_category,
is_mobile,
is_passkey_supported,
is_p2p_enabled,
is_p2p_available,
]);

const toggleDrawer = React.useCallback(() => {
Expand Down Expand Up @@ -230,7 +233,7 @@ const ToggleMenuDrawer = observer(({ platform_config }) => {
!route.is_invisible &&
(route.path !== routes.cashier_pa || is_payment_agent_visible) &&
(route.path !== routes.cashier_pa_transfer || is_payment_agent_transfer_visible) &&
(route.path !== routes.cashier_p2p || is_p2p_enabled) &&
(route.path !== routes.cashier_p2p || is_p2p_available) &&
(route.path !== routes.cashier_onramp || is_onramp_visible) &&
(route.path !== routes.cashier_acc_transfer || is_account_transfer_visible)
) {
Expand Down
20 changes: 18 additions & 2 deletions packages/core/src/Stores/client-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ export default class ClientStore extends BaseStore {
is_from_restricted_country: computed,
is_fully_authenticated: computed,
is_financial_account: computed,
is_p2p_available: computed,
landing_company_shortcode: computed,
landing_company: computed,
is_logged_in: computed,
Expand Down Expand Up @@ -630,6 +631,8 @@ export default class ClientStore extends BaseStore {
}

get available_onramp_currencies() {
if (!this.website_status?.currencies_config) return [];

return Object.entries(this.website_status?.currencies_config).reduce((currencies, [currency, values]) => {
if (values.platform.ramp.length > 0) {
currencies.push(currency);
Expand Down Expand Up @@ -694,6 +697,19 @@ export default class ClientStore extends BaseStore {
return getAccountTitle(this.loginid);
}

get is_p2p_available() {
const localstorage_p2p_settings = JSON.parse(localStorage.getItem('p2p_settings'));

const p2p_supported_currencies =
localstorage_p2p_settings?.supported_currencies || this.website_status?.p2p_config?.supported_currencies;

return (
p2p_supported_currencies?.includes(this.currency.toLocaleLowerCase()) &&
!this.is_virtual &&
!this.root_store.traders_hub.is_low_risk_cr_eu_real
);
}

get currency() {
if (this.selected_currency.length) {
return this.selected_currency;
Expand Down Expand Up @@ -1619,8 +1635,8 @@ export default class ClientStore extends BaseStore {
authorize_response.authorize.preferred_language,
this.is_new_session
);
const stored_language = LocalStore.get(LANGUAGE_KEY);
if (stored_language && language !== stored_language) {
const stored_language_without_double_quotes = LocalStore.get(LANGUAGE_KEY).replace(/"/g, '');
if (stored_language_without_double_quotes && language !== stored_language_without_double_quotes) {
window.history.replaceState({}, document.title, urlForLanguage(language));
await this.root_store.common.changeSelectedLanguage(language);
}
Expand Down
1 change: 1 addition & 0 deletions packages/stores/src/mockStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ const mock = (): TStores & { is_mock: boolean } => {
pre_switch_broadcast: false,
residence: '',
is_svg: false,
is_p2p_available: false,
responseMt5LoginList: jest.fn(),
responseTradingPlatformAccountsList: jest.fn(),
setFinancialAndTradingAssessment: jest.fn(),
Expand Down
1 change: 1 addition & 0 deletions packages/stores/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ export type TClientStore = {
trading_platform_accounts: DetailsOfEachMT5Loginid[];
}) => DetailsOfEachMT5Loginid[];
standpoint: TStandPoint;
is_p2p_available: boolean;
prevent_redirect_to_hub: boolean;
setPreventRedirectToHub: (value: boolean) => void;
setAccountStatus: (status?: GetAccountStatus) => void;
Expand Down

0 comments on commit 19e27b4

Please sign in to comment.