Skip to content

Commit 19e27b4

Browse files
authored
[TRAH] george / TRAH-5131 / Payment Agents and Deriv P2P Options are 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
1 parent e489a4f commit 19e27b4

File tree

7 files changed

+74
-75
lines changed

7 files changed

+74
-75
lines changed

packages/cashier/src/containers/cashier/__tests__/cashier.spec.tsx

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import React from 'react';
2-
import { fireEvent, render, screen } from '@testing-library/react';
3-
import { BrowserHistory, createBrowserHistory } from 'history';
42
import { Router } from 'react-router';
3+
import { BrowserHistory, createBrowserHistory } from 'history';
4+
5+
import { APIProvider } from '@deriv/api';
6+
import { routes } from '@deriv/shared';
7+
import { mockStore, P2PSettingsProvider } from '@deriv/stores';
8+
import { fireEvent, render, screen } from '@testing-library/react';
9+
510
import getRoutesConfig from 'Constants/routes-config';
6-
import Cashier from '../cashier';
7-
import { P2PSettingsProvider, mockStore } from '@deriv/stores';
11+
812
import CashierProviders from '../../../cashier-providers';
9-
import { routes } from '@deriv/shared';
10-
import { APIProvider } from '@deriv/api';
13+
import Cashier from '../cashier';
1114

