From 2d10240eff69e8fb41bfd94cf3b6c593844198e2 Mon Sep 17 00:00:00 2001
From: henry-deriv <118344354+henry-deriv@users.noreply.github.com>
Date: Tue, 26 Sep 2023 16:39:29 +0800
Subject: [PATCH 1/5] henry/92673/fix: implement redirect action for add and
manage account (#8143)
* fix: implement redirect action for add and manage account
* chore: refactor
---
.../src/App/Containers/Redirect/redirect.jsx | 28 +++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/packages/core/src/App/Containers/Redirect/redirect.jsx b/packages/core/src/App/Containers/Redirect/redirect.jsx
index 530bf682a9e6..1cb2d9c80f07 100644
--- a/packages/core/src/App/Containers/Redirect/redirect.jsx
+++ b/packages/core/src/App/Containers/Redirect/redirect.jsx
@@ -10,7 +10,6 @@ const Redirect = ({
currency,
setVerificationCode,
verification_code,
- hasAnyRealAccount,
openRealAccountSignup,
setResetTradingPasswordModalOpen,
toggleAccountSignupModal,
@@ -24,7 +23,12 @@ const Redirect = ({
let redirected_to_route = false;
const action_param = url_params.get('action');
const code_param = url_params.get('code') || verification_code[action_param];
+ const ext_platform_url = url_params.get('ext_platform_url');
+ const redirectToExternalPlatform = url => {
+ history.push(`${routes.root}?ext_platform_url=${url}`);
+ redirected_to_route = true;
+ };
setVerificationCode(code_param, action_param);
setNewEmail(url_params.get('email'), action_param);
@@ -119,14 +123,9 @@ const Redirect = ({
case 'add_account': {
WS.wait('get_account_status').then(() => {
if (!currency) return openRealAccountSignup('set_currency');
- if (hasAnyRealAccount()) return openRealAccountSignup('manage');
return openRealAccountSignup('svg');
});
- const ext_platform_url = url_params.get('ext_platform_url');
- if (ext_platform_url) {
- history.push(`${routes.root}?ext_platform_url=${ext_platform_url}`);
- redirected_to_route = true;
- }
+ if (ext_platform_url) redirectToExternalPlatform(ext_platform_url);
break;
}
case 'add_account_multiplier': {
@@ -134,11 +133,14 @@ const Redirect = ({
if (!currency) return openRealAccountSignup('set_currency');
return openRealAccountSignup('maltainvest');
});
- const ext_platform_url = url_params.get('ext_platform_url');
- if (ext_platform_url) {
- history.push(`${routes.root}?ext_platform_url=${ext_platform_url}`);
- redirected_to_route = true;
- }
+ if (ext_platform_url) redirectToExternalPlatform(ext_platform_url);
+ break;
+ }
+ case 'manage_account': {
+ WS.wait('get_account_status').then(() => {
+ return openRealAccountSignup('manage');
+ });
+ if (ext_platform_url) redirectToExternalPlatform(ext_platform_url);
break;
}
case 'verification': {
@@ -184,7 +186,6 @@ Redirect.propTypes = {
currency: PropTypes.string,
loginid: PropTypes.string,
getServerTime: PropTypes.object,
- hasAnyRealAccount: PropTypes.bool,
history: PropTypes.object,
openRealAccountSignup: PropTypes.func,
setResetTradingPasswordModalOpen: PropTypes.func,
@@ -204,7 +205,6 @@ export default withRouter(
setVerificationCode: client.setVerificationCode,
verification_code: client.verification_code,
fetchResidenceList: client.fetchResidenceList,
- hasAnyRealAccount: client.hasAnyRealAccount,
openRealAccountSignup: ui.openRealAccountSignup,
setResetTradingPasswordModalOpen: ui.setResetTradingPasswordModalOpen,
toggleAccountSignupModal: ui.toggleAccountSignupModal,
From 013f6d4905f7e203635b04f6437edff60cf893f8 Mon Sep 17 00:00:00 2001
From: kate-deriv <121025168+kate-deriv@users.noreply.github.com>
Date: Tue, 26 Sep 2023 11:59:50 +0300
Subject: [PATCH 2/5] Kate / Test coverage + TS migration: ContractError +
SellButton + SellInfo in Trader package (#8805)
* refactor: ts migration and tests for sell folder
* refactor: migrate to ts and add tests for contract error component
* chore: update test description
* chore: change extention
* refactor: remove unused components
---
.../Contract/Components/InfoBox/info-box.jsx | 2 +-
.../Contract/Components/Sell/sell-button.jsx | 34 -------------------
.../Contract/Components/Sell/sell-info.jsx | 34 -------------------
.../__tests__/contract-error.spec.tsx | 32 +++++++++++++++++
...{contract-error.jsx => contract-error.tsx} | 13 ++++---
5 files changed, 39 insertions(+), 76 deletions(-)
delete mode 100644 packages/trader/src/Modules/Contract/Components/Sell/sell-button.jsx
delete mode 100644 packages/trader/src/Modules/Contract/Components/Sell/sell-info.jsx
create mode 100644 packages/trader/src/Modules/Contract/Components/__tests__/contract-error.spec.tsx
rename packages/trader/src/Modules/Contract/Components/{contract-error.jsx => contract-error.tsx} (86%)
diff --git a/packages/trader/src/Modules/Contract/Components/InfoBox/info-box.jsx b/packages/trader/src/Modules/Contract/Components/InfoBox/info-box.jsx
index e0c3607add99..9631a004c4c4 100644
--- a/packages/trader/src/Modules/Contract/Components/InfoBox/info-box.jsx
+++ b/packages/trader/src/Modules/Contract/Components/InfoBox/info-box.jsx
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import { SlideIn } from 'App/Components/Animations';
import InfoBoxLongcode from './info-box-longcode.jsx';
-import ContractError from '../contract-error.jsx';
+import ContractError from '../contract-error';
const InfoBox = ({ contract_info, error_message, removeError }) => {
const is_ready = !!contract_info.longcode;
diff --git a/packages/trader/src/Modules/Contract/Components/Sell/sell-button.jsx b/packages/trader/src/Modules/Contract/Components/Sell/sell-button.jsx
deleted file mode 100644
index ca255bdb2be4..000000000000
--- a/packages/trader/src/Modules/Contract/Components/Sell/sell-button.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { observer } from 'mobx-react';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Popover } from '@deriv/components';
-import { localize } from '@deriv/translations';
-
-const SellButton = ({ contract_info, is_sell_requested, is_valid_to_sell, onClickSell }) => {
- const sell_message = is_valid_to_sell
- ? localize(
- 'Contract will be sold at the prevailing market price when the request is received by our servers. This price may differ from the indicated price.'
- )
- : contract_info.validation_error;
-
- return (
-
-
-
-
- );
-};
-
-SellButton.propTypes = {
- contract_info: PropTypes.object,
- is_sell_requested: PropTypes.bool,
- is_valid_to_sell: PropTypes.bool,
- onClickSell: PropTypes.func,
-};
-
-export default observer(SellButton);
diff --git a/packages/trader/src/Modules/Contract/Components/Sell/sell-info.jsx b/packages/trader/src/Modules/Contract/Components/Sell/sell-info.jsx
deleted file mode 100644
index e13e3047523d..000000000000
--- a/packages/trader/src/Modules/Contract/Components/Sell/sell-info.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { observer } from 'mobx-react';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Money } from '@deriv/components';
-import { localize, Localize } from '@deriv/translations';
-
-const SellInfo = ({ contract_info, sell_info }) => (
-
-
- ,
- ]}
- />
-
-
- {localize('Your transaction reference number is {{transaction_id}}', {
- transaction_id: sell_info.transaction_id,
- })}
-
-
-);
-
-SellInfo.propTypes = {
- contract_info: PropTypes.object,
- sell_info: PropTypes.object,
-};
-
-export default observer(SellInfo);
diff --git a/packages/trader/src/Modules/Contract/Components/__tests__/contract-error.spec.tsx b/packages/trader/src/Modules/Contract/Components/__tests__/contract-error.spec.tsx
new file mode 100644
index 000000000000..8d13b378df61
--- /dev/null
+++ b/packages/trader/src/Modules/Contract/Components/__tests__/contract-error.spec.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import ContractError from '../contract-error';
+
+const mocked_props = {
+ onClickClose: jest.fn(),
+};
+const test_text = 'test_text';
+jest.mock('@deriv/components', () => ({
+ Icon: jest.fn(() => 'MockedIcon'),
+}));
+
+describe('ContractError', () => {
+ it('should not render component if message is falsy', () => {
+ const { container } = render();
+
+ expect(container).toBeEmptyDOMElement();
+ });
+ it('should render component with specific text inside if it was passed as a message in the props', () => {
+ render();
+
+ expect(screen.getByText(test_text)).toBeInTheDocument();
+ });
+ it('should call the function if the icon was clicked', () => {
+ render();
+ const icon = screen.getByText('MockedIcon');
+ userEvent.click(icon);
+
+ expect(mocked_props.onClickClose).toBeCalled();
+ });
+});
diff --git a/packages/trader/src/Modules/Contract/Components/contract-error.jsx b/packages/trader/src/Modules/Contract/Components/contract-error.tsx
similarity index 86%
rename from packages/trader/src/Modules/Contract/Components/contract-error.jsx
rename to packages/trader/src/Modules/Contract/Components/contract-error.tsx
index a8c6098f6c8e..d26019c9a0b0 100644
--- a/packages/trader/src/Modules/Contract/Components/contract-error.jsx
+++ b/packages/trader/src/Modules/Contract/Components/contract-error.tsx
@@ -1,10 +1,14 @@
-import PropTypes from 'prop-types';
import React from 'react';
import { Icon } from '@deriv/components';
+type TContractError = {
+ message?: string;
+ onClickClose: () => void;
+};
+
// TODO: move to App/Components, Refactor svg, consider other types, more features;
// when a general design and more icons for all messages is ready
-const ContractError = ({ message = '', onClickClose }) =>
+const ContractError = ({ message = '', onClickClose }: TContractError) =>
!message ? null : (
@@ -26,9 +30,4 @@ const ContractError = ({ message = '', onClickClose }) =>
);
-ContractError.propTypes = {
- message: PropTypes.string,
- onClickClose: PropTypes.func,
-};
-
export default ContractError;
From b8308438be035e728b817b1cbf60b6f3e0711a95 Mon Sep 17 00:00:00 2001
From: kate-deriv <121025168+kate-deriv@users.noreply.github.com>
Date: Tue, 26 Sep 2023 12:12:19 +0300
Subject: [PATCH 3/5] Kate / DTRA-178 / Enable Asians contract from SmartTrader
(#9050)
* refactor: move trade type from un to supported
* feat: ad contract type check func and add to contract details
* feat: add chart markers settings for contract type
* chore: add style for mobile
* chore: remove gradient
* chore: empty commit
* chore: add gradient for contract details card for desktop
* feat: add chart markers setings and update style
* refactor: apply suggestions
* chore: empty commit
* feat: enable smart trader contract
* refactor: remove rounding for barrier value
* refactor: add swipble component for contract audit mobile and fix style
* refactor: applied suggestions from review
* feat: enable asians contract
* feat: add barrier for asians contract in contract audit
* refactor: update tests
* refactor: checks in contract details file
* chore: impove reg exp
* chore: add reg ex improvement
* fix: change trade type icons
* fix: add entry tick
* chore: empty commit
* chore: empty commit
* fix: conflicts
* chore: remove unnessesary prop
---
.../stories/contract-card/statics/contract.js | 16 ++++-----
.../shared/src/utils/constants/contract.ts | 16 ++++-----
.../shared/src/utils/contract/contract.ts | 9 +++--
.../helpers/__tests__/format-response.ts | 2 +-
.../ContractAudit/contract-details.jsx | 36 +++++++++++--------
5 files changed, 45 insertions(+), 34 deletions(-)
diff --git a/packages/components/stories/contract-card/statics/contract.js b/packages/components/stories/contract-card/statics/contract.js
index 7e671ff54a61..67e040c8a65a 100644
--- a/packages/components/stories/contract-card/statics/contract.js
+++ b/packages/components/stories/contract-card/statics/contract.js
@@ -128,14 +128,6 @@ export const getUnsupportedContracts = () => ({
name: 'Low Tick',
position: 'bottom',
},
- ASIANU: {
- name: 'Asian Up',
- position: 'top',
- },
- ASIAND: {
- name: 'Asian Down',
- position: 'bottom',
- },
LBFLOATCALL: {
name: 'Close-to-Low',
position: 'top',
@@ -254,6 +246,14 @@ export const getSupportedContracts = is_high_low => ({
name: 'Goes Outside',
position: 'bottom',
},
+ ASIANU: {
+ name: 'Asian Up',
+ position: 'top',
+ },
+ ASIAND: {
+ name: 'Asian Down',
+ position: 'bottom',
+ },
});
export const getContractConfig = is_high_low => ({
diff --git a/packages/shared/src/utils/constants/contract.ts b/packages/shared/src/utils/constants/contract.ts
index 33c318cb9c0e..44dee5aa36a7 100644
--- a/packages/shared/src/utils/constants/contract.ts
+++ b/packages/shared/src/utils/constants/contract.ts
@@ -358,14 +358,6 @@ export const getUnsupportedContracts = () =>
name: localize('Low Tick'),
position: 'bottom',
},
- ASIANU: {
- name: localize('Asian Up'),
- position: 'top',
- },
- ASIAND: {
- name: localize('Asian Down'),
- position: 'bottom',
- },
LBFLOATCALL: {
name: localize('Close-to-Low'),
position: 'top',
@@ -493,6 +485,14 @@ export const getSupportedContracts = (is_high_low?: boolean) =>
name: localize('Goes Outside'),
position: 'bottom',
},
+ ASIANU: {
+ name: localize('Asian Up'),
+ position: 'top',
+ },
+ ASIAND: {
+ name: localize('Asian Down'),
+ position: 'bottom',
+ },
} as const);
export const getContractConfig = (is_high_low?: boolean) => ({
diff --git a/packages/shared/src/utils/contract/contract.ts b/packages/shared/src/utils/contract/contract.ts
index aaf7bcbc7543..5a2012e69b51 100644
--- a/packages/shared/src/utils/contract/contract.ts
+++ b/packages/shared/src/utils/contract/contract.ts
@@ -71,7 +71,9 @@ export const isTurbosContract = (contract_type = '') => /TURBOS/i.test(contract_
export const isVanillaContract = (contract_type = '') => /VANILLA/i.test(contract_type);
-export const isSmartTraderContract = (contract_type = '') => /RUN|EXPIRY|RANGE|UPORDOWN/i.test(contract_type);
+export const isSmartTraderContract = (contract_type = '') => /RUN|EXPIRY|RANGE|UPORDOWN|ASIAN/i.test(contract_type);
+
+export const isAsiansContract = (contract_type = '') => /ASIAN/i.test(contract_type);
export const isCryptoContract = (underlying = '') => underlying.startsWith('cry');
@@ -103,7 +105,10 @@ export const getAccuBarriersForContractDetails = (contract_info: TContractInfo)
export const getCurrentTick = (contract_info: TContractInfo) => {
const tick_stream = unique(contract_info.tick_stream || [], 'epoch');
- const current_tick = isDigitContract(contract_info.contract_type) ? tick_stream.length : tick_stream.length - 1;
+ const current_tick =
+ isDigitContract(contract_info.contract_type) || isAsiansContract(contract_info.contract_type)
+ ? tick_stream.length
+ : tick_stream.length - 1;
return !current_tick || current_tick < 0 ? 0 : current_tick;
};
diff --git a/packages/shared/src/utils/helpers/__tests__/format-response.ts b/packages/shared/src/utils/helpers/__tests__/format-response.ts
index c1b54cf27d52..2b0638def931 100644
--- a/packages/shared/src/utils/helpers/__tests__/format-response.ts
+++ b/packages/shared/src/utils/helpers/__tests__/format-response.ts
@@ -95,7 +95,7 @@ describe('format-response', () => {
display_name: 'Volatility 25 Index',
id: 1234,
indicative: 0,
- is_unsupported: true,
+ is_unsupported: false,
payout: 3500.1,
contract_update: undefined,
purchase: 2500.5,
diff --git a/packages/trader/src/App/Components/Elements/ContractAudit/contract-details.jsx b/packages/trader/src/App/Components/Elements/ContractAudit/contract-details.jsx
index 204e2a72f939..51e4083bdccf 100644
--- a/packages/trader/src/App/Components/Elements/ContractAudit/contract-details.jsx
+++ b/packages/trader/src/App/Components/Elements/ContractAudit/contract-details.jsx
@@ -6,11 +6,12 @@ import {
epochToMoment,
getCancellationPrice,
getCurrencyDisplayCode,
+ hasTwoBarriers,
isAccumulatorContract,
isMobile,
isMultiplierContract,
isSmartTraderContract,
- hasTwoBarriers,
+ isAsiansContract,
isTurbosContract,
isUserSold,
isEndedBeforeCancellationExpired,
@@ -49,6 +50,7 @@ const ContractDetails = ({ contract_end_time, contract_info, duration, duration_
const show_barrier = !is_vanilla && !isAccumulatorContract(contract_type) && !isSmartTraderContract(contract_type);
const show_duration = !isAccumulatorContract(contract_type) || !isNaN(contract_end_time);
const show_payout_per_point = isTurbosContract(contract_type) || is_vanilla;
+ const show_strike_barrier = is_vanilla || isAsiansContract(contract_type);
const ticks_duration_text = isAccumulatorContract(contract_type)
? `${tick_passed}/${tick_count} ${localize('ticks')}`
: `${tick_count} ${tick_count < 2 ? localize('tick') : localize('ticks')}`;
@@ -98,7 +100,7 @@ const ContractDetails = ({ contract_end_time, contract_info, duration, duration_
value={tick_count > 0 ? ticks_duration_text : `${duration} ${duration_unit}`}
/>
)}
- {is_vanilla && (
+ {show_strike_barrier && (
}
@@ -120,6 +122,23 @@ const ContractDetails = ({ contract_end_time, contract_info, duration, duration_
value={getBarrierValue(contract_info) || ' - '}
/>
)}
+ {hasTwoBarriers(contract_type) && (
+
+ {[high_barrier, low_barrier].map((barrier, index) => (
+ }
+ key={barrier}
+ label={
+ high_barrier === barrier
+ ? localize('High barrier')
+ : localize('Low barrier')
+ }
+ value={barrier}
+ />
+ ))}
+
+ )}
{show_payout_per_point && (
)}
- {hasTwoBarriers(contract_type) && (
-
- {[high_barrier, low_barrier].map((barrier, index) => (
- }
- key={barrier}
- label={high_barrier === barrier ? localize('High barrier') : localize('Low barrier')}
- value={barrier}
- />
- ))}
-
- )}
}
From 76bddebdaa9ab88ba1c67289a8b7a264b9823037 Mon Sep 17 00:00:00 2001
From: henry-deriv <118344354+henry-deriv@users.noreply.github.com>
Date: Tue, 26 Sep 2023 17:19:50 +0800
Subject: [PATCH 4/5] henry/matin/feq-79/remove-connect-from-reports (#9446)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* fix: initial commit
* fix: initial setup for useReportsStore
* chore: remove connect from account-statistics (#2)
* chore: remove connect from filter-component (#3)
* fix: refactor useReportsStores
* chore: remove connect from Indicative-cell (#4)
* fix: reduce typescript errors
* fix: sonarcloud
* fix: resolve typescript errors
* chore: remove connect from composite-calendar
* fix: type fix
* fix: remove connect files and mobx providers
* fix: resolve comments
* fix: resolve comment
* fix: remove unused files
* fix: fix types
* fix: resolve comments
* fix: resolve comments
* fix: snoarcloud
* fix: comment
* fix: comment
* fix: resolve comment
* fix: add onclick to test
* fix: reset with master
* fix: resolve comment
---------
Co-authored-by: Matin shafiei
Co-authored-by: “Matin-deriv”
---
.../contract-card-body.tsx | 2 +-
.../toggle-card-dialog.tsx | 2 +-
.../contract-card/contract-card.tsx | 2 +-
.../result-overlay/result-overlay.tsx | 4 +-
.../components/data-list/data-list-cell.tsx | 20 +-
.../components/data-list/data-list-row.tsx | 6 +-
.../src/components/data-list/data-list.tsx | 16 +-
.../src/components/data-table/data-table.tsx | 28 +-
.../components/data-table/table-row-info.tsx | 4 +-
.../src/components/data-table/table-row.tsx | 2 +-
.../src/components/dialog/dialog.tsx | 2 +-
.../filter-dropdown/filter-dropdown.tsx | 8 +-
.../infinite-data-list/infinite-data-list.tsx | 18 +-
.../components/input-field/input-field.tsx | 2 +-
.../src/components/input-field/input.tsx | 2 +-
.../positions-drawer-card.tsx | 6 +-
.../src/components/types/common.types.ts | 11 +-
.../src/components/types/contract.types.ts | 8 +-
packages/reports/build/webpack.config.js | 1 -
packages/reports/package.json | 3 -
.../composite-calendar-mobile.tsx | 26 +-
.../CompositeCalendar/composite-calendar.tsx | 22 +-
.../src/Components/account-statistics.tsx | 24 +-
.../src/Components/filter-component.tsx | 48 +---
.../src/Components/indicative-cell.tsx | 28 +-
.../src/Constants/data-table-constants.tsx | 3 +-
.../reports/src/Containers/open-positions.tsx | 241 ++++++++----------
.../reports/src/Containers/profit-table.tsx | 159 +++++-------
.../src/Containers/progress-slider-stream.tsx | 21 +-
packages/reports/src/Containers/routes.tsx | 23 +-
packages/reports/src/Containers/statement.tsx | 175 +++++--------
packages/reports/src/Stores/connect.js | 31 ---
packages/reports/src/Stores/index.ts | 41 ---
.../reports/src/Stores/useReportsStores.tsx | 69 +++++
.../reports/src/Types/common-prop.type.ts | 8 +-
.../reports/src/_common/base/server_time.js | 25 --
packages/reports/src/_common/utility.js | 41 ---
packages/reports/src/app.tsx | 15 +-
packages/reports/src/init-store.js | 20 --
packages/reports/src/reports-providers.tsx | 14 +
packages/stores/src/mockStore.ts | 35 +--
packages/stores/types.ts | 108 ++++----
42 files changed, 553 insertions(+), 771 deletions(-)
delete mode 100644 packages/reports/src/Stores/connect.js
delete mode 100644 packages/reports/src/Stores/index.ts
create mode 100644 packages/reports/src/Stores/useReportsStores.tsx
delete mode 100644 packages/reports/src/_common/base/server_time.js
delete mode 100644 packages/reports/src/init-store.js
create mode 100644 packages/reports/src/reports-providers.tsx
diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-body.tsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-body.tsx
index 9ccf910a4274..2f72de4633be 100644
--- a/packages/components/src/components/contract-card/contract-card-items/contract-card-body.tsx
+++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-body.tsx
@@ -26,7 +26,7 @@ export type TGeneralContractCardBodyProps = {
current_focus?: string | null;
error_message_alignment?: string;
getCardLabels: TGetCardLables;
- getContractById: (contract_id?: number) => TContractStore;
+ getContractById: (contract_id: number) => TContractStore;
should_show_cancellation_warning: boolean;
has_progress_slider: boolean;
is_mobile: boolean;
diff --git a/packages/components/src/components/contract-card/contract-card-items/toggle-card-dialog.tsx b/packages/components/src/components/contract-card/contract-card-items/toggle-card-dialog.tsx
index 2d3fbea6e2bb..ce87b3690213 100644
--- a/packages/components/src/components/contract-card/contract-card-items/toggle-card-dialog.tsx
+++ b/packages/components/src/components/contract-card/contract-card-items/toggle-card-dialog.tsx
@@ -60,7 +60,7 @@ const ToggleCardDialog = ({
const toggle_ref = React.useRef(null);
const dialog_ref = React.useRef(null);
- const contract = getContractById(contract_id);
+ const contract = getContractById(Number(contract_id));
React.useEffect(() => {
ContractUpdateFormWrapper = connectWithContractUpdate?.(ContractUpdateForm) || ContractUpdateForm;
diff --git a/packages/components/src/components/contract-card/contract-card.tsx b/packages/components/src/components/contract-card/contract-card.tsx
index 2213afe58b48..77a54f5f9ecb 100644
--- a/packages/components/src/components/contract-card/contract-card.tsx
+++ b/packages/components/src/components/contract-card/contract-card.tsx
@@ -18,7 +18,7 @@ type TContractCardProps = {
is_multiplier: boolean;
is_positions: boolean;
is_unsupported: boolean;
- onClickRemove: (contract_id?: number) => void;
+ onClickRemove: (contract_id: number) => void;
profit_loss: number;
result: string;
should_show_result_overlay: boolean;
diff --git a/packages/components/src/components/contract-card/result-overlay/result-overlay.tsx b/packages/components/src/components/contract-card/result-overlay/result-overlay.tsx
index 0762e3eff3aa..25be6f8cf87a 100644
--- a/packages/components/src/components/contract-card/result-overlay/result-overlay.tsx
+++ b/packages/components/src/components/contract-card/result-overlay/result-overlay.tsx
@@ -14,7 +14,7 @@ type TResultOverlayProps = {
is_unsupported: boolean;
is_visible: boolean;
onClick: () => void;
- onClickRemove: (contract_id?: number) => void;
+ onClickRemove: (contract_id: number) => void;
result: string;
};
@@ -88,7 +88,7 @@ const ResultOverlay = ({
onClickRemove(contract_id)}
+ onClick={() => onClickRemove(Number(contract_id))}
/>
)}
{getContractPath && (
diff --git a/packages/components/src/components/data-list/data-list-cell.tsx b/packages/components/src/components/data-list/data-list-cell.tsx
index 27e5dabc9f90..241e0d046b4b 100644
--- a/packages/components/src/components/data-list/data-list-cell.tsx
+++ b/packages/components/src/components/data-list/data-list-cell.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import classNames from 'classnames';
import { isTurbosContract, isVanillaContract } from '@deriv/shared';
-import { TPassThrough, TRow } from './data-list';
+import { TPassThrough, TRow } from '../types/common.types';
export type TColIndex =
| 'type'
@@ -36,22 +36,24 @@ export type TDataListCell = {
className?: string;
column?: {
key?: string;
- title?: React.ReactNode;
- col_index: TColIndex;
+ title?: string;
+ col_index?: TColIndex;
renderCellContent?: (props: TRenderCellContent) => React.ReactNode;
- renderHeader?: (props: THeaderProps) => React.ReactNode;
+ renderHeader?: (prop: renderHeaderType) => React.ReactNode;
};
is_footer?: boolean;
passthrough?: TPassThrough;
- row: TRow;
+ row?: TRow;
};
+type renderHeaderType = { title?: string; is_vanilla?: boolean };
+
const DataListCell = ({ className, column, is_footer, passthrough, row }: TDataListCell) => {
if (!column) return null;
const { col_index, title } = column;
- const cell_value = row[col_index];
- const is_turbos = isTurbosContract(row.contract_info?.contract_type);
- const is_vanilla = isVanillaContract(row.contract_info?.contract_type);
+ const cell_value = row?.[col_index as TColIndex];
+ const is_turbos = isTurbosContract(row?.contract_info?.contract_type);
+ const is_vanilla = isVanillaContract(row?.contract_info?.contract_type);
return (
@@ -66,7 +68,7 @@ const DataListCell = ({ className, column, is_footer, passthrough, row }: TDataL
cell_value,
is_footer,
passthrough,
- row_obj: row,
+ row_obj: row as TRow,
is_vanilla,
is_turbos,
})
diff --git a/packages/components/src/components/data-list/data-list-row.tsx b/packages/components/src/components/data-list/data-list-row.tsx
index ed96acdd15fe..37189cc6c5d1 100644
--- a/packages/components/src/components/data-list/data-list-row.tsx
+++ b/packages/components/src/components/data-list/data-list-row.tsx
@@ -2,7 +2,9 @@ import classNames from 'classnames';
import React from 'react';
import { NavLink } from 'react-router-dom';
import { useIsMounted } from '@deriv/shared';
-import { TPassThrough, TRow, TRowRenderer } from './data-list';
+import { TRowRenderer } from './data-list';
+import { TPassThrough } from '../types/common.types';
+import { TSource } from '../data-table/data-table';
type TDataListRow = {
action_desc?: {
@@ -17,7 +19,7 @@ type TDataListRow = {
is_new_row: boolean;
is_scrolling: boolean;
passthrough?: TPassThrough;
- row: TRow;
+ row: TSource;
};
const DataListRow = ({
diff --git a/packages/components/src/components/data-list/data-list.tsx b/packages/components/src/components/data-list/data-list.tsx
index 79c606efbc8e..01d829796f3b 100644
--- a/packages/components/src/components/data-list/data-list.tsx
+++ b/packages/components/src/components/data-list/data-list.tsx
@@ -17,6 +17,12 @@ import DataListCell, { TColIndex, TDataListCell } from './data-list-cell';
import DataListRow from './data-list-row';
import ThemedScrollbars from '../themed-scrollbars';
import { MeasuredCellParent } from 'react-virtualized/dist/es/CellMeasurer';
+import { TTableRowItem, TPassThrough, TRow } from '../types/common.types';
+
+const List = _List as unknown as React.FC
;
+const AutoSizer = _AutoSizer as unknown as React.FC;
+const CellMeasurer = _CellMeasurer as unknown as React.FC;
+export type TRowRenderer = (params: Partial) => React.ReactNode;
type TMobileRowRenderer = {
row?: TRow;
@@ -26,19 +32,14 @@ type TMobileRowRenderer = {
onClickCancel: (contract_id?: number) => void;
onClickSell: (contract_id?: number) => void;
measure?: () => void;
+ passthrough?: TPassThrough;
};
-const List = _List as unknown as React.FC;
-const AutoSizer = _AutoSizer as unknown as React.FC;
-const CellMeasurer = _CellMeasurer as unknown as React.FC;
-export type TRowRenderer = (params: Partial) => React.ReactNode;
-export type TPassThrough = { isTopUp: (item: TRow) => boolean };
-export type TRow = { [key: string]: any };
export type TDataList = {
className?: string;
data_source: TRow[];
footer?: TRow;
- getRowAction?: (row: TRow) => { component: JSX.Element } | string;
+ getRowAction?: (row: TRow) => TTableRowItem;
getRowSize?: (params: { index: number }) => number;
keyMapper?: (row: TRow) => number | string;
onRowsRendered?: (params: IndexRange) => void;
@@ -121,6 +122,7 @@ const DataList = React.memo(
const getContent = ({ measure }: GetContentType = {}) => (
TTableRowItem[];
getRowSize?: ((params: { index: number }) => number) | number;
measure?: () => void;
- getRowAction?: (row: Record) => { component: JSX.Element } | string;
+ getRowAction?: (item: TSource) => TTableRowItem;
onScroll?: React.UIEventHandler;
id?: number;
- passthrough?: (item: TSource) => boolean;
+ passthrough?: React.ComponentProps['passthrough'];
autoHide?: boolean;
- footer: Record;
- preloaderCheck: (param: TSource) => boolean;
- data_source: TSource[];
+ footer?: Record | React.ReactNode;
+ preloaderCheck?: (param: TSource) => boolean;
+ data_source?: TSource[];
keyMapper?: (row: TSource) => number | string;
};
@@ -82,7 +82,8 @@ const DataTable = ({
cache_ref.current = new CellMeasurerCache({
fixedWidth: true,
keyMapper: row_index => {
- if (row_index < data_source.length) return keyMapper?.(data_source[row_index]) || row_index;
+ if (data_source && row_index < data_source.length)
+ return keyMapper?.(data_source[row_index]) || row_index;
return row_index;
},
});
@@ -101,10 +102,13 @@ const DataTable = ({
};
const rowRenderer = ({ style, index, key, parent }: TRowRenderer) => {
- const item = data_source[index];
- const action = getRowAction && getRowAction(item);
- const contract_id = item.contract_id || item.id;
- const row_key = keyMapper?.(item) || key;
+ const item = data_source?.[index];
+ const contract_id = (item?.contract_id || item?.id) as string;
+ let action: TTableRowItem | undefined, row_key;
+ if (item) {
+ action = getRowAction && getRowAction(item);
+ row_key = keyMapper?.(item) || key;
+ }
// If row content is complex, consider rendering a light-weight placeholder while scrolling.
const getContent = ({ measure }: TMeasure) => (
@@ -119,7 +123,7 @@ const DataTable = ({
passthrough={passthrough}
replace={typeof action === 'object' ? action : undefined}
row_obj={item}
- show_preloader={typeof preloaderCheck === 'function' ? preloaderCheck(item) : false}
+ show_preloader={typeof preloaderCheck === 'function' && item ? preloaderCheck(item) : false}
to={typeof action === 'string' ? action : undefined}
is_dynamic_height={is_dynamic_height}
is_footer={false}
@@ -185,7 +189,7 @@ const DataTable = ({
height={height}
overscanRowCount={1}
ref={(ref: Grid) => (list_ref.current = ref)}
- rowCount={data_source.length}
+ rowCount={data_source?.length || 0}
rowHeight={
is_dynamic_height && cache_ref?.current?.rowHeight
? cache_ref?.current?.rowHeight
diff --git a/packages/components/src/components/data-table/table-row-info.tsx b/packages/components/src/components/data-table/table-row-info.tsx
index 33c45309eba5..79f94638821e 100644
--- a/packages/components/src/components/data-table/table-row-info.tsx
+++ b/packages/components/src/components/data-table/table-row-info.tsx
@@ -31,7 +31,7 @@ const TableRowInfo = ({ replace, is_footer, cells, className, is_dynamic_height,
onClick={is_footer || !replace ? undefined : toggleDetails}
className={classNames(className, { 'statement__row--detail': show_details })}
>
- {show_details ? {replace?.component}
: cells}
+ {show_details && typeof replace === 'object' ? {replace?.component}
: cells}
);
}
@@ -40,7 +40,7 @@ const TableRowInfo = ({ replace, is_footer, cells, className, is_dynamic_height,
onClick={is_footer || !replace ? undefined : toggleDetails}
className={classNames(className, { 'statement__row--detail': show_details })}
>
- {show_details ? (
+ {show_details && typeof replace === 'object' ? (
{replace?.component}
diff --git a/packages/components/src/components/data-table/table-row.tsx b/packages/components/src/components/data-table/table-row.tsx
index f69acab953db..07a723467826 100644
--- a/packages/components/src/components/data-table/table-row.tsx
+++ b/packages/components/src/components/data-table/table-row.tsx
@@ -11,7 +11,7 @@ type TTableRow = {
id?: string;
is_footer: boolean;
is_header?: boolean;
- passthrough?: (item: TSource) => boolean;
+ passthrough?: { isTopUp: (item: TSource) => boolean };
replace?: TTableRowItem;
to?: string;
show_preloader?: boolean;
diff --git a/packages/components/src/components/dialog/dialog.tsx b/packages/components/src/components/dialog/dialog.tsx
index d2f7209ca4fd..1acf950382f8 100644
--- a/packages/components/src/components/dialog/dialog.tsx
+++ b/packages/components/src/components/dialog/dialog.tsx
@@ -26,7 +26,7 @@ type TDialog = {
onConfirm: () => void;
onEscapeButtonCancel?: () => void;
portal_element_id?: string;
- title?: string;
+ title?: string | JSX.Element;
};
const Dialog = ({
diff --git a/packages/components/src/components/filter-dropdown/filter-dropdown.tsx b/packages/components/src/components/filter-dropdown/filter-dropdown.tsx
index be1c618f5601..a73265a9aa5e 100644
--- a/packages/components/src/components/filter-dropdown/filter-dropdown.tsx
+++ b/packages/components/src/components/filter-dropdown/filter-dropdown.tsx
@@ -13,14 +13,14 @@ type TListItem = {
};
type TFilterDropdown = {
- dropdown_className: string;
+ dropdown_className?: string;
dropdown_display_className: string;
filter_list: Array;
handleFilterChange: (e: string) => void;
- initial_filter: string;
+ initial_filter?: string;
initial_selected_filter: string;
- label: string;
- hide_top_placeholder: boolean;
+ label?: string;
+ hide_top_placeholder?: boolean;
};
const FilterDropdown = ({
diff --git a/packages/components/src/components/infinite-data-list/infinite-data-list.tsx b/packages/components/src/components/infinite-data-list/infinite-data-list.tsx
index 23f625d67ea1..883115edc59b 100644
--- a/packages/components/src/components/infinite-data-list/infinite-data-list.tsx
+++ b/packages/components/src/components/infinite-data-list/infinite-data-list.tsx
@@ -1,20 +1,20 @@
import React from 'react';
import { InfiniteLoader as _InfiniteLoader, InfiniteLoaderProps, Index, IndexRange } from 'react-virtualized';
-import DataList, { TRow, TRowRenderer } from '../data-list/data-list';
+import DataList from '../data-list/data-list';
const InfiniteLoader = _InfiniteLoader as unknown as React.FC;
-type TInfiniteDatalist = {
+
+type TInfiniteDatalist = Pick<
+ React.ComponentProps,
+ 'getRowSize' | 'onRowsRendered' | 'onScroll' | 'overscanRowCount' | 'rowRenderer'
+> & {
className: string;
data_list_className: string;
has_more_items_to_load: boolean;
- items: TRow[];
- keyMapperFn?: (row: TRow) => number | string;
- loadMoreRowsFn: (params: IndexRange) => Promise;
- onScroll: () => void;
- rowRenderer: TRowRenderer;
has_filler: boolean;
- overscanRowCount: number;
- getRowSize?: (params: { index: number }) => number;
+ items: React.ComponentProps['data_source'];
+ keyMapperFn: React.ComponentProps['keyMapper'];
+ loadMoreRowsFn: (params: IndexRange) => Promise;
};
const InfiniteDataList = ({
diff --git a/packages/components/src/components/input-field/input-field.tsx b/packages/components/src/components/input-field/input-field.tsx
index a7b60b333d7c..67859d60be00 100644
--- a/packages/components/src/components/input-field/input-field.tsx
+++ b/packages/components/src/components/input-field/input-field.tsx
@@ -23,7 +23,7 @@ type TInputField = {
classNamePrefix?: string;
classNameWrapper?: string; // CSS class for the component wrapper
currency: string;
- current_focus: string;
+ current_focus?: string | null;
data_testid?: string;
data_tip?: string;
data_value?: string;
diff --git a/packages/components/src/components/input-field/input.tsx b/packages/components/src/components/input-field/input.tsx
index 126a164b16ca..3547ddef0aa9 100644
--- a/packages/components/src/components/input-field/input.tsx
+++ b/packages/components/src/components/input-field/input.tsx
@@ -13,7 +13,7 @@ type TInputProps = {
className?: string;
classNameDynamicSuffix?: string;
classNameInlinePrefix?: string;
- current_focus: string;
+ current_focus?: string | null;
data_testid?: string;
data_tip?: string;
data_value?: number | string;
diff --git a/packages/components/src/components/positions-drawer-card/positions-drawer-card.tsx b/packages/components/src/components/positions-drawer-card/positions-drawer-card.tsx
index a929e246887a..fd9ed4667948 100644
--- a/packages/components/src/components/positions-drawer-card/positions-drawer-card.tsx
+++ b/packages/components/src/components/positions-drawer-card/positions-drawer-card.tsx
@@ -23,9 +23,9 @@ type TPositionsDrawerCardProps = {
contract_info: TContractInfo;
contract_update?: TContractInfo['contract_update'];
currency: string;
- current_focus: string;
+ current_focus: string | null;
display_name?: string;
- getContractById: (contract_id?: number) => TContractStore;
+ getContractById: (contract_id: number) => TContractStore;
is_mobile?: boolean;
is_sell_requested?: boolean;
is_unsupported?: boolean;
@@ -33,7 +33,7 @@ type TPositionsDrawerCardProps = {
profit_loss?: number;
onClickCancel: (contract_id?: number) => void;
onClickSell: (contract_id?: number) => void;
- onClickRemove: (contract_id?: number) => void;
+ onClickRemove: (contract_id: number) => void;
onFooterEntered?: () => void;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
diff --git a/packages/components/src/components/types/common.types.ts b/packages/components/src/components/types/common.types.ts
index 8b459a97081b..65048a670689 100644
--- a/packages/components/src/components/types/common.types.ts
+++ b/packages/components/src/components/types/common.types.ts
@@ -13,4 +13,13 @@ export type TItem = {
value: Array | string;
};
-export type TTableRowItem = { component: React.ReactNode };
+export type TTableRowItem =
+ | {
+ message?: string;
+ component?: React.ReactElement;
+ }
+ | string;
+
+export type TRow = { [key: string]: any };
+
+export type TPassThrough = { isTopUp: (item: TRow) => boolean };
diff --git a/packages/components/src/components/types/contract.types.ts b/packages/components/src/components/types/contract.types.ts
index 212a926b300b..090e2607aa33 100644
--- a/packages/components/src/components/types/contract.types.ts
+++ b/packages/components/src/components/types/contract.types.ts
@@ -1,11 +1,11 @@
export type TGetContractPath = (contract_id?: number) => string;
export type TToastConfig = {
- key?: string;
- content: string;
- timeout?: number;
+ key: string;
+ content: string | React.ReactNode;
is_bottom?: boolean;
- type?: string;
+ timeout?: number;
+ type: string;
};
export type TErrorMessages = Readonly<{
diff --git a/packages/reports/build/webpack.config.js b/packages/reports/build/webpack.config.js
index abe0e97d799b..8837014558a2 100644
--- a/packages/reports/build/webpack.config.js
+++ b/packages/reports/build/webpack.config.js
@@ -40,7 +40,6 @@ module.exports = function (env) {
'react-router-dom': 'react-router-dom',
'react-router': 'react-router',
mobx: 'mobx',
- 'mobx-react': 'mobx-react',
'@deriv/shared': '@deriv/shared',
'@deriv/components': '@deriv/components',
'@deriv/translations': '@deriv/translations',
diff --git a/packages/reports/package.json b/packages/reports/package.json
index 1f1e18eb1b98..8dc811b193b6 100644
--- a/packages/reports/package.json
+++ b/packages/reports/package.json
@@ -76,7 +76,6 @@
},
"dependencies": {
"@deriv/components": "^1.0.0",
- "@deriv/deriv-api": "^1.0.11",
"@deriv/shared": "^1.0.0",
"@deriv/stores": "^1.0.0",
"@deriv/translations": "^1.0.0",
@@ -95,8 +94,6 @@
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
"mobx": "^6.6.1",
- "mobx-react": "^7.5.1",
- "mobx-utils": "^6.0.5",
"moment": "^2.29.2",
"null-loader": "^4.0.1",
"object.fromentries": "^2.0.0",
diff --git a/packages/reports/src/Components/Form/CompositeCalendar/composite-calendar-mobile.tsx b/packages/reports/src/Components/Form/CompositeCalendar/composite-calendar-mobile.tsx
index 3e53511c6bc8..d059be4877e1 100644
--- a/packages/reports/src/Components/Form/CompositeCalendar/composite-calendar-mobile.tsx
+++ b/packages/reports/src/Components/Form/CompositeCalendar/composite-calendar-mobile.tsx
@@ -44,14 +44,14 @@ export const RadioButton = ({ id, className, selected_value, value, label, onCha
const CUSTOM_KEY = 'custom';
type TCompositeCalendarMobile = {
- input_date_range: TInputDateRange;
- current_focus: string;
- duration_list: Array;
+ input_date_range?: TInputDateRange;
+ current_focus?: string;
+ duration_list?: Array;
onChange: (
value: { from?: moment.Moment; to?: moment.Moment; is_batch?: boolean },
extra_data?: { date_range: TInputDateRange }
) => void;
- setCurrentFocus: (focus: string) => void;
+ setCurrentFocus?: (focus: string) => void;
from: number;
to: number;
};
@@ -66,7 +66,7 @@ const CompositeCalendarMobile = React.memo(
from,
to,
}: TCompositeCalendarMobile) => {
- const date_range = input_date_range || duration_list.find(range => range.value === 'all_time');
+ const date_range = input_date_range || duration_list?.find(range => range.value === 'all_time');
const [from_date, setFrom] = React.useState(from ? toMoment(from).format('YYYY-MM-DD') : undefined);
const [to_date, setTo] = React.useState(to ? toMoment(to).format('YYYY-MM-DD') : undefined);
@@ -97,7 +97,7 @@ const CompositeCalendarMobile = React.memo(
const new_from = from_date || to_date || today;
const new_to = to_date || today;
- const new_date_range = Object.assign(selected_date_range, {
+ const new_date_range = Object.assign(selected_date_range as TInputDateRange, {
label: `${toMoment(new_from).format('DD MMM YYYY')} - ${toMoment(new_to).format('DD MMM YYYY')}`,
});
@@ -114,9 +114,9 @@ const CompositeCalendarMobile = React.memo(
};
const applyDateRange = () => {
- if (selected_date_range.onClick) {
+ if (selected_date_range?.onClick) {
selectDateRange(selected_date_range);
- } else if (selected_date_range.value === CUSTOM_KEY) {
+ } else if (selected_date_range?.value === CUSTOM_KEY) {
selectCustomDateRange();
}
setAppliedDateRange(selected_date_range);
@@ -166,7 +166,7 @@ const CompositeCalendarMobile = React.memo(
const onDateRangeChange = (_date_range: TInputDateRange) => {
setSelectedDateRange(
- duration_list.find(range => _date_range && range.value === _date_range.value) || _date_range
+ duration_list?.find(range => _date_range && range.value === _date_range.value) || _date_range
);
};
@@ -185,7 +185,7 @@ const CompositeCalendarMobile = React.memo(
icon={() => }
onClick={openDialog}
setCurrentFocus={setCurrentFocus}
- value={applied_date_range.label}
+ value={applied_date_range?.label}
/>
- {duration_list.map(duration => (
+ {duration_list?.map(duration => (
))}
@@ -216,7 +216,7 @@ const CompositeCalendarMobile = React.memo(
className='composite-calendar-modal__custom-radio'
value={CUSTOM_KEY}
label={localize('Custom')}
- selected_value={selected_date_range.value}
+ selected_value={selected_date_range?.value}
onChange={onDateRangeChange}
/>
diff --git a/packages/reports/src/Components/Form/CompositeCalendar/composite-calendar.tsx b/packages/reports/src/Components/Form/CompositeCalendar/composite-calendar.tsx
index 8523b9917dee..0a2611a578b1 100644
--- a/packages/reports/src/Components/Form/CompositeCalendar/composite-calendar.tsx
+++ b/packages/reports/src/Components/Form/CompositeCalendar/composite-calendar.tsx
@@ -3,18 +3,15 @@ import Loadable from 'react-loadable';
import { DesktopWrapper, InputField, MobileWrapper, useOnClickOutside } from '@deriv/components';
import { localize } from '@deriv/translations';
import { daysFromTodayTo, toMoment } from '@deriv/shared';
-import { connect } from 'Stores/connect';
-import type { TCoreStores } from '@deriv/stores/types';
import CompositeCalendarMobile from './composite-calendar-mobile';
import SideList from './side-list';
import CalendarIcon from './calendar-icon';
import TwoMonthPicker from './two-month-picker';
import moment from 'moment';
+import { observer, useStore } from '@deriv/stores';
type TCompositeCalendar = {
- current_focus: string;
onChange: (values: { to?: moment.Moment; from?: moment.Moment; is_batch?: boolean }) => void;
- setCurrentFocus: () => void;
to: number;
from: number;
};
@@ -34,8 +31,10 @@ const TwoMonthPickerLoadable = Loadable
= props => {
- const { current_focus, onChange, setCurrentFocus, to, from } = props;
+const CompositeCalendar = observer((props: TCompositeCalendar) => {
+ const { ui } = useStore();
+ const { current_focus, setCurrentFocus } = ui;
+ const { onChange, to, from } = props;
const [show_to, setShowTo] = React.useState(false);
const [show_from, setShowFrom] = React.useState(false);
@@ -111,7 +110,7 @@ const CompositeCalendar: React.FC = props => {
useOnClickOutside(
wrapper_ref,
- event => {
+ (event: React.MouseEvent) => {
event?.stopPropagation();
event?.preventDefault();
hideCalendar();
@@ -181,13 +180,8 @@ const CompositeCalendar: React.FC = props => {
);
-};
+});
CompositeCalendar.displayName = 'CompositeCalendar';
-export default React.memo(
- connect(({ ui }: TCoreStores) => ({
- current_focus: ui.current_focus,
- setCurrentFocus: ui.setCurrentFocus,
- }))(CompositeCalendar)
-);
+export default React.memo(CompositeCalendar);
diff --git a/packages/reports/src/Components/account-statistics.tsx b/packages/reports/src/Components/account-statistics.tsx
index 2a1b605c4e51..f731df75264c 100644
--- a/packages/reports/src/Components/account-statistics.tsx
+++ b/packages/reports/src/Components/account-statistics.tsx
@@ -1,17 +1,15 @@
import React from 'react';
import { MobileWrapper, Money, Text } from '@deriv/components';
import { localize } from '@deriv/translations';
-import { connect } from 'Stores/connect';
+import { observer, useStore } from '@deriv/stores';
+import { useReportsStore } from 'Stores/useReportsStores';
-type TAccountStatistics = {
- account_statistics: {
- total_withdrawals: number;
- total_deposits: number;
- };
- currency: string;
-};
+const AccountStatistics = observer(() => {
+ const { client } = useStore();
+ const { statement } = useReportsStore();
+ const { currency } = client;
+ const { account_statistics } = statement;
-const AccountStatistics = ({ account_statistics, currency }: TAccountStatistics) => {
return (
@@ -64,10 +62,6 @@ const AccountStatistics = ({ account_statistics, currency }: TAccountStatistics)
);
-};
+});
-// TODO: implement reports store TRootStore in types.ts
-export default connect(({ modules, client }: any) => ({
- account_statistics: modules.statement.account_statistics,
- currency: client.currency,
-}))(AccountStatistics);
+export default AccountStatistics;
diff --git a/packages/reports/src/Components/filter-component.tsx b/packages/reports/src/Components/filter-component.tsx
index 608c1e6de178..3910805d547d 100644
--- a/packages/reports/src/Components/filter-component.tsx
+++ b/packages/reports/src/Components/filter-component.tsx
@@ -1,33 +1,14 @@
import React from 'react';
import { FilterDropdown } from '@deriv/components';
import { localize } from '@deriv/translations';
-import { connect } from 'Stores/connect';
import CompositeCalendar from './Form/CompositeCalendar';
-import { TRootStore } from 'Stores/index';
+import { observer } from '@deriv/stores';
+import { useReportsStore } from 'Stores/useReportsStores';
-type TFilterComponent = {
- action_type: string;
- date_from: number;
- date_to: number;
- filtered_date_range: {
- duration: number;
- label: string;
- onClick?: () => void;
- value?: string;
- };
- handleDateChange: () => void;
- handleFilterChange: () => void;
- suffix_icon: string;
-};
+const FilterComponent = observer(() => {
+ const { statement } = useReportsStore();
+ const { action_type, date_from, date_to, handleFilterChange, handleDateChange } = statement;
-const FilterComponent = ({
- action_type,
- date_from,
- date_to,
- handleFilterChange,
- handleDateChange,
- filtered_date_range,
-}: TFilterComponent) => {
const filter_list = [
{
text: localize('All transactions'),
@@ -57,12 +38,7 @@ const FilterComponent = ({
return (
-
+
);
-};
+});
-export default connect(({ modules }: TRootStore) => ({
- action_type: modules.statement.action_type,
- data: modules.statement.data,
- date_from: modules.statement.date_from,
- date_to: modules.statement.date_to,
- filtered_date_range: modules.statement.filtered_date_range,
- handleDateChange: modules.statement.handleDateChange,
- handleFilterChange: modules.statement.handleFilterChange,
-}))(FilterComponent);
+export default FilterComponent;
diff --git a/packages/reports/src/Components/indicative-cell.tsx b/packages/reports/src/Components/indicative-cell.tsx
index fcf20ab2ccdf..dc422d878a53 100644
--- a/packages/reports/src/Components/indicative-cell.tsx
+++ b/packages/reports/src/Components/indicative-cell.tsx
@@ -1,27 +1,21 @@
import React from 'react';
import { Icon, Money, DesktopWrapper, ContractCard } from '@deriv/components';
import { getCardLabels, TContractInfo } from '@deriv/shared';
-import { connect } from 'Stores/connect';
-import { TRootStore } from 'Stores/index';
+import { observer, useStore } from '@deriv/stores';
type TIndicativeCell = {
amount: number;
contract_info: TContractInfo;
currency: string;
- status: string;
+ status?: string;
is_footer: boolean;
is_sell_requested: boolean;
- onClickSell: () => void;
};
-const IndicativeCell = ({
- amount,
- currency,
- contract_info,
- is_footer,
- onClickSell,
- is_sell_requested,
-}: TIndicativeCell) => {
+const IndicativeCell = observer((props: TIndicativeCell) => {
+ const { amount, contract_info, currency, is_footer, is_sell_requested, status } = props;
+ const { portfolio } = useStore();
+ const { onClickSell } = portfolio;
const [movement, setMovement] = React.useState(null);
const [amount_state, setAmountState] = React.useState(0);
@@ -49,14 +43,14 @@ const IndicativeCell = ({
contract_info={contract_info}
is_sell_requested={is_sell_requested}
getCardLabels={getCardLabels}
- onClickSell={onClickSell}
+ onClickSell={contract_id => {
+ if (contract_id) onClickSell(contract_id);
+ }}
/>
)}
);
-};
+});
-export default connect(({ portfolio }: TRootStore) => ({
- onClickSell: portfolio.onClickSell,
-}))(IndicativeCell);
+export default IndicativeCell;
diff --git a/packages/reports/src/Constants/data-table-constants.tsx b/packages/reports/src/Constants/data-table-constants.tsx
index 5bba1b5f59ee..75d732a41309 100644
--- a/packages/reports/src/Constants/data-table-constants.tsx
+++ b/packages/reports/src/Constants/data-table-constants.tsx
@@ -18,6 +18,7 @@ import MarketSymbolIconRow from '../Components/market-symbol-icon-row';
import ProfitLossCell from '../Components/profit_loss_cell';
import CurrencyWrapper from '../Components/currency-wrapper';
import { useStore } from '@deriv/stores';
+import moment from 'moment';
type TPortfolioStore = ReturnType
['portfolio'];
@@ -41,6 +42,7 @@ type TAccumulatorOpenPositionstemplateProps = Omit<
TMultiplierOpenPositionstemplateProps,
'onClickCancel' | 'server_time'
>;
+
type TMultiplierOpenPositionstemplateProps = Pick<
TPortfolioStore,
'getPositionById' | 'onClickCancel' | 'onClickSell'
@@ -565,4 +567,3 @@ export const getAccumulatorOpenPositionsColumnsTemplate = ({
},
},
];
-/* eslint-enable react/display-name, react/prop-types */
diff --git a/packages/reports/src/Containers/open-positions.tsx b/packages/reports/src/Containers/open-positions.tsx
index 1c70d2d59706..e5bf812a8a8d 100644
--- a/packages/reports/src/Containers/open-positions.tsx
+++ b/packages/reports/src/Containers/open-positions.tsx
@@ -29,7 +29,6 @@ import {
getGrowthRatePercentage,
getCardLabels,
toMoment,
- TContractStore,
} from '@deriv/shared';
import { localize, Localize } from '@deriv/translations';
import { ReportsTableRowLoader } from '../Components/Elements/ContentLoader';
@@ -42,52 +41,52 @@ import {
getMultiplierOpenPositionsColumnsTemplate,
} from 'Constants/data-table-constants';
import PlaceholderComponent from '../Components/placeholder-component';
-import { connect } from 'Stores/connect';
-import type { TRootStore } from 'Stores/index';
-import { TColIndex } from 'Types';
+import { observer, useStore } from '@deriv/stores';
+import { TColIndex, TUnsupportedContractType } from 'Types';
import moment from 'moment';
-type TPortfolioStore = TRootStore['portfolio'];
+type TRangeFloatZeroToOne = React.ComponentProps['value'];
+type TPortfolioStore = ReturnType['portfolio'];
type TDataList = React.ComponentProps;
type TDataListCell = React.ComponentProps;
type TRowRenderer = TDataList['rowRenderer'];
-type TMobileRowRenderer = {
- row?: TDataList['data_source'][number];
- is_footer?: boolean;
- columns_map?: Record;
- server_time?: moment.Moment;
- onClickCancel: (contract_id?: number) => void;
- onClickSell: (contract_id?: number) => void;
- measure?: () => void;
-};
-type TRangeFloatZeroToOne = React.ComponentProps['value'];
+
type TEmptyPlaceholderWrapper = React.PropsWithChildren<{
is_empty: boolean;
component_icon: string;
}>;
-const EmptyPlaceholderWrapper = ({ is_empty, component_icon, children }: TEmptyPlaceholderWrapper) => (
-
- {is_empty ? (
-
- ) : (
- children
- )}
-
-);
+type TUiStore = Pick<
+ ReturnType['ui'],
+ | 'addToast'
+ | 'current_focus'
+ | 'removeToast'
+ | 'setCurrentFocus'
+ | 'should_show_cancellation_warning'
+ | 'toggleCancellationWarning'
+ | 'toggleUnsupportedContractModal'
+>;
-type TOpenPositionsTable = Pick & {
+type TMobileRowRenderer = TUiStore & {
+ row?: TDataList['data_source'][0];
+ is_footer?: boolean;
+ columns_map: Record;
+ getContractById: ReturnType['contract_trade']['getContractById'];
+ server_time: moment.Moment;
+ onClickCancel: (contract_id?: number) => void;
+ onClickRemove: TPortfolioStore['removePositionById'];
+ onClickSell: (contract_id?: number) => void;
+ measure?: () => void;
+};
+
+type TOpenPositionsTable = {
className: string;
columns: Record[];
component_icon: string;
currency: string;
active_positions: TPortfolioStore['active_positions'];
is_loading: boolean;
+ getRowAction: TDataList['getRowAction'];
mobileRowRenderer: TRowRenderer;
preloaderCheck: (item: TTotals) => boolean;
row_size: number;
@@ -115,57 +114,24 @@ type TTotals = {
payout?: number;
};
-type TAddToastProps = {
- key?: string;
- content: string;
- timeout?: number;
- is_bottom?: boolean;
- type?: string;
-};
-
-type TOpenPositions = Pick<
- TPortfolioStore,
- | 'active_positions'
- | 'error'
- | 'getPositionById'
- | 'is_loading'
- | 'is_multiplier'
- | 'onClickCancel'
- | 'onClickSell'
- | 'onMount'
-> & {
+type TOpenPositions = {
component_icon: string;
- currency: string;
- is_accumulator: boolean;
- is_eu: boolean;
- NotificationMessages: () => JSX.Element;
- server_time: moment.Moment;
- addToast: (obj: TAddToastProps) => void;
- current_focus: string;
- onClickRemove: () => void;
- getContractById: (contract_id?: number) => TContractStore;
- removeToast: () => void;
- setCurrentFocus: () => void;
- should_show_cancellation_warning: boolean;
- toggleCancellationWarning: () => void;
- toggleUnsupportedContractModal: () => void;
};
-type TMobileRowRendererProps = Pick<
- TOpenPositions,
- | 'addToast'
- | 'current_focus'
- | 'getContractById'
- | 'onClickRemove'
- | 'removeToast'
- | 'setCurrentFocus'
- | 'should_show_cancellation_warning'
- | 'toggleCancellationWarning'
- | 'toggleUnsupportedContractModal'
-> &
- Omit & {
- columns_map: { [key: TColIndex]: undefined | TDataListCell['column'] };
- };
+const EmptyPlaceholderWrapper = ({ is_empty, component_icon, children }: TEmptyPlaceholderWrapper) => (
+
+ {is_empty ? (
+
+ ) : (
+ children
+ )}
+
+);
const MobileRowRenderer = ({
row = {},
@@ -176,7 +142,7 @@ const MobileRowRenderer = ({
onClickSell,
measure,
...props
-}: TMobileRowRendererProps) => {
+}: TMobileRowRenderer) => {
React.useEffect(() => {
if (!is_footer) {
measure?.();
@@ -204,8 +170,7 @@ const MobileRowRenderer = ({
);
}
- const { contract_info, contract_update, type, is_sell_requested } =
- row as TPortfolioStore['active_positions'][number];
+ const { contract_info, contract_update, type, is_sell_requested } = row as TPortfolioStore['active_positions'][0];
const { currency, status, date_expiry, date_start, tick_count, purchase_time } = contract_info;
const current_tick = tick_count ? getCurrentTick(contract_info) : null;
const turbos_duration_unit = tick_count ? 'ticks' : getDurationUnitText(getDurationPeriod(contract_info), true);
@@ -215,7 +180,7 @@ const MobileRowRenderer = ({
const progress_value = (getTimePercentage(server_time, date_start ?? 0, date_expiry ?? 0) /
100) as TRangeFloatZeroToOne;
- if (isMultiplierContract(type ?? '') || isAccumulatorContract(type)) {
+ if (isMultiplierContract(type) || isAccumulatorContract(type)) {
return (
) : (
-
+
)}
@@ -344,10 +309,7 @@ const getRowAction: TDataList['getRowAction'] = row_obj =>
- ]?.name,
+ trade_type_name: getUnsupportedContracts()[row_obj.type as TUnsupportedContractType]?.name,
}}
/>
),
@@ -414,9 +376,10 @@ const getOpenPositionsTotals = (
let profit = 0;
active_positions_filtered?.forEach(({ contract_info }) => {
- buy_price += +(contract_info.buy_price ?? 0);
- bid_price += +(contract_info.bid_price ?? 0);
- take_profit += contract_info.limit_order?.take_profit?.order_amount ?? 0;
+ buy_price += Number(contract_info.buy_price);
+ bid_price += Number(contract_info.bid_price);
+ if (contract_info.limit_order?.take_profit?.order_amount)
+ take_profit += contract_info.limit_order.take_profit.order_amount;
if (contract_info) {
profit += getTotalProfit(contract_info);
}
@@ -456,23 +419,49 @@ const getOpenPositionsTotals = (
return totals;
};
-const OpenPositions = ({
- active_positions,
- component_icon,
- currency,
- error,
- getPositionById,
- is_accumulator,
- is_eu: hide_accu_in_dropdown,
- is_loading,
- is_multiplier,
- NotificationMessages,
- onClickCancel,
- onClickSell,
- onMount,
- server_time,
- ...props
-}: TOpenPositions) => {
+const OpenPositions = observer(({ component_icon, ...props }: TOpenPositions) => {
+ const { portfolio, client, ui, common, contract_trade } = useStore();
+ const {
+ active_positions,
+ error,
+ getPositionById,
+ is_accumulator,
+ is_loading,
+ is_multiplier,
+ onClickCancel,
+ onClickSell,
+ onMount,
+ removePositionById: onClickRemove,
+ } = portfolio;
+ const { currency, is_eu: hide_accu_in_dropdown } = client;
+ const {
+ notification_messages_ui: NotificationMessages,
+ addToast,
+ current_focus,
+ is_mobile,
+ removeToast,
+ setCurrentFocus,
+ should_show_cancellation_warning,
+ toggleCancellationWarning,
+ toggleUnsupportedContractModal,
+ } = ui;
+ const { server_time } = common;
+ const { getContractById } = contract_trade;
+
+ const store_props = {
+ onClickRemove,
+ NotificationMessages,
+ addToast,
+ current_focus,
+ is_mobile,
+ removeToast,
+ setCurrentFocus,
+ should_show_cancellation_warning,
+ toggleCancellationWarning,
+ toggleUnsupportedContractModal,
+ getContractById,
+ };
+
const [has_accumulator_contract, setHasAccumulatorContract] = React.useState(false);
const [has_multiplier_contract, setHasMultiplierContract] = React.useState(false);
const previous_active_positions = usePrevious(active_positions);
@@ -498,7 +487,7 @@ const OpenPositions = ({
if (is_accumulator_selected)
return (
isAccumulatorContract(contract_info.contract_type) &&
- (`${getGrowthRatePercentage(contract_info.growth_rate || 0)}%` === accumulator_rate ||
+ (`${getGrowthRatePercentage(Number(contract_info.growth_rate))}%` === accumulator_rate ||
!accumulator_rate.includes('%'))
);
return (
@@ -547,7 +536,7 @@ const OpenPositions = ({
if (error) return {error}
;
const getColumns = () => {
- if (is_multiplier_selected) {
+ if (is_multiplier_selected && server_time) {
return getMultiplierOpenPositionsColumnsTemplate({
currency,
onClickCancel,
@@ -570,17 +559,18 @@ const OpenPositions = ({
const columns_map = {} as Record;
columns.forEach(e => {
- columns_map[e.col_index] = e as TDataListCell['column'];
+ columns_map[e.col_index as TColIndex] = e as TDataListCell['column'];
});
const mobileRowRenderer: TRowRenderer = args => (
);
@@ -688,31 +678,6 @@ const OpenPositions = ({
{getOpenPositionsTable()}
);
-};
+});
-export default withRouter(
- connect(({ client, common, ui, portfolio, contract_trade }: TRootStore) => ({
- active_positions: portfolio.active_positions,
- currency: client.currency,
- is_eu: client.is_eu,
- error: portfolio.error,
- getPositionById: portfolio.getPositionById,
- is_accumulator: portfolio.is_accumulator,
- is_loading: portfolio.is_loading,
- is_multiplier: portfolio.is_multiplier,
- NotificationMessages: ui.notification_messages_ui,
- onClickCancel: portfolio.onClickCancel,
- onClickSell: portfolio.onClickSell,
- onMount: portfolio.onMount,
- server_time: common.server_time,
- addToast: ui.addToast,
- current_focus: ui.current_focus,
- onClickRemove: portfolio.removePositionById,
- getContractById: contract_trade.getContractById,
- removeToast: ui.removeToast,
- setCurrentFocus: ui.setCurrentFocus,
- should_show_cancellation_warning: ui.should_show_cancellation_warning,
- toggleCancellationWarning: ui.toggleCancellationWarning,
- toggleUnsupportedContractModal: ui.toggleUnsupportedContractModal,
- }))(OpenPositions)
-);
+export default withRouter(OpenPositions);
diff --git a/packages/reports/src/Containers/profit-table.tsx b/packages/reports/src/Containers/profit-table.tsx
index 5e1d6a626160..d250abb9555f 100644
--- a/packages/reports/src/Containers/profit-table.tsx
+++ b/packages/reports/src/Containers/profit-table.tsx
@@ -12,46 +12,29 @@ import {
import { localize, Localize } from '@deriv/translations';
import { ReportsTableRowLoader } from '../Components/Elements/ContentLoader';
import CompositeCalendar from '../Components/Form/CompositeCalendar';
-import {
- TInputDateRange,
- TColIndex,
- TColumnTemplateType,
- TSupportedContractType,
- TUnsupportedContractType,
-} from 'Types';
-
-import { connect } from 'Stores/connect';
+import { TSupportedContractType, TUnsupportedContractType } from 'Types';
import EmptyTradeHistoryMessage from '../Components/empty-trade-history-message';
import PlaceholderComponent from '../Components/placeholder-component';
import { ReportsMeta } from '../Components/reports-meta';
import { getProfitTableColumnsTemplate } from 'Constants/data-table-constants';
-import { TRootStore } from 'Stores/index';
-import moment from 'moment/moment';
+import { observer, useStore } from '@deriv/stores';
+import { useReportsStore } from 'Stores/useReportsStores';
type TProfitTable = {
component_icon: string;
- currency: string;
- data: Array<{ [key: string]: string }>;
- date_from: number;
- date_to: number;
- error: string;
- filtered_date_range: TInputDateRange;
- is_empty: boolean;
- is_loading: boolean;
- is_switching: boolean;
- handleDateChange: (values: { [key: string]: moment.Moment }) => void;
- handleScroll: (ev: React.UIEvent) => void;
- has_selected_date: boolean;
- onMount: VoidFunction;
- onUnmount: VoidFunction;
- totals: React.ReactNode;
};
-const getRowAction = (row_obj: { [key: string]: string }) => {
- const contract_type = extractInfoFromShortcode(row_obj?.shortcode)?.category?.toString().toUpperCase();
+type TDataListCell = React.ComponentProps;
+
+type TGetProfitTableColumnsTemplate = ReturnType;
+
+const getRowAction = (row_obj: { [key: string]: unknown }) => {
+ const contract_type = extractInfoFromShortcode(row_obj?.shortcode as string)
+ ?.category?.toString()
+ .toUpperCase();
return getSupportedContracts()[contract_type as TSupportedContractType] &&
- !isForwardStarting(row_obj.shortcode, +row_obj.purchase_time_unix)
- ? getContractPath(+row_obj.contract_id)
+ !isForwardStarting(row_obj.shortcode as string, Number(row_obj.purchase_time_unix))
+ ? getContractPath(Number(row_obj.contract_id))
: {
component: (
{
};
};
-const ProfitTable = ({
- component_icon,
- currency,
- data,
- date_from,
- date_to,
- error,
- filtered_date_range,
- is_empty,
- is_loading,
- is_switching,
- handleDateChange,
- handleScroll,
- has_selected_date,
- onMount,
- onUnmount,
- totals,
-}: TProfitTable) => {
+const ProfitTable = observer(({ component_icon }: TProfitTable) => {
+ const { client } = useStore();
+ const { profit_table } = useReportsStore();
+ const { currency, is_switching } = client;
+ const {
+ data,
+ date_from,
+ date_to,
+ error,
+ is_empty,
+ is_loading,
+ handleDateChange,
+ handleScroll,
+ has_selected_date,
+ onMount,
+ onUnmount,
+ totals,
+ } = profit_table;
+
React.useEffect(() => {
onMount();
return () => {
@@ -92,33 +76,31 @@ const ProfitTable = ({
if (error) return {error}
;
- const filter_component = (
-
- );
+ const filter_component = ;
- const columns = getProfitTableColumnsTemplate(currency, data.length);
+ const columns: TGetProfitTableColumnsTemplate = getProfitTableColumnsTemplate(currency, data.length);
- const columns_map = Object.fromEntries(columns.map(column => [column.col_index, column])) as {
- [key in TColIndex]: TColumnTemplateType;
- };
+ const columns_map = Object.fromEntries(columns.map(column => [column.col_index, column])) as Record<
+ TGetProfitTableColumnsTemplate[number]['col_index'],
+ TGetProfitTableColumnsTemplate[number]
+ >;
- const mobileRowRenderer = ({ row, is_footer }: { row: any; is_footer?: boolean }) => {
- const duration_type = /^(MULTUP|MULTDOWN)/.test(row.shortcode) ? '' : row.duration_type;
+ const mobileRowRenderer: React.ComponentProps['rowRenderer'] = ({ row, is_footer }) => {
+ const duration_type = /^(MULTUP|MULTDOWN)/.test(row?.shortcode) ? '' : row?.duration_type;
const duration_classname = duration_type ? `duration-type__${duration_type.toLowerCase()}` : '';
if (is_footer) {
return (
-
+
@@ -128,26 +110,38 @@ const ProfitTable = ({
return (
<>
-
+
{localize(duration_type)}
-
-
+
+
-
-
+
+
-
-
+
+
-
+
>
);
@@ -181,7 +175,6 @@ const ProfitTable = ({
columns={columns}
onScroll={handleScroll}
footer={totals}
- is_empty={is_empty}
getRowAction={getRowAction}
getRowSize={() => 63}
content_loader={ReportsTableRowLoader}
@@ -208,22 +201,6 @@ const ProfitTable = ({
)}
);
-};
+});
-export default connect(({ modules, client }: TRootStore) => ({
- currency: client.currency,
- data: modules.profit_table.data,
- date_from: modules.profit_table.date_from,
- date_to: modules.profit_table.date_to,
- error: modules.profit_table.error,
- filtered_date_range: modules.profit_table.filtered_date_range,
- is_empty: modules.profit_table.is_empty,
- is_loading: modules.profit_table.is_loading,
- is_switching: client.is_switching,
- handleDateChange: modules.profit_table.handleDateChange,
- handleScroll: modules.profit_table.handleScroll,
- has_selected_date: modules.profit_table.has_selected_date,
- onMount: modules.profit_table.onMount,
- onUnmount: modules.profit_table.onUnmount,
- totals: modules.profit_table.totals,
-}))(withRouter(ProfitTable));
+export default withRouter(ProfitTable);
diff --git a/packages/reports/src/Containers/progress-slider-stream.tsx b/packages/reports/src/Containers/progress-slider-stream.tsx
index 226c30f5e5cf..bfc6ed70f615 100644
--- a/packages/reports/src/Containers/progress-slider-stream.tsx
+++ b/packages/reports/src/Containers/progress-slider-stream.tsx
@@ -1,22 +1,24 @@
import React from 'react';
import { ProgressSlider } from '@deriv/components';
import { getCurrentTick, TContractInfo, getCardLabels } from '@deriv/shared';
-import { connect } from 'Stores/connect';
-import moment from 'moment';
-import { TRootStore } from 'Stores/index';
+import { observer, useStore } from '@deriv/stores';
type TProgressSliderStream = {
contract_info: Required;
- is_loading: boolean;
- server_time: moment.Moment;
};
-const ProgressSliderStream = ({ contract_info, is_loading, server_time }: TProgressSliderStream) => {
+const ProgressSliderStream = observer(({ contract_info }: TProgressSliderStream) => {
+ const { common, portfolio } = useStore();
+ const { server_time } = common;
+ const { is_loading } = portfolio;
+
if (!contract_info) {
return ;
}
const current_tick = contract_info.tick_count && getCurrentTick(contract_info);
+ if (!server_time) return null;
+
return (
);
-};
+});
-export default connect(({ common, portfolio }: TRootStore) => ({
- is_loading: portfolio.is_loading,
- server_time: common.server_time,
-}))(ProgressSliderStream);
+export default ProgressSliderStream;
diff --git a/packages/reports/src/Containers/routes.tsx b/packages/reports/src/Containers/routes.tsx
index ab4b8d04d70b..61c0b535cc17 100644
--- a/packages/reports/src/Containers/routes.tsx
+++ b/packages/reports/src/Containers/routes.tsx
@@ -1,26 +1,19 @@
-import React from 'react';
+import { observer, useStore } from '@deriv/stores';
import { withRouter } from 'react-router';
+import React from 'react';
import BinaryRoutes from 'Components/Routes';
-import { connect } from 'Stores/connect';
import ErrorComponent from 'Components/Errors';
-import { TRootStore } from 'Stores/index';
import { TRoutes } from 'Types';
-const Routes = ({ error, has_error, is_logged_in, is_logging_in, passthrough }: TRoutes) => {
+const Routes = observer(({ passthrough }: TRoutes) => {
+ const { client, common } = useStore();
+ const { is_logged_in, is_logging_in } = client;
+ const { error, has_error } = common;
if (has_error) {
return ;
}
return ;
-};
+});
-// need to wrap withRouter around connect
-// to prevent updates on from being blocked
-export default withRouter(
- connect(({ client, common }: TRootStore) => ({
- is_logged_in: client.is_logged_in,
- is_logging_in: client.is_logging_in,
- error: common.error,
- has_error: common.has_error,
- }))(Routes)
-);
+export default withRouter(Routes);
diff --git a/packages/reports/src/Containers/statement.tsx b/packages/reports/src/Containers/statement.tsx
index 5e0c2de1ed54..481c01bcb523 100644
--- a/packages/reports/src/Containers/statement.tsx
+++ b/packages/reports/src/Containers/statement.tsx
@@ -10,37 +10,21 @@ import {
} from '@deriv/shared';
import { localize, Localize } from '@deriv/translations';
import { ReportsTableRowLoader } from '../Components/Elements/ContentLoader';
-import { connect } from 'Stores/connect';
import { getStatementTableColumnsTemplate } from '../Constants/data-table-constants';
import PlaceholderComponent from '../Components/placeholder-component';
import AccountStatistics from '../Components/account-statistics';
import FilterComponent from '../Components/filter-component';
import { ReportsMeta } from '../Components/reports-meta';
import EmptyTradeHistoryMessage from '../Components/empty-trade-history-message';
-import { TRootStore } from 'Stores/index';
+import { observer, useStore } from '@deriv/stores';
+import { useReportsStore } from 'Stores/useReportsStores';
+import { TSupportedContractType, TUnsupportedContractType } from 'Types';
+import { TSource } from '@deriv/components/src/components/data-table/data-table';
+import { TRow } from '@deriv/components/src/components/types/common.types';
type TGetStatementTableColumnsTemplate = ReturnType;
type TColIndex = 'icon' | 'refid' | 'currency' | 'date' | 'action_type' | 'amount' | 'balance';
-type TFormatStatementTransaction = {
- action: string;
- date: string;
- display_name: string;
- refid: number;
- payout: string;
- amount: string;
- balance: string;
- desc: string;
- id: number;
- app_id: number;
- shortcode: string;
- action_type: string;
- purchase_time: number;
- transaction_time: number;
- withdrawal_details: string;
- longcode: string;
-};
-
type TAction =
| {
message?: string;
@@ -49,26 +33,7 @@ type TAction =
| string;
type TStatement = {
- action_type: string;
- account_statistics: React.ComponentProps['account_statistics'];
component_icon: string;
- currency: string;
- data: TFormatStatementTransaction[];
- date_from: number | null;
- date_to: number | null;
- error: string;
- filtered_date_range: React.ComponentProps['filtered_date_range'];
- handleDateChange: () => void;
- handleFilterChange: () => void;
- handleScroll: () => void;
- has_selected_date: boolean;
- is_empty: boolean;
- is_loading: boolean;
- is_mx_mlt: boolean;
- is_switching: boolean;
- is_virtual: boolean;
- onMount: () => void;
- onUnmount: () => void;
};
type TDetailsComponent = {
@@ -76,6 +41,9 @@ type TDetailsComponent = {
action_type: string;
};
+type TDataList = React.ComponentProps;
+type TDataListCell = React.ComponentProps;
+
const DetailsComponent = ({ message = '', action_type = '' }: TDetailsComponent) => {
const address_hash_match = /:\s([0-9a-zA-Z]+.{25,28})/gm.exec(message.split(/,\s/)[0]);
const address_hash = address_hash_match?.[1];
@@ -113,12 +81,14 @@ const DetailsComponent = ({ message = '', action_type = '' }: TDetailsComponent)
);
};
-const getRowAction = (row_obj: TFormatStatementTransaction) => {
+type TGetRowAction = TDataList['getRowAction'] | React.ComponentProps['getRowAction'];
+
+const getRowAction: TGetRowAction = (row_obj: TSource | TRow) => {
let action: TAction = {};
if (row_obj.id && ['buy', 'sell'].includes(row_obj.action_type)) {
- const contract_type = extractInfoFromShortcode(row_obj.shortcode).category.toUpperCase();
+ const contract_type = extractInfoFromShortcode(row_obj.shortcode)?.category?.toUpperCase();
action =
- getSupportedContracts()[contract_type] &&
+ getSupportedContracts()[contract_type as TSupportedContractType] &&
!isForwardStarting(row_obj.shortcode, row_obj.purchase_time || row_obj.transaction_time)
? getContractPath(row_obj.id)
: {
@@ -127,7 +97,8 @@ const getRowAction = (row_obj: TFormatStatementTransaction) => {
),
@@ -156,28 +127,13 @@ const getRowAction = (row_obj: TFormatStatementTransaction) => {
return action;
};
-const Statement = ({
- account_statistics,
- action_type,
- component_icon,
- currency,
- data,
- date_from,
- date_to,
- error,
- filtered_date_range,
- handleDateChange,
- handleFilterChange,
- handleScroll,
- has_selected_date,
- is_empty,
- is_loading,
- is_mx_mlt,
- is_switching,
- is_virtual,
- onMount,
- onUnmount,
-}: TStatement) => {
+const Statement = observer(({ component_icon }: TStatement) => {
+ const { client } = useStore();
+ const { statement } = useReportsStore();
+ const { currency, standpoint, is_switching, is_virtual } = client;
+ const { data, error, handleScroll, has_selected_date, is_empty, is_loading, onMount, onUnmount } = statement;
+ const is_mx_mlt = standpoint.iom || standpoint.malta;
+
React.useEffect(() => {
onMount();
return () => {
@@ -195,22 +151,41 @@ const Statement = ({
}, {} as Record);
// TODO: Export type instead of any from 'DataList' component when it migrates to tsx
- const mobileRowRenderer = ({ row, passthrough }: any) => (
+ const mobileRowRenderer = ({
+ row,
+ passthrough,
+ }: Pick[0], 'row' | 'passthrough'>) => (
-
-
+
+
-
-
+
+
-
-
+
+
-
+
);
@@ -219,27 +194,15 @@ const Statement = ({
- }
+ filter_component={}
is_statement
- optional_component={
- !is_switching &&
- is_mx_mlt &&
- }
+ optional_component={!is_switching && is_mx_mlt && }
/>
{is_switching ? (
) : (
- {data.length === 0 || is_empty ? (
+ {data?.length === 0 || is_empty ? (
getRowAction(row)}
+ getRowAction={getRowAction}
onScroll={handleScroll}
passthrough={{
- isTopUp: (item: TFormatStatementTransaction) =>
- is_virtual && item.action === 'Deposit',
+ isTopUp: (item: { action?: string }) => is_virtual && item.action === 'Deposit',
}}
>
@@ -278,8 +240,7 @@ const Statement = ({
rowRenderer={mobileRowRenderer}
row_gap={8}
passthrough={{
- isTopUp: (item: TFormatStatementTransaction) =>
- is_virtual && item.action === 'Deposit',
+ isTopUp: (item: { action?: string }) => is_virtual && item.action === 'Deposit',
}}
>
@@ -291,28 +252,6 @@ const Statement = ({
)}
);
-};
+});
-export default withRouter(
- connect(({ modules, client }: TRootStore) => ({
- action_type: modules.statement.action_type,
- account_statistics: modules.statement.account_statistics,
- currency: client.currency,
- data: modules.statement.data,
- date_from: modules.statement.date_from,
- date_to: modules.statement.date_to,
- error: modules.statement.error,
- filtered_date_range: modules.statement.filtered_date_range,
- handleDateChange: modules.statement.handleDateChange,
- handleFilterChange: modules.statement.handleFilterChange,
- handleScroll: modules.statement.handleScroll,
- has_selected_date: modules.statement.has_selected_date,
- is_empty: modules.statement.is_empty,
- is_loading: modules.statement.is_loading,
- is_mx_mlt: client.standpoint.iom || client.standpoint.malta,
- is_switching: client.is_switching,
- is_virtual: client.is_virtual,
- onMount: modules.statement.onMount,
- onUnmount: modules.statement.onUnmount,
- }))(Statement)
-);
+export default withRouter(Statement);
diff --git a/packages/reports/src/Stores/connect.js b/packages/reports/src/Stores/connect.js
deleted file mode 100644
index 4ef42c8d18b6..000000000000
--- a/packages/reports/src/Stores/connect.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useObserver } from 'mobx-react';
-import React from 'react';
-
-const isClassComponent = Component =>
- !!(typeof Component === 'function' && Component.prototype && Component.prototype.isReactComponent);
-
-export const MobxContent = React.createContext(null);
-
-function injectStorePropsToComponent(propsToSelectFn, BaseComponent) {
- const Component = own_props => {
- const store = React.useContext(MobxContent);
-
- let ObservedComponent = BaseComponent;
-
- if (isClassComponent(BaseComponent)) {
- const FunctionalWrapperComponent = props => ;
- ObservedComponent = FunctionalWrapperComponent;
- }
-
- return useObserver(() => ObservedComponent({ ...own_props, ...propsToSelectFn(store, own_props) }));
- };
-
- Component.displayName = BaseComponent.name;
- return Component;
-}
-
-export const MobxContentProvider = ({ store, children }) => {
- return {children};
-};
-
-export const connect = propsToSelectFn => Component => injectStorePropsToComponent(propsToSelectFn, Component);
diff --git a/packages/reports/src/Stores/index.ts b/packages/reports/src/Stores/index.ts
deleted file mode 100644
index 08806f1df4e5..000000000000
--- a/packages/reports/src/Stores/index.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import ModulesStore from './Modules';
-import ProfitTableStore from './Modules/Profit/profit-store';
-import StatementStore from './Modules/Statement/statement-store';
-import type { TCoreStores } from '@deriv/stores/types';
-
-export type TRootStore = TCoreStores & {
- modules: {
- profit_table: ProfitTableStore;
- statement: StatementStore;
- };
-};
-
-export default class RootStore {
- client: TCoreStores['client'];
- common: TCoreStores['common'];
- modules: ModulesStore;
- ui: TCoreStores['ui'];
- gtm: unknown;
- pushwoosh: unknown;
- notifications: TCoreStores['notifications'];
- contract_replay: unknown;
- contract_trade: TCoreStores['contract_trade'];
- portfolio: TCoreStores['portfolio'];
- chart_barrier_store: unknown;
- active_symbols: unknown;
-
- constructor(core_store: TCoreStores) {
- this.client = core_store.client;
- this.common = core_store.common;
- this.modules = new ModulesStore(this);
- this.ui = core_store.ui;
- this.gtm = core_store.gtm;
- this.pushwoosh = core_store.pushwoosh;
- this.notifications = core_store.notifications;
- this.contract_replay = core_store.contract_replay;
- this.contract_trade = core_store.contract_trade;
- this.portfolio = core_store.portfolio;
- this.chart_barrier_store = core_store.chart_barrier_store;
- this.active_symbols = core_store.active_symbols;
- }
-}
diff --git a/packages/reports/src/Stores/useReportsStores.tsx b/packages/reports/src/Stores/useReportsStores.tsx
new file mode 100644
index 000000000000..1e4e6bf76950
--- /dev/null
+++ b/packages/reports/src/Stores/useReportsStores.tsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import { useStore } from '@deriv/stores';
+import ProfitStores from './Modules/Profit/profit-store';
+import StatementStores from './Modules/Statement/statement-store';
+
+type TOverrideProfitStore = Omit & {
+ date_from: number;
+ data: { [key: string]: string }[];
+ totals: { [key: string]: unknown };
+};
+
+type TOverrideStatementStore = Omit<
+ StatementStores,
+ | 'account_statistics'
+ | 'action_type'
+ | 'data'
+ | 'date_from'
+ | 'date_to'
+ | 'filtered_date_range'
+ | 'handleDateChange'
+ | 'handleFilterChange'
+ | 'handleScroll'
+ | 'suffix_icon'
+> & {
+ account_statistics: { total_deposits: number; total_withdrawals: number };
+ action_type: string;
+ data: { [key: string]: string }[];
+ date_from: number;
+ date_to: number;
+ filtered_date_range: {
+ duration: number;
+ label: string;
+ onClick?: () => void;
+ value?: string;
+ };
+ handleDateChange: () => void;
+ handleFilterChange: () => void;
+ handleScroll: React.UIEventHandler;
+ suffix_icon: string;
+};
+
+type TReportsStore = {
+ profit_table: TOverrideProfitStore;
+ statement: TOverrideStatementStore;
+};
+
+const ReportsStoreContext = React.createContext(null);
+
+export const ReportsStoreProvider = ({ children }: React.PropsWithChildren) => {
+ const root_store = useStore();
+ const memoizedValue = React.useMemo(() => {
+ return {
+ profit_table: new ProfitStores({ root_store }),
+ statement: new StatementStores({ root_store }),
+ } as unknown as TReportsStore;
+ }, [root_store]);
+
+ return {children};
+};
+
+export const useReportsStore = () => {
+ const store = React.useContext(ReportsStoreContext);
+
+ if (!store) {
+ throw new Error('useReportsStore must be used within ReportsStoreProvider');
+ }
+
+ return store;
+};
diff --git a/packages/reports/src/Types/common-prop.type.ts b/packages/reports/src/Types/common-prop.type.ts
index 7327d126599c..9fd30234e7ed 100644
--- a/packages/reports/src/Types/common-prop.type.ts
+++ b/packages/reports/src/Types/common-prop.type.ts
@@ -1,6 +1,6 @@
import React from 'react';
import { Redirect } from 'react-router-dom';
-import { TRootStore } from 'Stores/index';
+import { TCoreStores } from '@deriv/stores/types';
import {
getMultiplierOpenPositionsColumnsTemplate,
getOpenPositionsColumnsTemplate,
@@ -11,7 +11,7 @@ import {
import { getSupportedContracts, getUnsupportedContracts } from '@deriv/shared';
export type TPassthrough = {
- root_store: TRootStore;
+ root_store: TCoreStores;
WS: Record;
};
@@ -34,11 +34,11 @@ export type TRoute = {
};
export type TErrorComponent = {
- header: string;
+ header: string | JSX.Element;
is_dialog: boolean;
message: React.ReactElement | string;
redirect_label: string;
- redirectOnClick: () => void;
+ redirectOnClick: (() => void) | null;
should_show_refresh: boolean;
type: string;
};
diff --git a/packages/reports/src/_common/base/server_time.js b/packages/reports/src/_common/base/server_time.js
deleted file mode 100644
index b639380b27a5..000000000000
--- a/packages/reports/src/_common/base/server_time.js
+++ /dev/null
@@ -1,25 +0,0 @@
-const PromiseClass = require('../utility').PromiseClass;
-
-const ServerTime = (() => {
- let clock_started = false;
- const pending = new PromiseClass();
- let common_store;
-
- const init = store => {
- if (!clock_started) {
- common_store = store;
- pending.resolve(common_store.server_time);
- clock_started = true;
- }
- };
-
- const get = () => (clock_started && common_store.server_time ? common_store.server_time.clone() : undefined);
-
- return {
- init,
- get,
- timePromise: () => (clock_started ? Promise.resolve(common_store.server_time) : pending.promise),
- };
-})();
-
-module.exports = ServerTime;
diff --git a/packages/reports/src/_common/utility.js b/packages/reports/src/_common/utility.js
index 5c20dc5c33e0..17103900f516 100644
--- a/packages/reports/src/_common/utility.js
+++ b/packages/reports/src/_common/utility.js
@@ -6,47 +6,6 @@ const template = (string, content) => {
return string.replace(/\[_(\d+)]/g, (s, index) => to_replace[+index - 1]);
};
-/**
- * Creates a DOM element and adds any attributes to it.
- *
- * @param {String} tag_name: the tag to create, e.g. 'div', 'a', etc
- * @param {Object} attributes: all the attributes to assign, e.g. { id: '...', class: '...', html: '...', ... }
- * @return the created DOM element
- */
-const createElement = (tag_name, attributes = {}) => {
- const el = document.createElement(tag_name);
- Object.keys(attributes).forEach(attr => {
- const value = attributes[attr];
- if (attr === 'text') {
- el.textContent = value;
- } else if (attr === 'html') {
- el.html(value);
- } else {
- el.setAttribute(attr, value);
- }
- });
- return el;
-};
-
-let static_hash;
-const getStaticHash = () => {
- static_hash =
- static_hash || (document.querySelector('script[src*="main"]').getAttribute('src') || '').split('.')[1];
- return static_hash;
-};
-
-class PromiseClass {
- constructor() {
- this.promise = new Promise((resolve, reject) => {
- this.reject = reject;
- this.resolve = resolve;
- });
- }
-}
-
module.exports = {
template,
- createElement,
- getStaticHash,
- PromiseClass,
};
diff --git a/packages/reports/src/app.tsx b/packages/reports/src/app.tsx
index 3d3298d62311..fa9f31db13d0 100644
--- a/packages/reports/src/app.tsx
+++ b/packages/reports/src/app.tsx
@@ -1,27 +1,20 @@
import React from 'react';
import Routes from 'Containers/routes';
-import { MobxContentProvider } from 'Stores/connect';
-import { StoreProvider } from '@deriv/stores';
+import ReportsProviders from './reports-providers';
import 'Sass/app.scss';
-import initStore from './init-store';
import type { TCoreStores } from '@deriv/stores/types';
type TAppProps = {
passthrough: {
root_store: TCoreStores;
- WS: unknown;
};
};
const App = ({ passthrough }: TAppProps) => {
- const root_store = initStore(passthrough.root_store, passthrough.WS);
-
return (
-
-
-
-
-
+
+
+
);
};
diff --git a/packages/reports/src/init-store.js b/packages/reports/src/init-store.js
deleted file mode 100644
index f6ad9f411595..000000000000
--- a/packages/reports/src/init-store.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { configure } from 'mobx';
-import RootStore from 'Stores';
-import { setWebsocket } from '@deriv/shared';
-import ServerTime from '_common/base/server_time';
-
-configure({ enforceActions: 'observed' });
-
-let root_store;
-
-const initStore = (core_store, websocket) => {
- if (root_store) return root_store;
-
- ServerTime.init(core_store.common);
- setWebsocket(websocket);
- root_store = new RootStore(core_store);
-
- return root_store;
-};
-
-export default initStore;
diff --git a/packages/reports/src/reports-providers.tsx b/packages/reports/src/reports-providers.tsx
new file mode 100644
index 000000000000..cb5dc0488479
--- /dev/null
+++ b/packages/reports/src/reports-providers.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { StoreProvider } from '@deriv/stores';
+import { ReportsStoreProvider } from 'Stores/useReportsStores';
+import type { TCoreStores } from '@deriv/stores/types';
+
+export const ReportsProviders = ({ children, store }: React.PropsWithChildren<{ store: TCoreStores }>) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default ReportsProviders;
diff --git a/packages/stores/src/mockStore.ts b/packages/stores/src/mockStore.ts
index 01aa244cbce4..5f2ac3b5acdc 100644
--- a/packages/stores/src/mockStore.ts
+++ b/packages/stores/src/mockStore.ts
@@ -2,6 +2,18 @@ import merge from 'lodash.merge';
import type { TStores } from '../types';
const mock = (): TStores & { is_mock: boolean } => {
+ const common_store_error = {
+ app_routing_history: [],
+ header: '',
+ message: '',
+ type: '',
+ redirect_label: '',
+ redirect_to: '',
+ should_clear_error_on_click: false,
+ should_show_refresh: false,
+ redirectOnClick: jest.fn(),
+ setError: jest.fn(),
+ };
return {
is_mock: true,
client: {
@@ -105,6 +117,7 @@ const mock = (): TStores & { is_mock: boolean } => {
is_united_kingdom: false,
},
currency: '',
+ currencies_list: [{ text: '', value: '', has_tool_tip: false }],
current_currency_type: '',
current_fiat_currency: '',
cfd_score: 0,
@@ -255,19 +268,7 @@ const mock = (): TStores & { is_mock: boolean } => {
setPrevAccountType: jest.fn(),
},
common: {
- error: {
- app_routing_history: [],
- header: '',
- message: '',
- type: '',
- redirect_label: '',
- redirect_to: '',
- should_clear_error_on_click: false,
- should_show_refresh: false,
- redirectOnClick: jest.fn(),
- setError: jest.fn(),
- },
- services_error: {},
+ error: common_store_error,
current_language: 'EN',
isCurrentLanguage: jest.fn(),
is_from_derivgo: false,
@@ -278,6 +279,7 @@ const mock = (): TStores & { is_mock: boolean } => {
changeCurrentLanguage: jest.fn(),
changeSelectedLanguage: jest.fn(),
is_network_online: false,
+ services_error: {},
server_time: undefined,
is_language_changing: false,
is_socket_opened: false,
@@ -299,8 +301,6 @@ const mock = (): TStores & { is_mock: boolean } => {
is_closing_create_real_account_modal: false,
is_dark_mode_on: false,
is_language_settings_modal_on: false,
- is_unsupported_contract_modal_visible: false,
- has_only_forward_starting_contracts: false,
header_extension: null,
is_link_expired_modal_visible: false,
is_mobile: false,
@@ -308,6 +308,7 @@ const mock = (): TStores & { is_mock: boolean } => {
is_reports_visible: false,
is_route_modal_on: false,
is_services_error_visible: false,
+ is_unsupported_contract_modal_visible: false,
disableApp: jest.fn(),
enableApp: jest.fn(),
setCurrentFocus: jest.fn(),
@@ -317,13 +318,14 @@ const mock = (): TStores & { is_mock: boolean } => {
togglePositionsDrawer: jest.fn(),
setDarkMode: jest.fn(),
setReportsTabIndex: jest.fn(),
+ has_only_forward_starting_contracts: false,
has_real_account_signup_ended: false,
notification_messages_ui: jest.fn(),
openRealAccountSignup: jest.fn(),
+ setHasOnlyForwardingContracts: jest.fn(),
setIsClosingCreateRealAccountModal: jest.fn(),
setRealAccountSignupEnd: jest.fn(),
setPurchaseState: jest.fn(),
- setHasOnlyForwardingContracts: jest.fn(),
shouldNavigateAfterChooseCrypto: jest.fn(),
toggleLanguageSettingsModal: jest.fn(),
toggleLinkExpiredModal: jest.fn(),
@@ -368,6 +370,7 @@ const mock = (): TStores & { is_mock: boolean } => {
toggleShouldShowRealAccountsList: jest.fn(),
is_reset_trading_password_modal_visible: false,
setResetTradingPasswordModalOpen: jest.fn(),
+ vanilla_trade_type: 'VANILLALONGCALL',
},
traders_hub: {
getAccount: jest.fn(),
diff --git a/packages/stores/types.ts b/packages/stores/types.ts
index 4fba8d9adb93..f85af2ec59cb 100644
--- a/packages/stores/types.ts
+++ b/packages/stores/types.ts
@@ -2,6 +2,7 @@ import type {
AccountLimitsResponse,
Authorize,
ContractUpdate,
+ ContractUpdateHistory,
DetailsOfEachMT5Loginid,
GetAccountStatus,
GetLimits,
@@ -84,25 +85,6 @@ type TPopulateSettingsExtensionsMenuItem = {
value: (props: T) => JSX.Element;
};
-type TPortfolioPosition = {
- contract_info: ProposalOpenContract &
- Portfolio1 & {
- contract_update?: ContractUpdate;
- };
- details?: string;
- display_name: string;
- id?: number;
- indicative: number;
- payout?: number;
- purchase?: number;
- reference: number;
- type?: string;
- is_unsupported: boolean;
- contract_update: ProposalOpenContract['limit_order'];
- is_sell_requested: boolean;
- profit_loss: number;
-};
-
type TAppRoutingHistory = {
action: string;
hash: string;
@@ -195,7 +177,9 @@ type TMenuItem = {
type TAddToastProps = {
key: string;
- content: string;
+ content: string | React.ReactNode;
+ is_bottom?: boolean;
+ timeout?: number;
type: string;
};
@@ -286,6 +270,7 @@ type TClientStore = {
setCFDScore: (score: number) => void;
country_standpoint: TCountryStandpoint;
currency: string;
+ currencies_list: { text: string; value: string; has_tool_tip?: boolean }[];
current_currency_type?: string;
current_fiat_currency?: string;
has_any_real_account: boolean;
@@ -442,7 +427,6 @@ type TCommonStoreError = {
type TCommonStore = {
isCurrentLanguage(language_code: string): boolean;
error: TCommonStoreError;
- services_error: { code: string; message: string; type: string } | Record;
has_error: boolean;
is_from_derivgo: boolean;
is_network_online: boolean;
@@ -455,6 +439,7 @@ type TCommonStore = {
current_language: string;
is_language_changing: boolean;
is_socket_opened: boolean;
+ services_error: { code: string; message: string; type: string } | Record;
setAppstorePlatform: (value: string) => void;
app_routing_history: TAppRoutingHistory[];
getExchangeRate: (from_currency: string, to_currency: string) => Promise;
@@ -468,14 +453,13 @@ type TUiStore = {
current_focus: string | null;
disableApp: () => void;
enableApp: () => void;
+ has_only_forward_starting_contracts: boolean;
has_real_account_signup_ended: boolean;
+ header_extension: JSX.Element | null;
is_account_settings_visible: boolean;
is_loading: boolean;
is_cashier_visible: boolean;
is_closing_create_real_account_modal: boolean;
- is_unsupported_contract_modal_visible: boolean;
- has_only_forward_starting_contracts: boolean;
- header_extension: JSX.Element | null;
is_dark_mode_on: boolean;
is_reports_visible: boolean;
is_route_modal_on: boolean;
@@ -485,17 +469,30 @@ type TUiStore = {
is_mobile: boolean;
is_positions_drawer_on: boolean;
is_services_error_visible: boolean;
+ is_unsupported_contract_modal_visible: boolean;
openRealAccountSignup: (
value: 'maltainvest' | 'svg' | 'add_crypto' | 'choose' | 'add_fiat' | 'set_currency' | 'manage'
) => void;
notification_messages_ui: React.ElementType;
- setCurrentFocus: (value: string) => void;
+ populateFooterExtensions: (
+ footer_extensions:
+ | [
+ {
+ position?: string;
+ Component?: React.FunctionComponent;
+ has_right_separator?: boolean;
+ }
+ ]
+ | []
+ ) => void;
+ setAppContentsScrollRef: (ref: React.MutableRefObject) => void;
+ setCurrentFocus: (value: string | null) => void;
setDarkMode: (is_dark_mode_on: boolean) => boolean;
+ setHasOnlyForwardingContracts: (has_only_forward_starting_contracts: boolean) => void;
setReportsTabIndex: (value: number) => void;
setIsClosingCreateRealAccountModal: (value: boolean) => void;
setRealAccountSignupEnd: (status: boolean) => void;
setPurchaseState: (index: number) => void;
- setHasOnlyForwardingContracts: (has_only_forward_starting_contracts: boolean) => void;
sub_section_index: number;
setSubSectionIndex: (index: number) => void;
shouldNavigateAfterChooseCrypto: (value: Omit | TRoutes) => void;
@@ -506,15 +503,15 @@ type TUiStore = {
toggleLinkExpiredModal: (state_change: boolean) => void;
togglePositionsDrawer: () => void;
toggleReadyToDepositModal: () => void;
+ toggleServicesErrorModal: (is_visible: boolean) => void;
toggleSetCurrencyModal: () => void;
toggleShouldShowRealAccountsList: (value: boolean) => void;
- toggleServicesErrorModal: () => void;
is_tablet: boolean;
removeToast: (key: string) => void;
is_ready_to_deposit_modal_visible: boolean;
reports_route_tab_index: number;
should_show_cancellation_warning: boolean;
- toggleCancellationWarning: (state_change: boolean) => void;
+ toggleCancellationWarning: (state_change?: boolean) => void;
toggleUnsupportedContractModal: (state_change: boolean) => void;
toggleReports: (is_visible: boolean) => void;
is_real_acc_signup_on: boolean;
@@ -541,18 +538,26 @@ type TUiStore = {
populateSettingsExtensions: (menu_items: Array | null) => void;
purchase_states: boolean[];
setShouldShowCooldownModal: (value: boolean) => void;
- setAppContentsScrollRef: (ref: React.MutableRefObject) => void;
- populateFooterExtensions: (
- footer_extensions:
- | [
- {
- position?: string;
- Component?: React.FunctionComponent;
- has_right_separator?: boolean;
- }
- ]
- | []
- ) => void;
+ vanilla_trade_type: 'VANILLALONGCALL' | 'VANILLALONGPUT';
+};
+
+type TPortfolioPosition = {
+ contract_info: ProposalOpenContract &
+ Portfolio1 & {
+ contract_update?: ContractUpdate;
+ };
+ details?: string;
+ display_name: string;
+ id?: number;
+ indicative: number;
+ payout?: number;
+ purchase?: number;
+ reference: number;
+ type?: string;
+ is_unsupported: boolean;
+ contract_update: ProposalOpenContract['limit_order'];
+ is_sell_requested: boolean;
+ profit_loss: number;
};
type TPortfolioStore = {
@@ -571,15 +576,32 @@ type TPortfolioStore = {
removePositionById: (id: number) => void;
};
-type TContractStore = {
- getContractById: (id: number) => ProposalOpenContract;
+type TContractTradeStore = {
contract_info: TPortfolioPosition['contract_info'];
contract_update_stop_loss: string;
contract_update_take_profit: string;
+ getContractById: (id: number) => TContractStore;
has_contract_update_stop_loss: boolean;
has_contract_update_take_profit: boolean;
};
+type TContractStore = {
+ clearContractUpdateConfigValues: () => void;
+ contract_info: TPortfolioPosition['contract_info'];
+ contract_update_history: ContractUpdateHistory;
+ contract_update_take_profit: number | string;
+ contract_update_stop_loss: number | string;
+ digits_info: { [key: number]: { digit: number; spot: string } };
+ display_status: string;
+ has_contract_update_take_profit: boolean;
+ has_contract_update_stop_loss: boolean;
+ is_digit_contract: boolean;
+ is_ended: boolean;
+ onChange: (param: { name: string; value: string | number | boolean }) => void;
+ updateLimitOrder: () => void;
+ validation_errors: { contract_update_stop_loss: string[]; contract_update_take_profit: string[] };
+};
+
type TMenuStore = {
attach: (item: TMenuItem) => void;
update: (menu: TMenuItem, index: number) => void;
@@ -705,7 +727,7 @@ export type TCoreStores = {
menu: TMenuStore;
ui: TUiStore;
portfolio: TPortfolioStore;
- contract_trade: TContractStore;
+ contract_trade: TContractTradeStore;
// This should be `any` as this property will be handled in each package.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
modules: Record;
From c2c44e7cbdb10307ccff7076f326a16dbbd31f11 Mon Sep 17 00:00:00 2001
From: kate-deriv <121025168+kate-deriv@users.noreply.github.com>
Date: Tue, 26 Sep 2023 12:20:21 +0300
Subject: [PATCH 5/5] Kate / Test coverage + TS migration:
Components/Elements/Media files in Trader package (#8457)
* refactor: ts migration and tess for media
* fix: change path for import
* refactor: change type for svg
* chore: remove file type from imports
* refactor: replace svg in test
* refactor: implemented suggestion from review
* fix: replace old type in svg d ts
* refactor: replace react.fc
* refactor: ts of index file
---
.../__tests__/media-description.spec.tsx | 15 +++++++++++
.../Media/__tests__/media-heading.spec.tsx | 15 +++++++++++
.../Media/__tests__/media-icon.spec.tsx | 25 +++++++++++++++++++
.../Media/__tests__/media-item.spec.tsx | 15 +++++++++++
.../App/Components/Elements/Media/index.js | 6 -----
.../App/Components/Elements/Media/index.ts | 6 +++++
.../Elements/Media/media-description.jsx | 5 ----
.../Elements/Media/media-description.tsx | 7 ++++++
.../Elements/Media/media-heading.jsx | 5 ----
.../Elements/Media/media-heading.tsx | 5 ++++
.../Components/Elements/Media/media-icon.jsx | 16 ------------
.../Components/Elements/Media/media-icon.tsx | 14 +++++++++++
.../Components/Elements/Media/media-item.jsx | 5 ----
.../Components/Elements/Media/media-item.tsx | 5 ++++
14 files changed, 107 insertions(+), 37 deletions(-)
create mode 100644 packages/trader/src/App/Components/Elements/Media/__tests__/media-description.spec.tsx
create mode 100644 packages/trader/src/App/Components/Elements/Media/__tests__/media-heading.spec.tsx
create mode 100644 packages/trader/src/App/Components/Elements/Media/__tests__/media-icon.spec.tsx
create mode 100644 packages/trader/src/App/Components/Elements/Media/__tests__/media-item.spec.tsx
delete mode 100644 packages/trader/src/App/Components/Elements/Media/index.js
create mode 100644 packages/trader/src/App/Components/Elements/Media/index.ts
delete mode 100644 packages/trader/src/App/Components/Elements/Media/media-description.jsx
create mode 100644 packages/trader/src/App/Components/Elements/Media/media-description.tsx
delete mode 100644 packages/trader/src/App/Components/Elements/Media/media-heading.jsx
create mode 100644 packages/trader/src/App/Components/Elements/Media/media-heading.tsx
delete mode 100644 packages/trader/src/App/Components/Elements/Media/media-icon.jsx
create mode 100644 packages/trader/src/App/Components/Elements/Media/media-icon.tsx
delete mode 100644 packages/trader/src/App/Components/Elements/Media/media-item.jsx
create mode 100644 packages/trader/src/App/Components/Elements/Media/media-item.tsx
diff --git a/packages/trader/src/App/Components/Elements/Media/__tests__/media-description.spec.tsx b/packages/trader/src/App/Components/Elements/Media/__tests__/media-description.spec.tsx
new file mode 100644
index 000000000000..ccad8a4317c1
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/__tests__/media-description.spec.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { MediaDescription } from 'App/Components/Elements/Media';
+
+const test_children = 'Test Children';
+
+describe('MediaDescription', () => {
+ it('should render children inside of proper MediaDescription div container with className', () => {
+ render({test_children});
+ const test_props_children = screen.getByText(test_children);
+
+ expect(test_props_children).toBeInTheDocument();
+ expect(test_props_children).toHaveClass('media__description');
+ });
+});
diff --git a/packages/trader/src/App/Components/Elements/Media/__tests__/media-heading.spec.tsx b/packages/trader/src/App/Components/Elements/Media/__tests__/media-heading.spec.tsx
new file mode 100644
index 000000000000..acb7f14dab68
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/__tests__/media-heading.spec.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { MediaHeading } from 'App/Components/Elements/Media';
+
+const test_children = 'Test Children';
+
+describe('MediaHeading', () => {
+ it('should render children inside of proper MediaHeading div container with className', () => {
+ render({test_children});
+ const test_props_children = screen.getByText(test_children);
+
+ expect(test_props_children).toBeInTheDocument();
+ expect(test_props_children).toHaveClass('media__heading');
+ });
+});
diff --git a/packages/trader/src/App/Components/Elements/Media/__tests__/media-icon.spec.tsx b/packages/trader/src/App/Components/Elements/Media/__tests__/media-icon.spec.tsx
new file mode 100644
index 000000000000..d87bdfd29a27
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/__tests__/media-icon.spec.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { MediaIcon } from 'App/Components/Elements/Media';
+
+const test_disabled = 'Interval Duration Disabled Light Icon';
+const test_enabled = 'Interval Duration Enabled Light Icon';
+const mock_props = {
+ disabled: jest.fn(() => {test_disabled}
),
+ enabled: jest.fn(() => {test_enabled}
),
+ id: 'test_id',
+ is_enabled: true,
+};
+
+describe('MediaIcon', () => {
+ it('should render MediaIcon component with enabled SVG if is_enabled === true', () => {
+ render();
+
+ expect(screen.getByText(test_enabled)).toBeInTheDocument();
+ });
+ it('should render MediaIcon component with disabled SVG if is_enabled === false', () => {
+ render();
+
+ expect(screen.getByText(test_disabled)).toBeInTheDocument();
+ });
+});
diff --git a/packages/trader/src/App/Components/Elements/Media/__tests__/media-item.spec.tsx b/packages/trader/src/App/Components/Elements/Media/__tests__/media-item.spec.tsx
new file mode 100644
index 000000000000..2770cd33fad3
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/__tests__/media-item.spec.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import MediaItem from '../media-item';
+
+const test_children = 'Test Children';
+
+describe('MediaItem', () => {
+ it('should render children inside of proper MediaItem div container with className', () => {
+ render({test_children});
+ const test_props_children = screen.getByText(test_children);
+
+ expect(test_props_children).toBeInTheDocument();
+ expect(test_props_children).toHaveClass('media');
+ });
+});
diff --git a/packages/trader/src/App/Components/Elements/Media/index.js b/packages/trader/src/App/Components/Elements/Media/index.js
deleted file mode 100644
index ce221026b9e0..000000000000
--- a/packages/trader/src/App/Components/Elements/Media/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import MediaItem from './media-item.jsx';
-
-export * from './media-description.jsx';
-export * from './media-heading.jsx';
-export * from './media-icon.jsx';
-export default MediaItem;
diff --git a/packages/trader/src/App/Components/Elements/Media/index.ts b/packages/trader/src/App/Components/Elements/Media/index.ts
new file mode 100644
index 000000000000..16f58a9fb22e
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/index.ts
@@ -0,0 +1,6 @@
+import MediaItem from './media-item';
+
+export * from './media-description';
+export * from './media-heading';
+export * from './media-icon';
+export default MediaItem;
diff --git a/packages/trader/src/App/Components/Elements/Media/media-description.jsx b/packages/trader/src/App/Components/Elements/Media/media-description.jsx
deleted file mode 100644
index 36c190dd4dd4..000000000000
--- a/packages/trader/src/App/Components/Elements/Media/media-description.jsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-
-const MediaDescription = props => {props.children}
;
-
-export { MediaDescription };
diff --git a/packages/trader/src/App/Components/Elements/Media/media-description.tsx b/packages/trader/src/App/Components/Elements/Media/media-description.tsx
new file mode 100644
index 000000000000..41b4b6a66644
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/media-description.tsx
@@ -0,0 +1,7 @@
+import React from 'react';
+
+const MediaDescription = ({ children }: React.PropsWithChildren) => (
+ {children}
+);
+
+export { MediaDescription };
diff --git a/packages/trader/src/App/Components/Elements/Media/media-heading.jsx b/packages/trader/src/App/Components/Elements/Media/media-heading.jsx
deleted file mode 100644
index 68e63deb8f4d..000000000000
--- a/packages/trader/src/App/Components/Elements/Media/media-heading.jsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-
-const MediaHeading = props => {props.children}
;
-
-export { MediaHeading };
diff --git a/packages/trader/src/App/Components/Elements/Media/media-heading.tsx b/packages/trader/src/App/Components/Elements/Media/media-heading.tsx
new file mode 100644
index 000000000000..5105497b3588
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/media-heading.tsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+const MediaHeading = ({ children }: React.PropsWithChildren) => {children}
;
+
+export { MediaHeading };
diff --git a/packages/trader/src/App/Components/Elements/Media/media-icon.jsx b/packages/trader/src/App/Components/Elements/Media/media-icon.jsx
deleted file mode 100644
index 645eeb88256a..000000000000
--- a/packages/trader/src/App/Components/Elements/Media/media-icon.jsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-const MediaIcon = ({ id, is_enabled, enabled, disabled }) => {
- const Icon = is_enabled ? enabled : disabled;
- return ;
-};
-
-MediaIcon.propTypes = {
- disabled: PropTypes.func,
- enabled: PropTypes.func,
- id: PropTypes.string,
- is_enabled: PropTypes.bool,
-};
-
-export { MediaIcon };
diff --git a/packages/trader/src/App/Components/Elements/Media/media-icon.tsx b/packages/trader/src/App/Components/Elements/Media/media-icon.tsx
new file mode 100644
index 000000000000..a4d7c5c0b4ac
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/media-icon.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+
+type TMediaIcon = {
+ disabled: React.ComponentType>;
+ enabled: React.ComponentType>;
+ id: string;
+ is_enabled: boolean;
+};
+const MediaIcon = ({ id, is_enabled, enabled, disabled }: TMediaIcon) => {
+ const Icon = is_enabled ? enabled : disabled;
+ return ;
+};
+
+export { MediaIcon };
diff --git a/packages/trader/src/App/Components/Elements/Media/media-item.jsx b/packages/trader/src/App/Components/Elements/Media/media-item.jsx
deleted file mode 100644
index 6347c10d720e..000000000000
--- a/packages/trader/src/App/Components/Elements/Media/media-item.jsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-
-const MediaItem = props => {props.children}
;
-
-export default MediaItem;
diff --git a/packages/trader/src/App/Components/Elements/Media/media-item.tsx b/packages/trader/src/App/Components/Elements/Media/media-item.tsx
new file mode 100644
index 000000000000..0d0ded93016b
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/Media/media-item.tsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+const MediaItem = ({ children }: React.PropsWithChildren) => {children}
;
+
+export default MediaItem;