1215
jest.mock('@deriv-com/ui', () => ({
1316
...jest.requireActual('@deriv-com/ui'),
@@ -19,38 +22,6 @@ jest.mock('@deriv/p2p', () => jest.fn(() => <div>P2P</div>));
1922
jest.mock('@deriv/hooks', () => {
2023
return {
2124
...jest.requireActual('@deriv/hooks'),
22-
usePaymentAgentList: jest.fn(() => ({
23-
data: [
24-
{
25-
currencies: 'USD',
26-
27-
further_information: 'Further information',
28-
max_withdrawal: '2000',
29-
min_withdrawal: '10',
30-
name: 'PA',
31-
paymentagent_loginid: 'CR9999999',
32-
phone_numbers: [
33-
{
34-
phone_number: '+987654321',
35-
},
36-
],
37-
summary: '',
38-
supported_payment_methods: [
39-
{
40-
payment_method: 'Visa',
41-
},
42-
],
43-
urls: [
44-
{
45-
url: 'https://test.test',
46-
},
47-
],
48-
withdrawal_commission: '0',
49-
},
50-
],
51-
isLoading: false,
52-
isSuccess: true,
53-
})),
5425
usePaymentAgentTransferVisible: jest.fn(() => ({
5526
data: true,
5627
isLoading: false,
@@ -141,6 +112,9 @@ describe('<Cashier />', () => {
141112
transaction_history: {
142113
is_transactions_crypto_visible: false,
143114
},
115+
payment_agent: {
116+
is_payment_agent_visible: false,
117+
},
144118
},
145119
},
146120
});
@@ -186,6 +160,7 @@ describe('<Cashier />', () => {
186160
mockRootStore.client.is_logged_in = true;
187161
mockRootStore.client.is_logging_in = false;
188162
mockRootStore.modules.cashier.general_store.is_cashier_onboarding = true;
163+
mockRootStore.modules.cashier.payment_agent.is_payment_agent_visible = true;
189164

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

packages/cashier/src/containers/cashier/cashier.tsx

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
import React, { useCallback, useEffect, useMemo } from 'react';
22
import { RouteComponentProps } from 'react-router';
33
import { withRouter } from 'react-router-dom';
4-
import { Div100vhContainer, FadeWrapper, PageOverlay, VerticalTab, Loading } from '@deriv/components';
4+
5+
import { Div100vhContainer, FadeWrapper, Loading, PageOverlay, VerticalTab } from '@deriv/components';
56
import {
6-
useAuthorize,
7-
useOnrampVisible,
87
useAccountTransferVisible,
8+
useAuthorize,
99
useIsP2PEnabled,
10-
usePaymentAgentList,
11-
usePaymentAgentTransferVisible,
10+
useOnrampVisible,
1211
useP2PNotificationCount,
1312
useP2PSettings,
13+
usePaymentAgentTransferVisible,
1414
} from '@deriv/hooks';
15-
import { getSelectedRoute, routes, setPerformanceValue, WS, matchRoute } from '@deriv/shared';
16-
import { localize } from '@deriv/translations';
15+
import { getSelectedRoute, matchRoute, routes, setPerformanceValue, WS } from '@deriv/shared';
1716
import { observer, useStore } from '@deriv/stores';
1817
import type { TCoreStores } from '@deriv/stores/types';
18+
import { localize } from '@deriv/translations';
1919
import { useDevice } from '@deriv-com/ui';
20+
2021
import ErrorDialog from '../../components/error-dialog';
21-
import { TRoute } from '../../types';
2222
import { useCashierStore } from '../../stores/useCashierStores';
23+
import { TRoute } from '../../types';
24+
2325
import './cashier.scss';
2426

2527
type TCashierProps = RouteComponentProps & {
@@ -45,7 +47,7 @@ type TCashierOptions = {
4547
const Cashier = observer(({ history, location, routes: routes_config }: TCashierProps) => {
4648
const { common, ui, client } = useStore();
4749
const { isDesktop, isMobile } = useDevice();
48-
const { withdraw, general_store } = useCashierStore();
50+
const { withdraw, general_store, payment_agent } = useCashierStore();
4951
const { error } = withdraw;
5052
const {
5153
is_cashier_onboarding,
@@ -56,6 +58,8 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
5658
cashier_route_tab_index: tab_index,
5759
setActiveTab,
5860
} = general_store;
61+
// 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.
62+
const { is_payment_agent_visible } = payment_agent;
5963
const {
6064
data: is_payment_agent_transfer_visible,
6165
isLoading: is_payment_agent_transfer_checking,
@@ -65,12 +69,6 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
6569
const { is_cashier_visible: is_visible, toggleCashier, toggleReadyToDepositModal } = ui;
6670
const { account_settings, currency, is_account_setting_loaded, is_logged_in, is_logging_in, is_svg, is_virtual } =
6771
client;
68-
const {
69-
data: paymentAgentList,
70-
isLoading: is_payment_agent_list_loading,
71-
isSuccess: is_payment_agent_list_success,
72-
} = usePaymentAgentList(currency);
73-
const is_payment_agent_visible = paymentAgentList && paymentAgentList.length > 0;
7472
const is_account_transfer_visible = useAccountTransferVisible();
7573
const is_onramp_visible = useOnrampVisible();
7674
const p2p_notification_count = useP2PNotificationCount();
@@ -238,13 +236,11 @@ const Cashier = observer(({ history, location, routes: routes_config }: TCashier
238236
]);
239237

240238
const is_p2p_loading = is_p2p_enabled_loading && !is_p2p_enabled_success;
241-
const is_payment_agent_loading = is_payment_agent_list_loading && !is_payment_agent_list_success;
242239
const is_cashier_loading =
243240
((!is_logged_in || isMobile) && is_logging_in) ||
244241
!is_account_setting_loaded ||
245242
is_payment_agent_transfer_checking ||
246-
is_p2p_loading ||
247-
is_payment_agent_loading;
243+
is_p2p_loading;
248244

249245
if (is_cashier_loading) {
250246
return <Loading is_fullscreen />;

packages/cashier/src/stores/general-store.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import { action, computed, observable, reaction, makeObservable } from 'mobx';
1+
import { action, computed, makeObservable, observable, reaction } from 'mobx';
2+
23
import { isCryptocurrency, routes } from '@deriv/shared';
4+
35
import Constants from 'Constants/constants';
6+
7+
import type { TRootStore, TWebSocket } from '../types';
8+
49
import BaseStore from './base-store';
510
import PaymentAgentStore from './payment-agent-store';
6-
import type { TRootStore, TWebSocket } from '../types';
711

812
export default class GeneralStore extends BaseStore {
913
constructor(
@@ -41,11 +45,14 @@ export default class GeneralStore extends BaseStore {
4145
});
4246

4347
reaction(
44-
() => [
45-
this.root_store.client.switched,
46-
this.root_store.client.is_logged_in,
47-
this.root_store.client.currency,
48-
],
48+
() => {
49+
return [
50+
this.root_store.common.current_language,
51+
this.root_store.client.switched,
52+
this.root_store.client.is_logged_in,
53+
this.root_store.client.currency,
54+
];
55+
},
4956
() => {
5057
this.init();
5158
}

packages/core/src/App/Components/Layout/Header/toggle-menu-drawer.jsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
import React from 'react';
22
import { useHistory, useLocation } from 'react-router-dom';
33
import classNames from 'classnames';
4+
45
import { useRemoteConfig } from '@deriv/api';
5-
import { Analytics } from '@deriv-com/analytics';
66
import { Div100vhContainer, Icon, MobileDrawer, ToggleSwitch } from '@deriv/components';
77
import {
88
useAccountTransferVisible,
99
useAuthorize,
10-
useIsP2PEnabled,
10+
useOauth2,
1111
useOnrampVisible,
12-
usePaymentAgentTransferVisible,
1312
useP2PSettings,
14-
useOauth2,
13+
usePaymentAgentTransferVisible,
1514
} from '@deriv/hooks';
1615
import { getOSNameWithUAParser, getStaticUrl, routes } from '@deriv/shared';
1716
import { observer, useStore } from '@deriv/stores';
1817
import { localize } from '@deriv/translations';
19-
import NetworkStatus from 'App/Components/Layout/Footer';
20-
import ServerTime from 'App/Containers/server-time.jsx';
21-
import getRoutesConfig from 'App/Constants/routes-config';
18+
import { Analytics } from '@deriv-com/analytics';
19+
2220
import LiveChat from 'App/Components/Elements/LiveChat';
2321
import WhatsApp from 'App/Components/Elements/WhatsApp';
22+
import NetworkStatus from 'App/Components/Layout/Footer';
23+
import getRoutesConfig from 'App/Constants/routes-config';
24+
import ServerTime from 'App/Containers/server-time.jsx';
25+
2426
import { MenuTitle, MobileLanguageMenu } from './Components/ToggleMenu';
2527
import MenuLink from './menu-link';
2628
import PlatformSwitcher from './platform-switcher';
@@ -53,6 +55,8 @@ const ToggleMenuDrawer = observer(({ platform_config }) => {
5355
is_proof_of_ownership_enabled,
5456
is_eu,
5557
is_passkey_supported,
58+
// 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.
59+
is_p2p_available,
5660
} = client;
5761
const { cashier } = modules;
5862
const { payment_agent } = cashier;
@@ -62,7 +66,6 @@ const ToggleMenuDrawer = observer(({ platform_config }) => {
6266
const { isSuccess } = useAuthorize();
6367
const is_onramp_visible = useOnrampVisible();
6468
const { data: is_payment_agent_transfer_visible } = usePaymentAgentTransferVisible();
65-
const { is_p2p_enabled } = useIsP2PEnabled();
6669

6770
const { pathname: route } = useLocation();
6871

@@ -125,7 +128,7 @@ const ToggleMenuDrawer = observer(({ platform_config }) => {
125128
is_trading_hub_category,
126129
is_mobile,
127130
is_passkey_supported,
128-
is_p2p_enabled,
131+
is_p2p_available,
129132
]);
130133

131134
const toggleDrawer = React.useCallback(() => {
@@ -230,7 +233,7 @@ const ToggleMenuDrawer = observer(({ platform_config }) => {
230233
!route.is_invisible &&
231234
(route.path !== routes.cashier_pa || is_payment_agent_visible) &&
232235
(route.path !== routes.cashier_pa_transfer || is_payment_agent_transfer_visible) &&
233-
(route.path !== routes.cashier_p2p || is_p2p_enabled) &&
236+
(route.path !== routes.cashier_p2p || is_p2p_available) &&
234237
(route.path !== routes.cashier_onramp || is_onramp_visible) &&
235238
(route.path !== routes.cashier_acc_transfer || is_account_transfer_visible)
236239
) {

packages/core/src/Stores/client-store.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ export default class ClientStore extends BaseStore {
300300
is_from_restricted_country: computed,
301301
is_fully_authenticated: computed,
302302
is_financial_account: computed,
303+
is_p2p_available: computed,
303304
landing_company_shortcode: computed,
304305
landing_company: computed,
305306
is_logged_in: computed,
@@ -630,6 +631,8 @@ export default class ClientStore extends BaseStore {
630631
}
631632

632633
get available_onramp_currencies() {
634+
if (!this.website_status?.currencies_config) return [];
635+
633636
return Object.entries(this.website_status?.currencies_config).reduce((currencies, [currency, values]) => {
634637
if (values.platform.ramp.length > 0) {
635638
currencies.push(currency);
@@ -694,6 +697,19 @@ export default class ClientStore extends BaseStore {
694697
return getAccountTitle(this.loginid);
695698
}
696699

700+
get is_p2p_available() {
701+
const localstorage_p2p_settings = JSON.parse(localStorage.getItem('p2p_settings'));
702+
703+
const p2p_supported_currencies =
704+
localstorage_p2p_settings?.supported_currencies || this.website_status?.p2p_config?.supported_currencies;
705+
706+
return (
707+
p2p_supported_currencies?.includes(this.currency.toLocaleLowerCase()) &&
708+
!this.is_virtual &&
709+
!this.root_store.traders_hub.is_low_risk_cr_eu_real
710+
);
711+
}
712+
697713
get currency() {
698714
if (this.selected_currency.length) {
699715
return this.selected_currency;
@@ -1619,8 +1635,8 @@ export default class ClientStore extends BaseStore {
16191635
authorize_response.authorize.preferred_language,
16201636
this.is_new_session
16211637
);
1622-
const stored_language = LocalStore.get(LANGUAGE_KEY);
1623-
if (stored_language && language !== stored_language) {
1638+
const stored_language_without_double_quotes = LocalStore.get(LANGUAGE_KEY).replace(/"/g, '');
1639+
if (stored_language_without_double_quotes && language !== stored_language_without_double_quotes) {
16241640
window.history.replaceState({}, document.title, urlForLanguage(language));
16251641
await this.root_store.common.changeSelectedLanguage(language);
16261642
}

packages/stores/src/mockStore.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ const mock = (): TStores & { is_mock: boolean } => {
177177
pre_switch_broadcast: false,
178178
residence: '',
179179
is_svg: false,
180+
is_p2p_available: false,
180181
responseMt5LoginList: jest.fn(),
181182
responseTradingPlatformAccountsList: jest.fn(),
182183
setFinancialAndTradingAssessment: jest.fn(),

packages/stores/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ export type TClientStore = {
540540
trading_platform_accounts: DetailsOfEachMT5Loginid[];
541541
}) => DetailsOfEachMT5Loginid[];
542542
standpoint: TStandPoint;
543+
is_p2p_available: boolean;
543544
prevent_redirect_to_hub: boolean;
544545
setPreventRedirectToHub: (value: boolean) => void;
545546
setAccountStatus: (status?: GetAccountStatus) => void;

0 commit comments

Comments
 (0)