0 && !result,
- 'dc-contract-card--red': profit < 0 && !result,
+ 'dc-contract-card--green': Number(profit) > 0 && !result,
+ 'dc-contract-card--red': Number(profit) < 0 && !result,
'contract-card__market-closed--disabled': is_market_closed && should_hide_closed_overlay,
})}
ref={hover_ref}
@@ -175,13 +200,4 @@ const ContractDrawerCard = observer(
}
);
-ContractDrawerCard.propTypes = {
- currency: PropTypes.string,
- is_accumulator: PropTypes.bool,
- is_smarttrader_contract: PropTypes.bool,
- is_collapsed: PropTypes.bool,
- is_turbos: PropTypes.bool,
- onClickCancel: PropTypes.func,
- onClickSell: PropTypes.func,
-};
export default ContractDrawerCard;
diff --git a/packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.jsx b/packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.tsx
similarity index 84%
rename from packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.jsx
rename to packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.tsx
index 0d51eae66590..69045cc10ab8 100644
--- a/packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.jsx
+++ b/packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.tsx
@@ -1,7 +1,6 @@
import classNames from 'classnames';
-import PropTypes from 'prop-types';
import React from 'react';
-import { withRouter } from 'react-router';
+import { RouteComponentProps, withRouter } from 'react-router';
import { CSSTransition } from 'react-transition-group';
import { DesktopWrapper, MobileWrapper, Div100vhContainer } from '@deriv/components';
import {
@@ -11,13 +10,35 @@ import {
getDurationTime,
getDurationUnitText,
getEndTime,
+ TContractStore,
} from '@deriv/shared';
import ContractAudit from 'App/Components/Elements/ContractAudit';
import { PositionsCardLoader } from 'App/Components/Elements/ContentLoader';
import ContractDrawerCard from './contract-drawer-card';
-import { SwipeableContractAudit } from './swipeable-components.jsx';
+import { SwipeableContractAudit } from './swipeable-components';
import { observer, useStore } from '@deriv/stores';
+type TContractDrawerCardProps = React.ComponentProps
;
+type TContractDrawerProps = RouteComponentProps & {
+ contract_update_history: TContractStore['contract_update_history'];
+ is_dark_theme: boolean;
+ toggleHistoryTab: (state_change?: boolean) => void;
+} & Pick<
+ TContractDrawerCardProps,
+ | 'contract_info'
+ | 'contract_update'
+ | 'is_accumulator'
+ | 'is_market_closed'
+ | 'is_multiplier'
+ | 'is_sell_requested'
+ | 'is_smarttrader_contract'
+ | 'is_turbos'
+ | 'is_vanilla'
+ | 'onClickCancel'
+ | 'onClickSell'
+ | 'status'
+ >;
+
const ContractDrawer = observer(
({
contract_info,
@@ -35,13 +56,13 @@ const ContractDrawer = observer(
onClickSell,
status,
toggleHistoryTab,
- }) => {
+ }: TContractDrawerProps) => {
const { common, ui } = useStore();
const { server_time } = common;
const { is_mobile } = ui;
const { currency, exit_tick_display_value, is_sold } = contract_info;
- const contract_drawer_ref = React.useRef();
- const contract_drawer_card_ref = React.useRef();
+ const contract_drawer_ref = React.useRef(null);
+ const contract_drawer_card_ref = React.useRef(null);
const [should_show_contract_audit, setShouldShowContractAudit] = React.useState(false);
const exit_spot =
isUserSold(contract_info) && !is_accumulator && !is_multiplier && !is_turbos
@@ -56,7 +77,6 @@ const ContractDrawer = observer(
is_accumulator={is_accumulator}
is_dark_theme={is_dark_theme}
is_multiplier={is_multiplier}
- is_smarttrader_contract={is_smarttrader_contract}
is_open
is_turbos={is_turbos}
duration={getDurationTime(contract_info)}
@@ -102,7 +122,7 @@ const ContractDrawer = observer(
) : (
);
@@ -119,11 +139,10 @@ const ContractDrawer = observer(
'contract-drawer--is-multiplier-sold': is_multiplier && isMobile() && getEndTime(contract_info),
})}
style={{
- transform:
- should_show_contract_audit &&
+ transform: (should_show_contract_audit &&
contract_drawer_ref.current &&
contract_drawer_card_ref.current &&
- `translateY(calc(${contract_drawer_card_ref.current.clientHeight}px - ${contract_drawer_ref.current.clientHeight}px))`,
+ `translateY(calc(${contract_drawer_card_ref.current.clientHeight}px - ${contract_drawer_ref.current.clientHeight}px))`) as React.CSSProperties['transform'],
}}
ref={contract_drawer_ref}
>
@@ -162,13 +181,4 @@ const ContractDrawer = observer(
}
);
-ContractDrawer.propTypes = {
- is_accumulator: PropTypes.bool,
- is_multiplier: PropTypes.bool,
- is_vanilla: PropTypes.bool,
- is_smarttrader_contract: PropTypes.bool,
- is_turbos: PropTypes.bool,
- toggleHistoryTab: PropTypes.func,
-};
-
export default withRouter(ContractDrawer);
diff --git a/packages/trader/src/App/Components/Elements/ContractDrawer/index.js b/packages/trader/src/App/Components/Elements/ContractDrawer/index.js
deleted file mode 100644
index 34ed63b1b74e..000000000000
--- a/packages/trader/src/App/Components/Elements/ContractDrawer/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import ContractDrawer from './contract-drawer.jsx';
-
-export default ContractDrawer;
diff --git a/packages/trader/src/App/Components/Elements/ContractDrawer/index.ts b/packages/trader/src/App/Components/Elements/ContractDrawer/index.ts
new file mode 100644
index 000000000000..563d551f3b95
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/ContractDrawer/index.ts
@@ -0,0 +1,3 @@
+import ContractDrawer from './contract-drawer';
+
+export default ContractDrawer;
diff --git a/packages/trader/src/App/Components/Elements/ContractDrawer/market-closed-contract-overlay.jsx b/packages/trader/src/App/Components/Elements/ContractDrawer/market-closed-contract-overlay.tsx
similarity index 64%
rename from packages/trader/src/App/Components/Elements/ContractDrawer/market-closed-contract-overlay.jsx
rename to packages/trader/src/App/Components/Elements/ContractDrawer/market-closed-contract-overlay.tsx
index 8d3d47aeb479..8538cd1de2c6 100644
--- a/packages/trader/src/App/Components/Elements/ContractDrawer/market-closed-contract-overlay.jsx
+++ b/packages/trader/src/App/Components/Elements/ContractDrawer/market-closed-contract-overlay.tsx
@@ -1,8 +1,7 @@
import React from 'react';
-import PropTypes from 'prop-types';
import { Text } from '@deriv/components';
-const MarketClosedContractOverlay = ({ validation_error }) => (
+const MarketClosedContractOverlay = ({ validation_error }: { validation_error?: string }) => (
{validation_error}
@@ -10,8 +9,4 @@ const MarketClosedContractOverlay = ({ validation_error }) => (
);
-MarketClosedContractOverlay.propTypes = {
- symbol: PropTypes.string,
-};
-
export default MarketClosedContractOverlay;
diff --git a/packages/trader/src/App/Components/Elements/ContractDrawer/swipeable-components.jsx b/packages/trader/src/App/Components/Elements/ContractDrawer/swipeable-components.tsx
similarity index 75%
rename from packages/trader/src/App/Components/Elements/ContractDrawer/swipeable-components.jsx
rename to packages/trader/src/App/Components/Elements/ContractDrawer/swipeable-components.tsx
index 9b9e917c28b3..55aefd7f33e7 100644
--- a/packages/trader/src/App/Components/Elements/ContractDrawer/swipeable-components.jsx
+++ b/packages/trader/src/App/Components/Elements/ContractDrawer/swipeable-components.tsx
@@ -1,13 +1,21 @@
import classNames from 'classnames';
-import PropTypes from 'prop-types';
import React from 'react';
import ReactDOM from 'react-dom';
import { SwipeableWrapper } from '@deriv/components';
+type TSwipeableContractAuditProps = React.PropsWithChildren<{
+ is_multiplier?: boolean;
+ onSwipedDown?: () => void;
+}>;
+type TSwipeableContractDrawerProps = React.PropsWithChildren<{
+ onSwipedDown?: () => void;
+ onSwipedUp?: () => void;
+}>;
+
/**
* Swipeable components
*/
-export const SwipeableContractAudit = ({ is_multiplier, children, onSwipedDown }) => {
+export const SwipeableContractAudit = ({ is_multiplier, children, onSwipedDown }: TSwipeableContractAuditProps) => {
const swipe_handlers = SwipeableWrapper.useSwipeable({
onSwipedDown,
});
@@ -31,13 +39,7 @@ export const SwipeableContractAudit = ({ is_multiplier, children, onSwipedDown }
);
};
-SwipeableContractAudit.propTypes = {
- is_multiplier: PropTypes.bool,
- children: PropTypes.node,
- onSwipedDown: PropTypes.func,
-};
-
-export const SwipeableContractDrawer = ({ children, onSwipedDown, onSwipedUp }) => {
+export const SwipeableContractDrawer = ({ children, onSwipedDown, onSwipedUp }: TSwipeableContractDrawerProps) => {
const swipe_handlers = SwipeableWrapper.useSwipeable({
onSwipedDown,
onSwipedUp,
@@ -45,9 +47,3 @@ export const SwipeableContractDrawer = ({ children, onSwipedDown, onSwipedUp })
return {children}
;
};
-
-SwipeableContractDrawer.propTypes = {
- children: PropTypes.node,
- onSwipedDown: PropTypes.func,
- onSwipedUp: PropTypes.func,
-};
diff --git a/packages/trader/src/App/Components/Elements/TogglePositions/__tests__/toggle-positions-mobile.spec.tsx b/packages/trader/src/App/Components/Elements/TogglePositions/__tests__/toggle-positions-mobile.spec.tsx
index cd2855ab77f7..025a84d9b56a 100644
--- a/packages/trader/src/App/Components/Elements/TogglePositions/__tests__/toggle-positions-mobile.spec.tsx
+++ b/packages/trader/src/App/Components/Elements/TogglePositions/__tests__/toggle-positions-mobile.spec.tsx
@@ -7,21 +7,53 @@ import { mockStore } from '@deriv/stores';
import { TCoreStores } from '@deriv/stores/types';
import { BrowserRouter } from 'react-router-dom';
-const default_mocked_props = {
+const default_mocked_props: React.ComponentProps = {
active_positions_count: 0,
- filtered_positions: [],
currency: 'USD',
- disableApp: jest.fn(),
- enableApp: jest.fn(),
error: '',
+ filtered_positions: [
+ {
+ contract_info: {
+ contract_id: 215925907928,
+ contract_type: 'CALL',
+ is_sold: 0,
+ shortcode: 'CALL_1HZ100V_76.33_1692187938_1692188838_S0P_0',
+ underlying: '1HZ100V',
+ },
+ contract_update: {},
+ display_name: 'Volatility 100 (1s) Index',
+ indicative: 29.55,
+ reference: 430851089968,
+ is_sell_requested: false,
+ is_unsupported: false,
+ profit_loss: -9.45,
+ },
+ {
+ contract_info: {
+ contract_id: 2,
+ contract_type: 'PUT',
+ is_sold: 0,
+ shortcode: 'PUT_R_10_19.53_1691443887_1691444787_S0P_0',
+ underlying: 'R_100',
+ },
+ contract_update: {},
+ display_name: 'Volatility 100 (1s) Index',
+ indicative: 29.55,
+ reference: 430851089968,
+ is_sell_requested: false,
+ is_unsupported: false,
+ profit_loss: -9.45,
+ },
+ ],
is_empty: true,
onClickSell: jest.fn(),
onClickCancel: jest.fn(),
- toggleUnsupportedContractModal: jest.fn(),
};
+
const default_mock_store = {
ui: {
togglePositionsDrawer: jest.fn(),
+ toggleUnsupportedContractModal: jest.fn(),
is_positions_drawer_on: false,
},
};
@@ -68,29 +100,47 @@ describe('TogglePositionsMobile component', () => {
expect(screen.getByText(/You have no open positions for this asset./i)).toBeInTheDocument();
});
it('should display 2 positions when is_positions_drawer_on === true, is_empty === false, and has 2 active positions', () => {
- const new_mocked_props = {
+ const new_mocked_props: React.ComponentProps = {
active_positions_count: 2,
+ currency: 'USD',
+ error: '',
filtered_positions: [
{
contract_info: {
- contract_id: '1',
+ contract_id: 1,
contract_type: 'CALL',
is_sold: 0,
shortcode: 'CALL_R_10_19.54_1691443851_1691444751_S0P_0',
underlying: 'R_100',
},
+ contract_update: {},
+ display_name: 'Volatility 100 (1s) Index',
+ indicative: 29.55,
+ reference: 430851089968,
+ is_sell_requested: false,
+ is_unsupported: false,
+ profit_loss: -9.45,
},
{
contract_info: {
- contract_id: '2',
+ contract_id: 2,
contract_type: 'PUT',
is_sold: 0,
shortcode: 'PUT_R_10_19.53_1691443887_1691444787_S0P_0',
underlying: 'R_100',
},
+ contract_update: {},
+ display_name: 'Volatility 100 (1s) Index',
+ indicative: 29.55,
+ reference: 430851089968,
+ is_sell_requested: false,
+ is_unsupported: false,
+ profit_loss: -9.45,
},
],
is_empty: false,
+ onClickSell: jest.fn(),
+ onClickCancel: jest.fn(),
};
const mock_root_store = mockStore({
...default_mock_store,
@@ -101,29 +151,47 @@ describe('TogglePositionsMobile component', () => {
expect(screen.getAllByText(/PositionsModalCard/i)).toHaveLength(2);
});
it('should display 1 of 2 positions after closing the modal if one of the 2 positions is sold', async () => {
- const new_mocked_props = {
+ const new_mocked_props: React.ComponentProps = {
active_positions_count: 1,
+ currency: 'USD',
+ error: '',
filtered_positions: [
{
contract_info: {
- contract_id: '1',
+ contract_id: 1,
contract_type: 'CALL',
is_sold: 0,
shortcode: 'CALL_R_10_19.54_1691443851_1691444751_S0P_0',
underlying: 'R_100',
},
+ contract_update: {},
+ display_name: 'Volatility 100 (1s) Index',
+ indicative: 29.55,
+ reference: 430851089968,
+ is_sell_requested: false,
+ is_unsupported: false,
+ profit_loss: -9.45,
},
{
contract_info: {
- contract_id: '2',
+ contract_id: 2,
contract_type: 'PUT',
is_sold: 1,
shortcode: 'PUT_R_10_19.53_1691443887_1691444787_S0P_0',
underlying: 'R_100',
},
+ contract_update: {},
+ display_name: 'Volatility 100 (1s) Index',
+ indicative: 29.55,
+ reference: 430851089968,
+ is_sell_requested: false,
+ is_unsupported: false,
+ profit_loss: -9.45,
},
],
is_empty: false,
+ onClickSell: jest.fn(),
+ onClickCancel: jest.fn(),
};
const mock_root_store = mockStore({
...default_mock_store,
@@ -140,24 +208,38 @@ describe('TogglePositionsMobile component', () => {
});
});
it('should display no more than 5 recent positions', () => {
- const positions_pair = [
+ const positions_pair: React.ComponentProps['filtered_positions'] = [
{
contract_info: {
- contract_id: '1',
+ contract_id: 1,
contract_type: 'CALL',
is_sold: 0,
shortcode: 'CALL_R_10_19.54_1691443851_1691444751_S0P_0',
underlying: 'R_100',
},
+ contract_update: {},
+ display_name: 'Volatility 100 (1s) Index',
+ indicative: 29.55,
+ reference: 430851089968,
+ is_sell_requested: false,
+ is_unsupported: false,
+ profit_loss: -9.45,
},
{
contract_info: {
- contract_id: '2',
+ contract_id: 2,
contract_type: 'PUT',
is_sold: 0,
shortcode: 'PUT_R_10_19.53_1691443887_1691444787_S0P_0',
underlying: 'R_100',
},
+ contract_update: {},
+ display_name: 'Volatility 100 (1s) Index',
+ indicative: 29.55,
+ reference: 430851089968,
+ is_sell_requested: false,
+ is_unsupported: false,
+ profit_loss: -9.45,
},
];
const new_mocked_props = {
diff --git a/packages/trader/src/App/Components/Elements/TogglePositions/__tests__/toggle-positions.spec.tsx b/packages/trader/src/App/Components/Elements/TogglePositions/__tests__/toggle-positions.spec.tsx
index 19770e5e8bf3..20e13be8dd7a 100644
--- a/packages/trader/src/App/Components/Elements/TogglePositions/__tests__/toggle-positions.spec.tsx
+++ b/packages/trader/src/App/Components/Elements/TogglePositions/__tests__/toggle-positions.spec.tsx
@@ -1,29 +1,35 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';
-import TogglePositions from '../toggle-positions.jsx';
+import TogglePositions from '../toggle-positions';
+
+const default_props = {
+ is_open: false,
+ positions_count: 0,
+ togglePositions: jest.fn(),
+};
describe('TogglePositions component', () => {
it('should have "positions-toggle--active" class when "is_open" is "true"', () => {
- render();
+ render();
expect(screen.getByTestId('dt_positions_toggle')).toHaveClass('positions-toggle--active');
});
it('should have "positions-toggle--has-count" class when "positions_count > 0"', () => {
- render();
+ render();
expect(screen.getByTestId('dt_positions_toggle')).toHaveClass('positions-toggle--has-count');
});
it('should call "togglePositions" when the user clicked on the link', () => {
const mockTogglePositions = jest.fn();
- render();
+ render();
const link = screen.getByTestId('dt_positions_toggle');
userEvent.click(link);
expect(mockTogglePositions).toHaveBeenCalledTimes(1);
});
it('should render "IcPortfolio" icon', () => {
- render();
+ render();
expect(screen.getByTestId('dt_icon')).toBeVisible();
});
});
diff --git a/packages/trader/src/App/Components/Elements/TogglePositions/index.js b/packages/trader/src/App/Components/Elements/TogglePositions/index.js
index 117ed97b03fd..c97185e5654a 100644
--- a/packages/trader/src/App/Components/Elements/TogglePositions/index.js
+++ b/packages/trader/src/App/Components/Elements/TogglePositions/index.js
@@ -1,3 +1,3 @@
-import TogglePositions from './toggle-positions.jsx';
+import TogglePositions from './toggle-positions';
export default TogglePositions;
diff --git a/packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions-mobile.jsx b/packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions-mobile.tsx
similarity index 87%
rename from packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions-mobile.jsx
rename to packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions-mobile.tsx
index d17e8ca51eed..eef96fdde3b9 100644
--- a/packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions-mobile.jsx
+++ b/packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions-mobile.tsx
@@ -6,24 +6,32 @@ import { localize } from '@deriv/translations';
import { NavLink } from 'react-router-dom';
import EmptyPortfolioMessage from '../EmptyPortfolioMessage';
import PositionsModalCard from 'App/Components/Elements/PositionsDrawer/positions-modal-card.jsx';
-import TogglePositions from './toggle-positions.jsx';
+import TogglePositions from './toggle-positions';
import { observer, useStore } from '@deriv/stores';
+type TTogglePositionsMobile = Pick<
+ ReturnType['portfolio'],
+ 'active_positions_count' | 'error' | 'onClickSell' | 'onClickCancel'
+> & {
+ currency: ReturnType['client']['currency'];
+ filtered_positions: ReturnType['portfolio']['all_positions'];
+ is_empty: boolean;
+};
+
+type THiddenPositionsId = TTogglePositionsMobile['filtered_positions'][0]['id'];
+
const TogglePositionsMobile = observer(
({
active_positions_count,
currency,
- disableApp,
- enableApp,
error,
filtered_positions,
is_empty,
onClickSell,
onClickCancel,
- toggleUnsupportedContractModal,
- }) => {
- const { togglePositionsDrawer, is_positions_drawer_on } = useStore().ui;
- const [hidden_positions_ids, setHiddenPositionsIds] = React.useState([]);
+ }: TTogglePositionsMobile) => {
+ const { togglePositionsDrawer, toggleUnsupportedContractModal, is_positions_drawer_on } = useStore().ui;
+ const [hidden_positions_ids, setHiddenPositionsIds] = React.useState([]);
const displayed_positions = filtered_positions
.filter(p =>
hidden_positions_ids.every(hidden_position_id => hidden_position_id !== p.contract_info.contract_id)
@@ -57,6 +65,7 @@ const TogglePositionsMobile = observer(
unmountOnExit
>
diff --git a/packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions.jsx b/packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions.tsx
similarity index 74%
rename from packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions.jsx
rename to packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions.tsx
index c37fb05d11f0..7e7691372e11 100644
--- a/packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions.jsx
+++ b/packages/trader/src/App/Components/Elements/TogglePositions/toggle-positions.tsx
@@ -1,10 +1,15 @@
import classNames from 'classnames';
-import PropTypes from 'prop-types';
import React from 'react';
import { Icon } from '@deriv/components';
import 'Sass/app/_common/components/positions-toggle.scss';
-const TogglePositions = ({ positions_count, is_open, togglePositions }) => {
+type TTogglePositions = {
+ positions_count: number;
+ is_open: boolean;
+ togglePositions: () => void;
+};
+
+const TogglePositions = ({ positions_count, is_open, togglePositions }: TTogglePositions) => {
const positions_toggle_class = classNames('positions-toggle', {
'positions-toggle--active': is_open,
'positions-toggle--has-count': positions_count > 0,
@@ -22,12 +27,4 @@ const TogglePositions = ({ positions_count, is_open, togglePositions }) => {
);
};
-TogglePositions.propTypes = {
- is_open: PropTypes.bool,
- is_positions_drawer_on: PropTypes.bool,
- positions_count: PropTypes.number,
- togglePositions: PropTypes.func,
- togglePositionsDrawer: PropTypes.func,
-};
-
export default TogglePositions;
diff --git a/packages/trader/src/App/Components/Elements/market-countdown-timer.jsx b/packages/trader/src/App/Components/Elements/market-countdown-timer.jsx
deleted file mode 100644
index 833af29df84f..000000000000
--- a/packages/trader/src/App/Components/Elements/market-countdown-timer.jsx
+++ /dev/null
@@ -1,209 +0,0 @@
-import classNames from 'classnames';
-import React from 'react';
-import PropTypes from 'prop-types';
-import moment from 'moment';
-import { Text } from '@deriv/components';
-import { useIsMounted, WS, convertTimeFormat, isMarketClosed } from '@deriv/shared';
-import { Localize } from '@deriv/translations';
-import { observer } from '@deriv/stores';
-import { useTraderStore } from 'Stores/useTraderStores';
-
-// check market in coming 7 days
-const days_to_check_before_exit = 7;
-
-const getTradingTimes = async target_time => {
- const data = await WS.tradingTimes(target_time);
- if (data.error) {
- return { api_initial_load_error: data.error.message };
- }
- return data;
-};
-// eslint-disable-next-line consistent-return
-const getSymbol = (target_symbol, trading_times) => {
- let symbol;
- const { markets } = trading_times;
- for (let i = 0; i < markets.length; i++) {
- const { submarkets } = markets[i];
- for (let j = 0; j < submarkets.length; j++) {
- const { symbols } = submarkets[j];
- symbol = symbols.find(item => item.symbol === target_symbol);
- if (symbol !== undefined) return symbol;
- }
- }
-};
-
-const calculateTimeLeft = remaining_time_to_open => {
- const difference = remaining_time_to_open - Date.now();
- return difference > 0
- ? {
- days: Math.floor(difference / (1000 * 60 * 60 * 24)),
- hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
- minutes: Math.floor((difference / 1000 / 60) % 60),
- seconds: Math.floor((difference / 1000) % 60),
- }
- : {};
-};
-
-const MarketCountdownTimer = observer(({ is_main_page, setIsTimerLoading, onMarketOpen, symbol }) => {
- const { active_symbols } = useTraderStore();
- const isMounted = useIsMounted();
- const [when_market_opens, setWhenMarketOpens] = React.useState({});
- const [time_left, setTimeLeft] = React.useState(calculateTimeLeft(when_market_opens?.remaining_time_to_open));
- const [is_loading, setLoading] = React.useState(true);
-
- React.useEffect(() => {
- if (!is_main_page || (is_main_page && isMarketClosed(active_symbols, symbol))) {
- setLoading(true);
- // eslint-disable-next-line consistent-return
- const whenMarketOpens = async (days_offset, target_symbol) => {
- // days_offset is 0 for today, 1 for tomorrow, etc.
- if (days_offset > days_to_check_before_exit) return {};
- let remaining_time_to_open;
- const target_date = moment(new Date()).add(days_offset, 'days');
- const api_response = await getTradingTimes(target_date.format('YYYY-MM-DD'));
- if (!api_response.api_initial_load_error) {
- const { times } = getSymbol(target_symbol, api_response.trading_times);
- const { open, close } = times;
- const is_closed_all_day = open?.length === 1 && open[0] === '--' && close[0] === '--';
- if (is_closed_all_day) {
- // check tomorrow trading times
- return whenMarketOpens(days_offset + 1, target_symbol);
- }
- const date_str = target_date.toISOString().substring(0, 11);
- const getUTCDate = hour => new Date(`${date_str}${hour}Z`);
- for (let i = 0; i < open?.length; i++) {
- const diff = +getUTCDate(open[i]) - Date.now();
- if (diff > 0) {
- remaining_time_to_open = +getUTCDate(open[i]);
- if (isMounted() && target_symbol === symbol) {
- return setWhenMarketOpens({
- days_offset,
- opening_time: open[i],
- remaining_time_to_open,
- });
- }
- }
- }
- whenMarketOpens(days_offset + 1, target_symbol);
- }
- };
-
- whenMarketOpens(0, symbol);
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [symbol]);
-
- React.useEffect(() => {
- let timer;
- if (when_market_opens?.remaining_time_to_open) {
- timer = setTimeout(() => {
- setTimeLeft(calculateTimeLeft(when_market_opens.remaining_time_to_open));
- if (new Date(when_market_opens.remaining_time_to_open) - +new Date() < 1000) {
- setLoading(true);
- if (is_main_page) onMarketOpen(false);
- }
- }, 1000);
- }
- return () => {
- if (timer) {
- clearTimeout(timer);
- }
- };
- }, [time_left, when_market_opens, onMarketOpen, is_main_page]);
-
- React.useEffect(() => {
- if (!is_loading) setIsTimerLoading(false);
- }, [is_loading, setIsTimerLoading]);
-
- let timer_components = '';
-
- if (Object.keys(time_left).length) {
- const hours = (time_left.days * 24 + time_left.hours).toString().padStart(2, '0');
- const minutes = time_left.minutes.toString().padStart(2, '0');
- const seconds = time_left.seconds.toString().padStart(2, '0');
- timer_components = `${hours}:${minutes}:${seconds}`;
- }
-
- if (!(when_market_opens && timer_components)) return null;
-
- const { opening_time, days_offset } = when_market_opens;
- let opening_time_banner = null;
- if (opening_time) {
- const formatted_opening_time = convertTimeFormat(opening_time);
- const target_date = moment(new Date()).add(days_offset, 'days');
- const opening_date = target_date.format('DD MMM YYYY');
- const opening_day = target_date.format('dddd');
- opening_time_banner = (
-
- ]}
- values={{
- formatted_opening_time,
- opening_day,
- opening_date,
- }}
- />
-
- );
- }
-
- if (is_loading) setLoading(false);
-
- return (
-
-
-
-
- {opening_time_banner}
-
-
-
-
- {timer_components}
-
-
-
- );
-});
-
-MarketCountdownTimer.propTypes = {
- is_main_page: PropTypes.bool,
- setIsTimerLoading: PropTypes.func,
- onMarketOpen: PropTypes.func,
- symbol: PropTypes.string.isRequired,
-};
-
-export default MarketCountdownTimer;
diff --git a/packages/trader/src/App/Components/Elements/market-countdown-timer.tsx b/packages/trader/src/App/Components/Elements/market-countdown-timer.tsx
new file mode 100644
index 000000000000..03ec30b9ec2a
--- /dev/null
+++ b/packages/trader/src/App/Components/Elements/market-countdown-timer.tsx
@@ -0,0 +1,224 @@
+import classNames from 'classnames';
+import React from 'react';
+import moment from 'moment';
+import { Text } from '@deriv/components';
+import { useIsMounted, WS, convertTimeFormat, isMarketClosed } from '@deriv/shared';
+import { Localize } from '@deriv/translations';
+import { observer } from '@deriv/stores';
+import { useTraderStore } from 'Stores/useTraderStores';
+import { TradingTimesRequest, TradingTimesResponse } from '@deriv/api-types';
+
+type TMarketCountDownTimer = {
+ is_main_page: boolean;
+ setIsTimerLoading: React.Dispatch>;
+ onMarketOpen: ReturnType['prepareTradeStore'];
+ symbol: ReturnType['symbol'];
+};
+
+type TWhenMarketOpens = {
+ days_offset: number;
+ opening_time: string;
+ remaining_time_to_open: number;
+};
+
+// check market in coming 7 days
+const days_to_check_before_exit = 7;
+
+const getTradingTimes = async (target_time: TradingTimesRequest['trading_times']) => {
+ const data = await WS.tradingTimes(target_time);
+ if (data.error) {
+ return { api_initial_load_error: data.error.message };
+ }
+ return data;
+};
+// eslint-disable-next-line consistent-return
+const getSymbol = (
+ target_symbol: string,
+ trading_times: NonNullable>
+) => {
+ let symbol;
+ const { markets } = trading_times;
+ for (let i = 0; i < markets.length; i++) {
+ const { submarkets } = markets[i];
+ if (submarkets) {
+ for (let j = 0; j < submarkets.length; j++) {
+ const { symbols } = submarkets[j];
+ symbol = symbols?.find(item => item.symbol === target_symbol);
+ if (symbol !== undefined) return symbol;
+ }
+ }
+ }
+};
+
+const calculateTimeLeft = (remaining_time_to_open: number) => {
+ const difference = remaining_time_to_open - Date.now();
+ return difference > 0
+ ? {
+ days: Math.floor(difference / (1000 * 60 * 60 * 24)),
+ hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
+ minutes: Math.floor((difference / 1000 / 60) % 60),
+ seconds: Math.floor((difference / 1000) % 60),
+ }
+ : {};
+};
+
+const MarketCountdownTimer = observer(
+ ({ is_main_page, setIsTimerLoading, onMarketOpen, symbol }: TMarketCountDownTimer) => {
+ const { active_symbols } = useTraderStore();
+ const isMounted = useIsMounted();
+ const [when_market_opens, setWhenMarketOpens] = React.useState({} as TWhenMarketOpens);
+ const [time_left, setTimeLeft] = React.useState(calculateTimeLeft(when_market_opens?.remaining_time_to_open));
+ const [is_loading, setLoading] = React.useState(true);
+
+ React.useEffect(() => {
+ if (!is_main_page || (is_main_page && isMarketClosed(active_symbols, symbol))) {
+ setLoading(true);
+ // eslint-disable-next-line consistent-return
+ // @ts-expect-error there is no explict return type because of if statements
+ const whenMarketOpens = async (days_offset: number, target_symbol: string) => {
+ // days_offset is 0 for today, 1 for tomorrow, etc.
+ if (days_offset > days_to_check_before_exit) return {};
+ let remaining_time_to_open;
+ const target_date = moment(new Date()).add(days_offset, 'days');
+ const api_response = await getTradingTimes(target_date.format('YYYY-MM-DD'));
+ if (!api_response.api_initial_load_error) {
+ const returned_symbol = getSymbol(target_symbol, api_response.trading_times);
+ const open = returned_symbol?.times.open as string[];
+ const close = returned_symbol?.times.close as string[];
+ const is_closed_all_day = open?.length === 1 && open[0] === '--' && close[0] === '--';
+ if (is_closed_all_day) {
+ // check tomorrow trading times
+ return whenMarketOpens(days_offset + 1, target_symbol);
+ }
+ const date_str = target_date.toISOString().substring(0, 11);
+ const getUTCDate = (hour: string) => new Date(`${date_str}${hour}Z`);
+ for (let i = 0; i < open?.length; i++) {
+ const diff = +getUTCDate(open[i]) - Date.now();
+ if (diff > 0) {
+ remaining_time_to_open = +getUTCDate(open[i]);
+ if (isMounted() && target_symbol === symbol) {
+ return setWhenMarketOpens({
+ days_offset,
+ opening_time: open[i],
+ remaining_time_to_open,
+ });
+ }
+ }
+ }
+ whenMarketOpens(days_offset + 1, target_symbol);
+ }
+ };
+
+ whenMarketOpens(0, symbol);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [symbol]);
+
+ React.useEffect(() => {
+ let timer: ReturnType;
+ if (when_market_opens?.remaining_time_to_open) {
+ timer = setTimeout(() => {
+ setTimeLeft(calculateTimeLeft(when_market_opens.remaining_time_to_open));
+ if (+new Date(when_market_opens.remaining_time_to_open) - +new Date() < 1000) {
+ setLoading(true);
+ if (is_main_page) onMarketOpen(false);
+ }
+ }, 1000);
+ }
+ return () => {
+ if (timer) {
+ clearTimeout(timer);
+ }
+ };
+ }, [time_left, when_market_opens, onMarketOpen, is_main_page]);
+
+ React.useEffect(() => {
+ if (!is_loading) setIsTimerLoading(false);
+ }, [is_loading, setIsTimerLoading]);
+
+ let timer_components = '';
+
+ if (Object.keys(time_left).length) {
+ const hours = (Number(time_left.days) * 24 + Number(time_left.hours)).toString().padStart(2, '0');
+ const minutes = Number(time_left.minutes).toString().padStart(2, '0');
+ const seconds = Number(time_left.seconds).toString().padStart(2, '0');
+ timer_components = `${hours}:${minutes}:${seconds}`;
+ }
+
+ if (!(when_market_opens && timer_components)) return null;
+
+ const { opening_time, days_offset } = when_market_opens;
+ let opening_time_banner = null;
+ if (opening_time) {
+ const formatted_opening_time = convertTimeFormat(opening_time);
+ const target_date = moment(new Date()).add(days_offset, 'days');
+ const opening_date = target_date.format('DD MMM YYYY');
+ const opening_day = target_date.format('dddd');
+ opening_time_banner = (
+
+ ]}
+ values={{
+ formatted_opening_time,
+ opening_day,
+ opening_date,
+ }}
+ />
+
+ );
+ }
+
+ if (is_loading) setLoading(false);
+
+ return (
+
+
+
+
+ {opening_time_banner}
+
+
+
+
+ {timer_components}
+
+
+
+ );
+ }
+);
+
+export default MarketCountdownTimer;
diff --git a/packages/trader/src/App/Components/Elements/market-is-closed-overlay.jsx b/packages/trader/src/App/Components/Elements/market-is-closed-overlay.tsx
similarity index 68%
rename from packages/trader/src/App/Components/Elements/market-is-closed-overlay.jsx
rename to packages/trader/src/App/Components/Elements/market-is-closed-overlay.tsx
index a68ab239d67c..e2c58ab7180b 100644
--- a/packages/trader/src/App/Components/Elements/market-is-closed-overlay.jsx
+++ b/packages/trader/src/App/Components/Elements/market-is-closed-overlay.tsx
@@ -1,14 +1,29 @@
import classNames from 'classnames';
import React from 'react';
-import PropTypes from 'prop-types';
import { Button, Text } from '@deriv/components';
import { localize, Localize } from '@deriv/translations';
-import MarketCountdownTimer from './market-countdown-timer.jsx';
+import MarketCountdownTimer from './market-countdown-timer';
+import { useStore } from '@deriv/stores';
+import { useTraderStore } from 'Stores/useTraderStores.js';
-const MarketIsClosedOverlay = ({ is_eu, is_synthetics_trading_market_available, onClick, onMarketOpen, symbol }) => {
+type TMarketIsClosedOverlay = {
+ is_eu: ReturnType['client']['is_eu'];
+ is_synthetics_trading_market_available: ReturnType['is_synthetics_trading_market_available'];
+ onClick: () => void;
+ onMarketOpen: React.ComponentProps['onMarketOpen'];
+ symbol: ReturnType['symbol'];
+};
+
+const MarketIsClosedOverlay = ({
+ is_eu,
+ is_synthetics_trading_market_available,
+ onClick,
+ onMarketOpen,
+ symbol,
+}: TMarketIsClosedOverlay) => {
const [is_timer_loading, setIsTimerLoading] = React.useState(true);
- let message = (
+ let message: JSX.Element | null = (
);
let btn_lbl = localize('Try Synthetic Indices');
@@ -45,12 +60,4 @@ const MarketIsClosedOverlay = ({ is_eu, is_synthetics_trading_market_available,
);
};
-MarketIsClosedOverlay.propTypes = {
- is_eu: PropTypes.bool,
- is_synthetics_trading_market_available: PropTypes.bool,
- onClick: PropTypes.func,
- onMarketOpen: PropTypes.func,
- symbol: PropTypes.string,
-};
-
export default MarketIsClosedOverlay;
diff --git a/packages/trader/src/App/Containers/ProgressSliderStream/__tests__/progress-slider-stream.spec.jsx b/packages/trader/src/App/Containers/ProgressSliderStream/__tests__/progress-slider-stream.spec.jsx
deleted file mode 100644
index 76db96aadf64..000000000000
--- a/packages/trader/src/App/Containers/ProgressSliderStream/__tests__/progress-slider-stream.spec.jsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import React from 'react';
-import { screen, render } from '@testing-library/react';
-import { mockStore } from '@deriv/stores';
-import TraderProviders from '../../../../trader-providers';
-import ProgressSliderStream from '../progress-slider-stream';
-
-jest.mock('@deriv/components', () => ({
- ...jest.requireActual('@deriv/components'),
- ProgressSlider: () => Mocked Progress Slider
,
-}));
-
-const contract_info = {
- contract_type: 'TEST',
- date_expiry: 1222222224,
- date_start: 1222222222,
- tick_count: 2,
- tick_stream: [
- { epoch: 1, tick: 1, tick_display_value: '300' },
- { epoch: 2, tick: 2, tick_display_value: '302' },
- ],
-};
-
-describe('', () => {
- const mockProgressSliderStream = (mocked_store, contract_info = null) => {
- return (
-
-
-
- );
- };
-
- it('should not render if contract_info is falsy', () => {
- const mock_root_store = mockStore({});
- render(mockProgressSliderStream(mock_root_store));
-
- expect(screen.queryByText('Mocked Progress Slider')).not.toBeInTheDocument();
- });
- it('should render if contract_info was passed in props', () => {
- const mock_root_store = mockStore({});
- render(mockProgressSliderStream(mock_root_store, contract_info));
-
- expect(screen.getByText('Mocked Progress Slider')).toBeInTheDocument();
- });
-});
diff --git a/packages/trader/src/App/Containers/ProgressSliderStream/index.js b/packages/trader/src/App/Containers/ProgressSliderStream/index.js
deleted file mode 100644
index 657c6ba7065a..000000000000
--- a/packages/trader/src/App/Containers/ProgressSliderStream/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export default from './progress-slider-stream.jsx';
diff --git a/packages/trader/src/App/Containers/ProgressSliderStream/progress-slider-stream.jsx b/packages/trader/src/App/Containers/ProgressSliderStream/progress-slider-stream.jsx
deleted file mode 100644
index 34409af133c9..000000000000
--- a/packages/trader/src/App/Containers/ProgressSliderStream/progress-slider-stream.jsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { ProgressSlider } from '@deriv/components';
-import { getCardLabels, getCurrentTick } from '@deriv/shared';
-import { observer, useStore } from '@deriv/stores';
-
-const ProgressSliderStream = observer(({ contract_info }) => {
- 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);
-
- return (
-
- );
-});
-
-ProgressSliderStream.propTypes = {
- contract_info: PropTypes.object,
-};
-
-export default ProgressSliderStream;
diff --git a/packages/trader/src/App/Containers/populate-header.jsx b/packages/trader/src/App/Containers/populate-header.jsx
index 74127c7c9c33..6cb78ddd14cc 100644
--- a/packages/trader/src/App/Containers/populate-header.jsx
+++ b/packages/trader/src/App/Containers/populate-header.jsx
@@ -1,15 +1,14 @@
import React from 'react';
-import TogglePositionsMobile from 'App/Components/Elements/TogglePositions/toggle-positions-mobile.jsx';
+import TogglePositionsMobile from 'App/Components/Elements/TogglePositions/toggle-positions-mobile';
import { filterByContractType } from 'App/Components/Elements/PositionsDrawer/helpers';
import { useTraderStore } from 'Stores/useTraderStores';
import { observer, useStore } from '@deriv/stores';
import { TURBOS, VANILLALONG, isTurbosContract, isVanillaContract } from '@deriv/shared';
const PopulateHeader = observer(() => {
- const { portfolio, ui, client } = useStore();
+ const { portfolio, client } = useStore();
const { symbol, contract_type: trade_contract_type } = useTraderStore();
const { currency: positions_currency } = client;
- const { disableApp, enableApp } = ui;
const {
active_positions_count,
all_positions: positions,
@@ -37,12 +36,10 @@ const PopulateHeader = observer(() => {
return (
diff --git a/packages/trader/src/App/Containers/trade-footer-extensions.jsx b/packages/trader/src/App/Containers/trade-footer-extensions.tsx
similarity index 82%
rename from packages/trader/src/App/Containers/trade-footer-extensions.jsx
rename to packages/trader/src/App/Containers/trade-footer-extensions.tsx
index 702950f5ebca..8643c94f5987 100644
--- a/packages/trader/src/App/Containers/trade-footer-extensions.jsx
+++ b/packages/trader/src/App/Containers/trade-footer-extensions.tsx
@@ -1,11 +1,11 @@
-import PropTypes from 'prop-types';
import React from 'react';
-import { withRouter } from 'react-router-dom';
+import { RouteComponentProps, withRouter } from 'react-router-dom';
import { routes } from '@deriv/shared';
-import TogglePositions from 'App/Components/Elements/TogglePositions';
+import TogglePositions from '../Components/Elements/TogglePositions/toggle-positions';
import { observer, useStore } from '@deriv/stores';
-const TradeFooterExtensions = observer(() => {
+const TradeFooterExtensions = observer((props: RouteComponentProps) => {
+ const { location } = props;
const { client, portfolio, ui } = useStore();
const { is_logged_in } = client;
const { active_positions_count } = portfolio;
@@ -40,8 +40,4 @@ const TradeFooterExtensions = observer(() => {
return null;
});
-TradeFooterExtensions.propTypes = {
- location: PropTypes.object,
-};
-
export default withRouter(TradeFooterExtensions);
diff --git a/packages/trader/src/App/app.tsx b/packages/trader/src/App/app.tsx
index a2bfedb085fb..bbafd8fa512f 100644
--- a/packages/trader/src/App/app.tsx
+++ b/packages/trader/src/App/app.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import Loadable from 'react-loadable';
import Routes from 'App/Containers/Routes/routes.jsx';
import TradeHeaderExtensions from 'App/Containers/trade-header-extensions';
-import TradeFooterExtensions from 'App/Containers/trade-footer-extensions.jsx';
+import TradeFooterExtensions from 'App/Containers/trade-footer-extensions';
import TradeSettingsExtensions from 'App/Containers/trade-settings-extensions';
import { NetworkStatusToastErrorPopup } from 'Modules/Trading/Containers/toast-popup';
import initStore from './init-store';
diff --git a/packages/trader/src/Modules/Contract/Components/Digits/digits.jsx b/packages/trader/src/Modules/Contract/Components/Digits/digits.tsx
similarity index 66%
rename from packages/trader/src/Modules/Contract/Components/Digits/digits.jsx
rename to packages/trader/src/Modules/Contract/Components/Digits/digits.tsx
index 8436d533dde2..e963a30c2ee7 100644
--- a/packages/trader/src/Modules/Contract/Components/Digits/digits.jsx
+++ b/packages/trader/src/Modules/Contract/Components/Digits/digits.tsx
@@ -1,13 +1,59 @@
import classNames from 'classnames';
-import PropTypes from 'prop-types';
import React from 'react';
import { toJS } from 'mobx';
import { DesktopWrapper, MobileWrapper, Popover, Text } from '@deriv/components';
-import { getMarketNamesMap, isMobile, useIsMounted, isContractElapsed } from '@deriv/shared';
+import {
+ getMarketNamesMap,
+ isMobile,
+ useIsMounted,
+ isContractElapsed,
+ TContractStore,
+ TTickSpotData,
+} from '@deriv/shared';
import { localize, Localize } from '@deriv/translations';
import { Bounce, SlideIn } from 'App/Components/Animations';
import { DigitSpot, LastDigitPrediction } from '../LastDigitPrediction';
import 'Sass/app/modules/contract/digits.scss';
+import { useTraderStore } from 'Stores/useTraderStores';
+
+type TTraderStore = ReturnType;
+type TOnChangeStatus = { status: string | null | undefined; current_tick: number | null };
+type TOnLastDigitSpot = {
+ spot: string | null;
+ is_lost?: boolean;
+ is_selected_winning: boolean;
+ is_latest: boolean;
+ is_won?: boolean;
+};
+
+type TDigitsWrapper = TDigits & {
+ onChangeStatus?: (params: TOnChangeStatus) => void;
+ onLastDigitSpot?: (params: TOnLastDigitSpot) => void;
+};
+type TDigits = Pick & {
+ digits_array?: number[];
+ display_status?: TContractStore['display_status'];
+ is_digit_contract?: TContractStore['is_digit_contract'];
+ is_ended?: TContractStore['is_ended'];
+ is_trade_page?: boolean;
+ onDigitChange?: TTraderStore['onChange'];
+ selected_digit?: TTraderStore['last_digit'];
+ trade_type?: TTraderStore['contract_type'];
+ tick?: TTickSpotData;
+ underlying: TTraderStore['symbol'];
+};
+type TTickStream = NonNullable[number];
+type TTickData =
+ | TTickSpotData
+ | null
+ | undefined
+ | {
+ ask: TTickStream['tick'];
+ bid: TTickStream['tick'];
+ current_tick: number;
+ epoch: TTickStream['epoch'];
+ pip_size?: number;
+ };
const DigitsWrapper = ({
contract_info,
@@ -22,9 +68,9 @@ const DigitsWrapper = ({
trade_type,
onChangeStatus,
...props
-}) => {
+}: TDigitsWrapper) => {
const has_contract = contract_info.date_start;
- let tick = props.tick;
+ let tick: TTickData = props.tick;
const is_tick_ready = is_trade_page ? !!tick : true;
const is_contract_elapsed = is_trade_page ? isContractElapsed(contract_info, tick) : false;
@@ -35,13 +81,13 @@ const DigitsWrapper = ({
if (has_contract && !is_contract_elapsed) {
tick = null;
const tick_stream = contract_info.tick_stream;
- if (tick_stream && tick_stream.length) {
+ if (tick_stream?.length) {
const t = toJS(tick_stream.slice(-1)[0]);
tick = {
ask: t.tick,
bid: t.tick,
epoch: t.epoch,
- pip_size: t.tick_display_value.split('.')[1].length,
+ pip_size: t.tick_display_value?.split('.')[1].length,
current_tick: tick_stream.length,
};
}
@@ -49,7 +95,7 @@ const DigitsWrapper = ({
React.useEffect(() => {
if (onChangeStatus) {
- onChangeStatus({ status, current_tick: tick ? tick.current_tick : null });
+ onChangeStatus({ status, current_tick: tick && 'current_tick' in tick ? tick.current_tick : null });
}
}, [tick, is_trade_page, display_status, onChangeStatus, status]);
@@ -59,15 +105,15 @@ const DigitsWrapper = ({
// i.e - 40px + 6px left and 6px right padding/margin = 52
dimension={isMobile() ? 64 : 52}
has_entry_spot={!!contract_info.entry_tick}
- barrier={!is_contract_elapsed && is_tick_ready ? +contract_info.barrier : null}
- contract_type={!is_contract_elapsed && is_tick_ready ? contract_info.contract_type : null}
+ barrier={!is_contract_elapsed && is_tick_ready ? Number(contract_info.barrier) : null}
+ contract_type={!is_contract_elapsed && is_tick_ready ? contract_info.contract_type : ''}
digits={digits_array}
digits_info={!is_contract_elapsed && is_tick_ready ? digits_info : {}}
is_digit_contract={is_digit_contract}
is_ended={is_ended}
is_trade_page={is_trade_page}
- status={status}
- tick={tick}
+ status={status as React.ComponentProps['status']}
+ tick={tick as React.ComponentProps['tick']}
trade_type={trade_type}
onDigitChange={onDigitChange}
selected_digit={selected_digit}
@@ -76,28 +122,26 @@ const DigitsWrapper = ({
);
};
-const Digits = React.memo(props => {
- const [status, setStatus] = React.useState();
- const [current_tick, setCurrentTick] = React.useState();
- const [spot, setSpot] = React.useState();
- const [is_selected_winning, setIsSelectedWinning] = React.useState();
- const [is_latest, setIsLatest] = React.useState();
- const [is_won, setIsWon] = React.useState();
- const [is_lost, setIsLost] = React.useState();
+const Digits = React.memo((props: TDigits) => {
+ const [status, setStatus] = React.useState();
+ const [current_tick, setCurrentTick] = React.useState();
+ const [spot, setSpot] = React.useState();
+ const [is_selected_winning, setIsSelectedWinning] = React.useState();
+ const [is_won, setIsWon] = React.useState();
+ const [is_lost, setIsLost] = React.useState();
const isMounted = useIsMounted();
const { contract_info, digits_array, is_digit_contract, is_trade_page, underlying } = props;
- const onChangeStatus = params => {
+ const onChangeStatus = (params: TOnChangeStatus) => {
setStatus(params.status);
setCurrentTick(params.current_tick);
};
- const onLastDigitSpot = params => {
+ const onLastDigitSpot = (params: TOnLastDigitSpot) => {
setSpot(params.spot);
setIsLost(params.is_lost);
setIsSelectedWinning(params.is_selected_winning);
- setIsLatest(params.is_latest);
setIsWon(params.is_won);
};
@@ -105,7 +149,8 @@ const Digits = React.memo(props => {
const underlying_name = is_trade_page ? underlying : contract_info.underlying;
return localize('Last digit stats for latest 1000 ticks for {{underlying_name}}', {
- underlying_name: getMarketNamesMap()[underlying_name.toUpperCase()],
+ underlying_name:
+ getMarketNamesMap()[underlying_name?.toUpperCase() as keyof ReturnType],
});
};
@@ -151,7 +196,6 @@ const Digits = React.memo(props => {
current_spot={spot}
is_lost={is_lost}
is_selected_winning={is_selected_winning}
- is_visible={!!(is_latest && spot)}
is_won={is_won}
/>
@@ -164,18 +208,4 @@ const Digits = React.memo(props => {
Digits.displayName = 'Digits';
-Digits.propTypes = {
- contract_info: PropTypes.object,
- digits_array: PropTypes.array,
- digits_info: PropTypes.object,
- display_status: PropTypes.string,
- is_digit_contract: PropTypes.bool,
- is_ended: PropTypes.bool,
- is_trade_page: PropTypes.bool,
- trade_type: PropTypes.string,
- onDigitChange: PropTypes.func,
- selected_digit: PropTypes.number,
- underlying: PropTypes.string,
-};
-
export default Digits;
diff --git a/packages/trader/src/Modules/Contract/Components/Digits/index.js b/packages/trader/src/Modules/Contract/Components/Digits/index.js
index d46e4208466c..5a177415c03a 100644
--- a/packages/trader/src/Modules/Contract/Components/Digits/index.js
+++ b/packages/trader/src/Modules/Contract/Components/Digits/index.js
@@ -1,3 +1,3 @@
-import Digits from './digits.jsx';
+import Digits from './digits';
export default Digits;
diff --git a/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/digit-display.tsx b/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/digit-display.tsx
index 856cfe2e4aec..482d22dc692f 100644
--- a/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/digit-display.tsx
+++ b/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/digit-display.tsx
@@ -20,7 +20,7 @@ type TDigitDisplay = Pick, 'is_lost' | 'i
digit: number | null;
spot: string | null;
};
- selected_digit: number | boolean;
+ selected_digit?: number;
status: ProposalOpenContract['status'];
stats?: number | null;
value: number;
diff --git a/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/digit-spot.tsx b/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/digit-spot.tsx
index 18ee62ff7b95..0f8720f4314f 100644
--- a/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/digit-spot.tsx
+++ b/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/digit-spot.tsx
@@ -3,7 +3,7 @@ import React from 'react';
import { Text } from '@deriv/components';
type TDigitSpot = {
- current_spot: string | null;
+ current_spot?: string | null;
is_selected_winning?: boolean;
is_lost?: boolean;
is_won?: boolean;
diff --git a/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/last-digit-prediction.tsx b/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/last-digit-prediction.tsx
index b8dbabe9bbb2..bca5ba854ec4 100644
--- a/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/last-digit-prediction.tsx
+++ b/packages/trader/src/Modules/Contract/Components/LastDigitPrediction/last-digit-prediction.tsx
@@ -11,13 +11,13 @@ type TLastDigitPrediction = Pick<
'barrier' | 'is_digit_contract' | 'has_entry_spot' | 'onLastDigitSpot'
> & {
contract_type?: string;
- digits: number[];
+ digits?: number[];
digits_info: { [key: string]: { digit: number; spot: string } };
dimension: number;
is_ended?: boolean;
- is_trade_page: boolean;
- onDigitChange: (event: { target: { name: string; value: number } }) => void;
- selected_digit: number | boolean;
+ is_trade_page?: boolean;
+ onDigitChange?: (event: { target: { name: string; value: number } }) => void;
+ selected_digit?: number;
status?: ProposalOpenContract['status'];
tick?: TicksStreamResponse['tick'];
trade_type?: string;
@@ -138,7 +138,7 @@ const LastDigitPrediction = ({
value={idx}
onLastDigitSpot={onLastDigitSpot}
onSelect={isSelectableDigitType() ? handleSelect : null}
- selected_digit={isSelectableDigitType() ? selected_digit : false}
+ selected_digit={isSelectableDigitType() ? selected_digit : undefined}
/>
))}
diff --git a/packages/trader/src/Modules/Trading/Components/Elements/__tests__/purchase-button.spec.tsx b/packages/trader/src/Modules/Trading/Components/Elements/__tests__/purchase-button.spec.tsx
index 6fbdf17615dd..f8d1f5e18593 100644
--- a/packages/trader/src/Modules/Trading/Components/Elements/__tests__/purchase-button.spec.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Elements/__tests__/purchase-button.spec.tsx
@@ -31,7 +31,7 @@ const default_mocked_props = {
should_fade: false,
setPurchaseState: jest.fn(),
type: 'VANILLALONGCALL',
-};
+} as unknown as React.ComponentProps;
jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
diff --git a/packages/trader/src/Modules/Trading/Components/Elements/__tests__/purchase-fieldset.spec.tsx b/packages/trader/src/Modules/Trading/Components/Elements/__tests__/purchase-fieldset.spec.tsx
index aad213c17fc1..f48114e67eb9 100644
--- a/packages/trader/src/Modules/Trading/Components/Elements/__tests__/purchase-fieldset.spec.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Elements/__tests__/purchase-fieldset.spec.tsx
@@ -33,7 +33,7 @@ const default_mocked_props = {
purchased_states_arr: [true, false],
setPurchaseState: jest.fn(),
type: '',
-};
+} as unknown as React.ComponentProps;
jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
diff --git a/packages/trader/src/Modules/Trading/Components/Elements/mobile-widget.jsx b/packages/trader/src/Modules/Trading/Components/Elements/mobile-widget.jsx
index 972fddcaaeb1..3cc03e313cbc 100644
--- a/packages/trader/src/Modules/Trading/Components/Elements/mobile-widget.jsx
+++ b/packages/trader/src/Modules/Trading/Components/Elements/mobile-widget.jsx
@@ -3,7 +3,7 @@ import { Money } from '@deriv/components';
import { localize, Localize } from '@deriv/translations';
import { getExpiryType, getDurationMinMaxValues, getLocalizedBasis } from '@deriv/shared';
import { MultiplierAmountWidget } from 'Modules/Trading/Components/Form/TradeParams/Multiplier/widgets.jsx';
-import TradeParamsModal from '../../Containers/trade-params-mobile.jsx';
+import TradeParamsModal from '../../Containers/trade-params-mobile';
import { observer, useStore } from '@deriv/stores';
import { useTraderStore } from 'Stores/useTraderStores';
diff --git a/packages/trader/src/Modules/Trading/Components/Elements/payout-per-point-mobile.tsx b/packages/trader/src/Modules/Trading/Components/Elements/payout-per-point-mobile.tsx
index f2a409658087..fd24be61089d 100644
--- a/packages/trader/src/Modules/Trading/Components/Elements/payout-per-point-mobile.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Elements/payout-per-point-mobile.tsx
@@ -5,22 +5,10 @@ import Fieldset from 'App/Components/Form/fieldset';
import { observer } from '@deriv/stores';
import { getContractSubtype, isVanillaContract } from '@deriv/shared';
import { useTraderStore } from 'Stores/useTraderStores';
+import { TProposalTypeInfo } from 'Types';
type TProposalInfo = {
- [key: string]: {
- has_error?: boolean;
- id: string;
- has_increased?: boolean;
- message?: string;
- cancellation?: {
- ask_price: number;
- date_expiry: number;
- };
- growth_rate?: number;
- obj_contract_basis?: Record<'text' | 'value', string>;
- returns?: string;
- stake: string;
- };
+ [key: string]: TProposalTypeInfo;
};
const PayoutPerPointMobile = observer(() => {
diff --git a/packages/trader/src/Modules/Trading/Components/Elements/purchase-button.tsx b/packages/trader/src/Modules/Trading/Components/Elements/purchase-button.tsx
index 2d39b67f94e8..5f24ead4faeb 100644
--- a/packages/trader/src/Modules/Trading/Components/Elements/purchase-button.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Elements/purchase-button.tsx
@@ -3,11 +3,11 @@ import React from 'react';
import { DesktopWrapper, MobileWrapper, Money, IconTradeTypes, Text } from '@deriv/components';
import ContractInfo from 'Modules/Trading/Components/Form/Purchase/contract-info';
import { getContractTypeDisplay } from '@deriv/shared';
-import { TProposalTypeInfo } from 'Types';
+import { TProposalTypeInfo, TTradeStore } from 'Types';
type TPurchaseButton = {
basis: string;
- buy_info: { error?: string };
+ buy_info: TTradeStore['purchase_info'];
currency: string;
growth_rate: number;
has_deal_cancellation: boolean;
@@ -164,6 +164,7 @@ const PurchaseButton = ({
is_loading={is_loading}
is_multiplier={is_multiplier}
is_turbos={is_turbos}
+ is_vanilla={is_vanilla}
should_fade={should_fade}
proposal_info={info}
type={type}
diff --git a/packages/trader/src/Modules/Trading/Components/Elements/purchase-fieldset.tsx b/packages/trader/src/Modules/Trading/Components/Elements/purchase-fieldset.tsx
index 9dd0c883dfb5..b45321d42b1f 100644
--- a/packages/trader/src/Modules/Trading/Components/Elements/purchase-fieldset.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Elements/purchase-fieldset.tsx
@@ -5,11 +5,11 @@ import Fieldset from 'App/Components/Form/fieldset';
import ContractInfo from 'Modules/Trading/Components/Form/Purchase/contract-info';
import PurchaseButton from 'Modules/Trading/Components/Elements/purchase-button';
import CancelDealInfo from '../Form/Purchase/cancel-deal-info';
-import { TProposalTypeInfo } from 'Types';
+import { TProposalTypeInfo, TTradeStore } from 'Types';
type TPurchaseFieldset = {
basis: string;
- buy_info: { error?: string };
+ buy_info: TTradeStore['purchase_info'];
currency: string;
growth_rate: number;
has_cancellation: boolean;
@@ -119,6 +119,8 @@ const PurchaseFieldset = ({
is_vanilla={is_vanilla}
should_fade={should_fade}
type={type}
+ is_accumulator={is_accumulator}
+ growth_rate={growth_rate}
/>
)}
{
});
it('should render
component when click on ', () => {
- render(
);
+ render(
);
const dt_contract_dropdown = screen.getByTestId('dt_contract_dropdown');
fireEvent.click(dt_contract_dropdown);
diff --git a/packages/trader/src/Modules/Trading/Components/Form/ContractType/__tests__/contract-type-widget.spec.tsx b/packages/trader/src/Modules/Trading/Components/Form/ContractType/__tests__/contract-type-widget.spec.tsx
index 4e81e7dc06b2..a0d0f9bb48b7 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/ContractType/__tests__/contract-type-widget.spec.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/ContractType/__tests__/contract-type-widget.spec.tsx
@@ -72,7 +72,7 @@ describe('
', () => {
};
it('should render
component when click on ', () => {
- render(
);
+ render(
);
expect(screen.getByTestId('dt_contract_widget')).toBeInTheDocument();
});
});
diff --git a/packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-widget.tsx b/packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-widget.tsx
index 7f5224568e3a..ec166eee8c31 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-widget.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-widget.tsx
@@ -7,10 +7,15 @@ import { getContractTypeCategoryIcons, findContractCategory } from '../../../Hel
import { TContractCategory, TContractType, TList } from './types';
type TContractTypeWidget = {
- name?: string;
+ name: string;
value: TContractType['value'];
list: TContractCategory[];
- onChange: (event: DeepPartial
>) => void;
+ onChange: (e: {
+ target: {
+ name: string;
+ value: unknown;
+ };
+ }) => Promise;
languageChanged?: boolean;
};
diff --git a/packages/trader/src/Modules/Trading/Components/Form/Purchase/cancel-deal-info.tsx b/packages/trader/src/Modules/Trading/Components/Form/Purchase/cancel-deal-info.tsx
index febf2f6cc8de..3010d38f6a34 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/Purchase/cancel-deal-info.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/Purchase/cancel-deal-info.tsx
@@ -13,15 +13,12 @@ const CancelDealInfo = observer(({ proposal_info }: { proposal_info: TProposalTy
const error = has_error ?? !id;
const [is_row_layout, setIsRowLayout] = React.useState(false);
- const ref = React.useRef(null);
+ const ref = React.useRef(null);
React.useEffect(() => {
if (ref.current) {
- const el_height = ref.current.parentElement?.clientHeight;
- if (
- el_height &&
- ((el_height > 21 && isDesktop()) || ((el_height > 21 || getDecimalPlaces(currency) > 2) && isMobile()))
- ) {
+ const el_height = Number(ref.current.parentElement?.clientHeight);
+ if ((el_height > 21 && isDesktop()) || ((el_height > 21 || getDecimalPlaces(currency) > 2) && isMobile())) {
setIsRowLayout(true);
} else {
setIsRowLayout(false);
diff --git a/packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.jsx b/packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.tsx
similarity index 77%
rename from packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.jsx
rename to packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.tsx
index 209a7d98a52e..6c3a53f41e0e 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.jsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.tsx
@@ -1,44 +1,23 @@
import classNames from 'classnames';
-import PropTypes from 'prop-types';
import React from 'react';
-import { DesktopWrapper, Icon, MobileWrapper, Money, Popover, Text } from '@deriv/components';
+import { DesktopWrapper, MobileWrapper, Money, Popover, Text } from '@deriv/components';
import { Localize, localize } from '@deriv/translations';
import { getContractSubtype, getCurrencyDisplayCode, getLocalizedBasis, getGrowthRatePercentage } from '@deriv/shared';
+import { useTraderStore } from 'Stores/useTraderStores';
import CancelDealInfo from './cancel-deal-info';
+import ValueMovement from './value-movement';
+import { TProposalTypeInfo } from 'Types';
-export const ValueMovement = ({
- has_error_or_not_loaded,
- proposal_info,
- currency,
- has_increased,
- is_turbos,
- is_vanilla,
- value,
- show_currency = true,
-}) => (
-
-
- {!has_error_or_not_loaded && (
-
- )}
-
-
- {!has_error_or_not_loaded && has_increased !== null && has_increased ? (
-
- ) : (
-
- )}
-
-
-);
+type TContractInfo = Pick<
+ ReturnType,
+ 'basis' | 'growth_rate' | 'is_accumulator' | 'is_turbos' | 'is_vanilla' | 'is_multiplier' | 'currency'
+> & {
+ has_increased?: boolean | null;
+ is_loading: boolean;
+ proposal_info: TProposalTypeInfo;
+ should_fade: boolean;
+ type: string;
+};
const ContractInfo = ({
basis,
@@ -53,7 +32,7 @@ const ContractInfo = ({
should_fade,
proposal_info,
type,
-}) => {
+}: TContractInfo) => {
const localized_basis = getLocalizedBasis();
const stakeOrPayout = () => {
switch (basis) {
@@ -72,7 +51,7 @@ const ContractInfo = ({
};
const has_error_or_not_loaded = proposal_info.has_error || !proposal_info.id;
- const basis_text = has_error_or_not_loaded ? stakeOrPayout() : proposal_info.obj_contract_basis.text;
+ const basis_text = has_error_or_not_loaded ? stakeOrPayout() : proposal_info?.obj_contract_basis?.text || '';
const { message, obj_contract_basis, stake } = proposal_info;
const setHintMessage = () => {
@@ -182,19 +161,4 @@ const ContractInfo = ({
);
};
-ContractInfo.propTypes = {
- basis: PropTypes.string,
- currency: PropTypes.string,
- growth_rate: PropTypes.number,
- has_increased: PropTypes.bool,
- is_accumulator: PropTypes.bool,
- is_multiplier: PropTypes.bool,
- is_turbos: PropTypes.bool,
- is_vanilla: PropTypes.bool,
- is_loading: PropTypes.bool,
- proposal_info: PropTypes.object,
- should_fade: PropTypes.bool,
- type: PropTypes.string,
-};
-
export default ContractInfo;
diff --git a/packages/trader/src/Modules/Trading/Components/Form/Purchase/value-movement.tsx b/packages/trader/src/Modules/Trading/Components/Form/Purchase/value-movement.tsx
new file mode 100644
index 000000000000..ff65e52dfc75
--- /dev/null
+++ b/packages/trader/src/Modules/Trading/Components/Form/Purchase/value-movement.tsx
@@ -0,0 +1,50 @@
+import classNames from 'classnames';
+import React from 'react';
+import { Icon, Money } from '@deriv/components';
+import ContractInfo from './contract-info';
+
+type TValueMovement = Partial<
+ Pick<
+ React.ComponentProps,
+ 'is_turbos' | 'is_vanilla' | 'currency' | 'has_increased' | 'proposal_info'
+ >
+> & {
+ has_error_or_not_loaded: boolean;
+ value?: number | string;
+ show_currency?: boolean;
+};
+const ValueMovement = ({
+ has_error_or_not_loaded,
+ proposal_info,
+ currency,
+ has_increased,
+ is_turbos = false,
+ is_vanilla = false,
+ value,
+ show_currency = true,
+}: TValueMovement) => (
+
+
+ {!has_error_or_not_loaded && (
+
+ )}
+
+
+ {!has_error_or_not_loaded && has_increased !== null && has_increased ? (
+
+ ) : (
+
+ )}
+
+
+);
+
+export default ValueMovement;
diff --git a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/Duration/duration-wrapper.jsx b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/Duration/duration-wrapper.jsx
index 8ef7596439f6..eb20274ae761 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/Duration/duration-wrapper.jsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/Duration/duration-wrapper.jsx
@@ -1,6 +1,4 @@
-import PropTypes from 'prop-types';
import React from 'react';
-import { PropTypes as MobxPropTypes } from 'mobx-react';
import { getDurationMinMaxValues } from '@deriv/shared';
import Duration from './duration.jsx';
import { observer, useStore } from '@deriv/stores';
@@ -195,18 +193,4 @@ const DurationWrapper = observer(() => {
);
});
-DurationWrapper.propTypes = {
- duration_d: PropTypes.number,
- duration_h: PropTypes.number,
- duration_m: PropTypes.number,
- duration_s: PropTypes.number,
- duration_unit: PropTypes.string,
- duration_units_list: MobxPropTypes.arrayOrObservableArray,
- getDurationFromUnit: PropTypes.func,
- is_minimized: PropTypes.bool,
- sessions: MobxPropTypes.arrayOrObservableArray,
- start_time: PropTypes.string,
- symbol: PropTypes.string,
-};
-
export default DurationWrapper;
diff --git a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/allow-equals.jsx b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/allow-equals.tsx
similarity index 72%
rename from packages/trader/src/Modules/Trading/Components/Form/TradeParams/allow-equals.jsx
rename to packages/trader/src/Modules/Trading/Components/Form/TradeParams/allow-equals.tsx
index 0d3ad0614154..448e3419ba38 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/allow-equals.jsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/allow-equals.tsx
@@ -1,5 +1,4 @@
import React from 'react';
-import PropTypes from 'prop-types';
import { Popover, Checkbox } from '@deriv/components';
import { localize } from '@deriv/translations';
import {
@@ -7,6 +6,22 @@ import {
hasDurationForCallPutEqual,
isRiseFallEqual,
} from 'Stores/Modules/Trading/Helpers/allow-equals';
+import { useTraderStore } from 'Stores/useTraderStores';
+
+type TTradeStore = Pick<
+ ReturnType,
+ | 'contract_start_type'
+ | 'contract_type'
+ | 'contract_types_list'
+ | 'duration_unit'
+ | 'expiry_type'
+ | 'has_equals_only'
+>;
+
+type TAllowEquals = TTradeStore & {
+ onChange: (e: { target: { name: string; value: number } }) => Promise;
+ value: number;
+};
const AllowEquals = ({
contract_start_type,
@@ -17,7 +32,7 @@ const AllowEquals = ({
onChange,
value,
has_equals_only,
-}) => {
+}: TAllowEquals) => {
const has_callputequal_duration = hasDurationForCallPutEqual(
contract_types_list,
duration_unit,
@@ -28,10 +43,12 @@ const AllowEquals = ({
const has_allow_equals =
isRiseFallEqual(contract_type) && (has_callputequal_duration || expiry_type === 'endtime') && has_callputequal;
- const changeValue = e => {
+ const changeValue: React.ComponentProps['onChange'] = e => {
e.persist();
- const { name, checked } = e.target;
- onChange({ target: { name, value: Number(checked) } });
+ if ('checked' in e.target) {
+ const { name, checked } = e.target;
+ onChange({ target: { name, value: Number(checked) } });
+ }
};
return (
@@ -61,15 +78,4 @@ const AllowEquals = ({
);
};
-AllowEquals.propTypes = {
- contract_start_type: PropTypes.string,
- contract_type: PropTypes.string,
- contract_types_list: PropTypes.object,
- duration_unit: PropTypes.string,
- expiry_type: PropTypes.string,
- has_equals_only: PropTypes.bool,
- onChange: PropTypes.func,
- value: PropTypes.number,
-};
-
export default AllowEquals;
diff --git a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount-mobile.jsx b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount-mobile.tsx
similarity index 86%
rename from packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount-mobile.jsx
rename to packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount-mobile.tsx
index 2e5439c3aff1..b968f272ee63 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount-mobile.jsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount-mobile.tsx
@@ -7,6 +7,24 @@ import { Money, Numpad, Tabs } from '@deriv/components';
import { getDecimalPlaces, isEmptyObject } from '@deriv/shared';
import MinMaxStakeInfo from './min-max-stake-info';
+type TAmountMobile = React.ComponentProps & {
+ amount_tab_idx?: number;
+ setAmountTabIdx: React.ComponentProps['onTabItemClick'];
+ stake_value: string | number;
+ payout_value: string | number;
+};
+
+type TBasis = {
+ basis: string;
+ duration_unit: string;
+ duration_value: number;
+ toggleModal: () => void;
+ has_duration_error: boolean;
+ selected_basis: string | number;
+ setSelectedAmount: (basis: string, num: string | number) => void;
+ setAmountError: (has_error: boolean) => void;
+};
+
const Basis = observer(
({
basis,
@@ -17,7 +35,7 @@ const Basis = observer(
selected_basis,
setSelectedAmount,
setAmountError,
- }) => {
+ }: TBasis) => {
const { ui, client } = useStore();
const { addToast } = ui;
const { currency } = client;
@@ -27,21 +45,21 @@ const Basis = observer(
is_vanilla,
onChangeMultiple,
stake_boundary,
- trade_amount,
- trade_basis,
- trade_duration_unit,
- trade_duration,
+ amount: trade_amount,
+ basis: trade_basis,
+ duration_unit: trade_duration_unit,
+ duration: trade_duration,
} = useTraderStore();
const { min_stake, max_stake } = stake_boundary[contract_type.toUpperCase()] || {};
const user_currency_decimal_places = getDecimalPlaces(currency);
- const onNumberChange = num => {
+ const onNumberChange = (num: number | string) => {
setSelectedAmount(basis, num);
validateAmount(num);
};
- const formatAmount = value =>
- !isNaN(value) && value !== '' ? Number(value).toFixed(user_currency_decimal_places) : value;
- const setBasisAndAmount = amount => {
- const on_change_obj = {};
+ const formatAmount = (value: number | string) =>
+ !isNaN(+value) && value !== '' ? Number(value).toFixed(user_currency_decimal_places) : value;
+ const setBasisAndAmount = (amount: number | string) => {
+ const on_change_obj: Partial> = {};
// Check for any duration changes in Duration trade params Tab before sending onChange object
if (duration_unit !== trade_duration_unit && !has_duration_error)
@@ -50,7 +68,7 @@ const Basis = observer(
if (amount !== trade_amount || basis !== trade_basis) {
on_change_obj.basis = basis;
- on_change_obj.amount = amount;
+ on_change_obj.amount = +amount;
}
if (!isEmptyObject(on_change_obj)) onChangeMultiple(on_change_obj);
@@ -59,7 +77,7 @@ const Basis = observer(
const zero_decimals = Number('0').toFixed(getDecimalPlaces(currency));
const min_amount = parseFloat(zero_decimals.toString().replace(/.$/, '1'));
- const validateAmount = value => {
+ const validateAmount = (value: number | string) => {
const localized_message = ;
const min_max_stake_message = (
{
+ }: TAmountMobile) => {
const { basis, basis_list } = useTraderStore();
const has_selected_tab_idx = typeof amount_tab_idx !== 'undefined';
const active_index = has_selected_tab_idx ? amount_tab_idx : basis_list.findIndex(b => b.value === basis);
diff --git a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount.jsx b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount.tsx
similarity index 88%
rename from packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount.jsx
rename to packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount.tsx
index 9352e4b03e24..c33cf5e80ab1 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount.jsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/amount.tsx
@@ -1,29 +1,37 @@
import { AMOUNT_MAX_LENGTH, addComma, getDecimalPlaces } from '@deriv/shared';
import { ButtonToggle, Dropdown, InputField } from '@deriv/components';
import { Localize, localize } from '@deriv/translations';
-
-import AllowEquals from './allow-equals.jsx';
+import AllowEquals from './allow-equals';
import Fieldset from 'App/Components/Form/fieldset';
import Multiplier from './Multiplier/multiplier.jsx';
import MultipliersInfo from './Multiplier/info.jsx';
import MinMaxStakeInfo from './min-max-stake-info';
-import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
import { useTraderStore } from 'Stores/useTraderStores';
import { observer, useStore } from '@deriv/stores';
+type TInput = {
+ amount: string | number;
+ currency: string;
+ current_focus: string | null;
+ error_messages?: string[];
+ is_disabled?: boolean;
+ is_single_currency: boolean;
+ onChange: (e: { target: { name: string; value: number | string } }) => void;
+ setCurrentFocus: (name: string | null) => void;
+};
+
export const Input = ({
amount,
currency,
current_focus,
error_messages,
- is_nativepicker,
is_single_currency,
is_disabled,
onChange,
setCurrentFocus,
-}) => (
+}: TInput) => (
);
-const Amount = observer(({ is_minimized, is_nativepicker }) => {
+const Amount = observer(({ is_minimized = false }: { is_minimized?: boolean }) => {
const { ui, client } = useStore();
const { currencies_list, is_single_currency } = client;
const { setCurrentFocus, current_focus } = ui;
@@ -82,9 +89,7 @@ const Amount = observer(({ is_minimized, is_nativepicker }) => {
if (is_minimized) {
return (
-
- {(basis_list.find(o => o.value === basis) || {}).text}
-
+
{basis_list.find(o => o.value === basis)?.text}
{
);
}
- const error_messages = validation_errors.amount;
+ const error_messages = validation_errors?.amount;
const getBasisList = () => basis_list.map(item => ({ text: item.text, value: item.value }));
@@ -140,12 +145,10 @@ const Amount = observer(({ is_minimized, is_nativepicker }) => {
current_focus={current_focus}
error_messages={error_messages}
is_single_currency={is_single_currency}
- is_nativepicker={is_nativepicker}
onChange={onChange}
setCurrentFocus={setCurrentFocus}
/>
{
current_focus={current_focus}
error_messages={error_messages}
is_single_currency={is_single_currency}
- is_nativepicker={is_nativepicker}
is_disabled={has_open_accu_contract}
onChange={onChange}
setCurrentFocus={setCurrentFocus}
@@ -177,13 +179,14 @@ const Amount = observer(({ is_minimized, is_nativepicker }) => {
duration_unit={duration_unit}
expiry_type={expiry_type}
onChange={onChange}
- value={parseInt(is_equal)}
+ value={Number(is_equal)}
has_equals_only={has_equals_only}
/>
{is_multiplier && (
{
);
});
-Amount.propTypes = {
- is_minimized: PropTypes.bool,
- is_nativepicker: PropTypes.bool,
-};
-
export default Amount;
diff --git a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/barrier.jsx b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/barrier.tsx
similarity index 94%
rename from packages/trader/src/Modules/Trading/Components/Form/TradeParams/barrier.jsx
rename to packages/trader/src/Modules/Trading/Components/Form/TradeParams/barrier.tsx
index 7ca8412e989f..e8f19de41855 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/barrier.jsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/barrier.tsx
@@ -1,15 +1,19 @@
import classNames from 'classnames';
-import PropTypes from 'prop-types';
import React from 'react';
import { DesktopWrapper, Icon, InputField, MobileWrapper, Modal, Text, usePrevious } from '@deriv/components';
import Fieldset from 'App/Components/Form/fieldset';
-import { ValueMovement } from '../Purchase/contract-info';
+import ValueMovement from '../Purchase/value-movement';
import { observer, useStore } from '@deriv/stores';
import { useTraderStore } from 'Stores/useTraderStores';
import { localize } from '@deriv/translations';
import LabeledQuantityInputMobile from '../LabeledQuantityInputMobile';
-const Barrier = observer(({ is_minimized, is_absolute_only }) => {
+type TBarrier = {
+ is_minimized?: boolean;
+ is_absolute_only?: boolean;
+};
+
+const Barrier = observer(({ is_minimized, is_absolute_only }: TBarrier) => {
const { ui } = useStore();
const { current_focus, setCurrentFocus } = ui;
const {
@@ -25,11 +29,12 @@ const Barrier = observer(({ is_minimized, is_absolute_only }) => {
} = useTraderStore();
const [show_modal, setShowModal] = React.useState(false);
const type_with_current_spot = Object.keys(trade_types).find(type => proposal_info?.[type]?.spot);
- const contract_info = proposal_info?.[type_with_current_spot];
+ let contract_info, has_spot_increased;
+ if (type_with_current_spot) contract_info = proposal_info?.[type_with_current_spot];
const current_spot = contract_info?.spot || '';
const current_barrier_price = contract_info?.barrier || '';
const previous_spot = usePrevious(current_spot);
- const has_spot_increased = current_spot > previous_spot;
+ if (previous_spot) has_spot_increased = Number(current_spot) > previous_spot;
const barrier_title = barrier_count === 1 ? localize('Barrier') : localize('Barriers');
const has_error_or_not_loaded = contract_info?.has_error || !contract_info?.id;
@@ -49,7 +54,7 @@ const Barrier = observer(({ is_minimized, is_absolute_only }) => {
// TODO: Some contracts yet to be implemented in app.deriv.com allow only absolute barrier, hence the prop
const is_absolute_barrier = is_day_duration || is_absolute_only;
- const format = value => {
+ const format = (value: string) => {
const float_value = parseFloat(value);
let final_value;
if (Math.sign(float_value) === -1) {
@@ -86,7 +91,7 @@ const Barrier = observer(({ is_minimized, is_absolute_only }) => {
)}
current_focus={current_focus}
onChange={onChange}
- error_messages={validation_errors.barrier_1 || []}
+ error_messages={validation_errors?.barrier_1 || []}
is_float
is_signed
setCurrentFocus={setCurrentFocus}
@@ -103,7 +108,7 @@ const Barrier = observer(({ is_minimized, is_absolute_only }) => {
classNameInput='trade-container__input'
current_focus={current_focus}
onChange={onChange}
- error_messages={validation_errors.barrier_2}
+ error_messages={validation_errors?.barrier_2}
is_float
is_signed
setCurrentFocus={setCurrentFocus}
@@ -155,7 +160,7 @@ const Barrier = observer(({ is_minimized, is_absolute_only }) => {
current_focus={current_focus}
onChange={onChange}
error_messages={
- (barrier_count === 1 ? validation_errors.barrier_1 : validation_errors.barrier_2) || []
+ (barrier_count === 1 ? validation_errors?.barrier_1 : validation_errors?.barrier_2) || []
}
error_message_alignment='top'
is_float
@@ -219,9 +224,4 @@ const Barrier = observer(({ is_minimized, is_absolute_only }) => {
);
});
-Barrier.propTypes = {
- is_absolute_only: PropTypes.bool,
- is_minimized: PropTypes.bool,
-};
-
export default Barrier;
diff --git a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/last-digit.jsx b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/last-digit.tsx
similarity index 80%
rename from packages/trader/src/Modules/Trading/Components/Form/TradeParams/last-digit.jsx
rename to packages/trader/src/Modules/Trading/Components/Form/TradeParams/last-digit.tsx
index 46edec68c99a..58930d65d309 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/last-digit.jsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/last-digit.tsx
@@ -1,4 +1,3 @@
-import PropTypes from 'prop-types';
import React from 'react';
import { isDesktop } from '@deriv/shared';
import { localize } from '@deriv/translations';
@@ -7,7 +6,11 @@ import Fieldset from 'App/Components/Form/fieldset';
import { observer } from '@deriv/stores';
import { useTraderStore } from 'Stores/useTraderStores';
-const LastDigit = observer(({ is_minimized }) => {
+type TLastDigit = {
+ is_minimized?: boolean;
+};
+
+const LastDigit = observer(({ is_minimized }: TLastDigit) => {
const { onChange, last_digit } = useTraderStore();
if (is_minimized) {
return {`${localize('Last Digit')}: ${last_digit}`}
;
@@ -29,10 +32,4 @@ const LastDigit = observer(({ is_minimized }) => {
);
});
-LastDigit.propTypes = {
- is_minimized: PropTypes.bool,
- last_digit: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
- onChange: PropTypes.func,
-};
-
export default LastDigit;
diff --git a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/min-max-stake-info.tsx b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/min-max-stake-info.tsx
index 8a842efeb757..6c74f6de5cce 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/TradeParams/min-max-stake-info.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/TradeParams/min-max-stake-info.tsx
@@ -6,16 +6,16 @@ import { isMobile } from '@deriv/shared';
type TMinMaxStakeInfo = {
className?: string;
- min_stake: number;
- max_stake: number;
- currency: string;
+ min_stake?: number;
+ max_stake?: number;
+ currency?: string;
};
const MinMaxStakeInfo = ({ className, currency, max_stake, min_stake }: TMinMaxStakeInfo) => {
return (
- {!isNaN(min_stake) &&
- !isNaN(max_stake) &&
+ {!isNaN(Number(min_stake)) &&
+ !isNaN(Number(max_stake)) &&
['Min', 'Max'].map(text => (
({
}));
jest.mock('../../../Containers/contract-type', () => jest.fn(() => 'MockedContractType'));
jest.mock('../../../Containers/purchase', () => jest.fn(() => 'MockedPurchase'));
-jest.mock('../../../Containers/trade-params.jsx', () => jest.fn(() => 'MockedTradeParams'));
+jest.mock('../../../Containers/trade-params', () => jest.fn(() => 'MockedTradeParams'));
const mock_props = {
is_market_closed: false,
diff --git a/packages/trader/src/Modules/Trading/Components/Form/screen-large.tsx b/packages/trader/src/Modules/Trading/Components/Form/screen-large.tsx
index 6916fd8d0c97..cd917012fd3a 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/screen-large.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/screen-large.tsx
@@ -4,7 +4,7 @@ import { TradeParamsLoader } from 'App/Components/Elements/ContentLoader';
import Fieldset from 'App/Components/Form/fieldset';
import ContractType from '../../Containers/contract-type';
import Purchase from '../../Containers/purchase';
-import TradeParams from '../../Containers/trade-params.jsx';
+import TradeParams from '../../Containers/trade-params';
type TScreenLarge = {
is_market_closed?: boolean;
diff --git a/packages/trader/src/Modules/Trading/Components/Form/screen-small.tsx b/packages/trader/src/Modules/Trading/Components/Form/screen-small.tsx
index 7181dd35f9b4..aef43f88b21b 100644
--- a/packages/trader/src/Modules/Trading/Components/Form/screen-small.tsx
+++ b/packages/trader/src/Modules/Trading/Components/Form/screen-small.tsx
@@ -13,7 +13,7 @@ import {
} from 'Modules/Trading/Components/Form/TradeParams/Multiplier/widgets.jsx';
import AccumulatorsAmountMobile from 'Modules/Trading/Components/Form/TradeParams/Accumulator/accumulators-amount-mobile';
import AccumulatorsInfoDisplay from 'Modules/Trading/Components/Form/TradeParams/Accumulator/accumulators-info-display';
-import { BarrierMobile, LastDigitMobile } from 'Modules/Trading/Containers/trade-params-mobile.jsx';
+import { BarrierMobile, LastDigitMobile } from 'Modules/Trading/Containers/trade-params-mobile';
import ContractType from 'Modules/Trading/Containers/contract-type';
import MobileWidget from 'Modules/Trading/Components/Elements/mobile-widget.jsx';
import Purchase from 'Modules/Trading/Containers/purchase';
diff --git a/packages/trader/src/Modules/Trading/Containers/Multiplier/multiplier-amount-modal.jsx b/packages/trader/src/Modules/Trading/Containers/Multiplier/multiplier-amount-modal.jsx
index 7818ffd8b8fa..ff8a61763e63 100644
--- a/packages/trader/src/Modules/Trading/Containers/Multiplier/multiplier-amount-modal.jsx
+++ b/packages/trader/src/Modules/Trading/Containers/Multiplier/multiplier-amount-modal.jsx
@@ -3,7 +3,7 @@ import { Div100vhContainer, Modal, Money, Popover, usePreventIOSZoom } from '@de
import { useIsMounted, WS } from '@deriv/shared';
import { localize, Localize } from '@deriv/translations';
import { requestPreviewProposal } from 'Stores/Modules/Trading/Helpers/preview-proposal';
-import AmountMobile from 'Modules/Trading/Components/Form/TradeParams/amount-mobile.jsx';
+import AmountMobile from 'Modules/Trading/Components/Form/TradeParams/amount-mobile';
import MultipliersInfo from 'Modules/Trading/Components/Form/TradeParams/Multiplier/info.jsx';
import { observer, useStore } from '@deriv/stores';
import { useTraderStore } from 'Stores/useTraderStores';
diff --git a/packages/trader/src/Modules/Trading/Containers/purchase.tsx b/packages/trader/src/Modules/Trading/Containers/purchase.tsx
index e6ae38d7edc7..20d4af5ab044 100644
--- a/packages/trader/src/Modules/Trading/Containers/purchase.tsx
+++ b/packages/trader/src/Modules/Trading/Containers/purchase.tsx
@@ -12,7 +12,7 @@ import AccumulatorsSellButton from '../Components/Form/TradeParams/Accumulator/a
import PurchaseFieldset from 'Modules/Trading/Components/Elements/purchase-fieldset';
import { useTraderStore } from 'Stores/useTraderStores';
import { observer, useStore } from '@deriv/stores';
-import { TProposalTypeInfo } from 'Types';
+import { TTradeStore } from 'Types';
type TGetSupportedContractsKey = keyof ReturnType;
@@ -48,14 +48,14 @@ const Purchase = observer(({ is_market_closed }: { is_market_closed?: boolean })
proposal_info,
purchase_info,
symbol,
- validation_errors,
+ validation_errors = {},
trade_types,
is_trade_enabled,
has_open_accu_contract,
} = useTraderStore();
const is_high_low = /^high_low$/.test(contract_type.toLowerCase());
- const isLoading = (info: TProposalTypeInfo | Record) => {
+ const isLoading = (info: TTradeStore['proposal_info'][string] | Record) => {
const has_validation_error = Object.values(validation_errors).some(e => e.length);
return !has_validation_error && !info?.has_error && !info.id;
};
diff --git a/packages/trader/src/Modules/Trading/Containers/trade-params-mobile.jsx b/packages/trader/src/Modules/Trading/Containers/trade-params-mobile.tsx
similarity index 75%
rename from packages/trader/src/Modules/Trading/Containers/trade-params-mobile.jsx
rename to packages/trader/src/Modules/Trading/Containers/trade-params-mobile.tsx
index fe9cd8e69bbe..8cb17c6ffe72 100644
--- a/packages/trader/src/Modules/Trading/Containers/trade-params-mobile.jsx
+++ b/packages/trader/src/Modules/Trading/Containers/trade-params-mobile.tsx
@@ -1,17 +1,68 @@
import 'Sass/app/modules/trading-mobile.scss';
-
import { Div100vhContainer, Modal, Money, Tabs, ThemedScrollbars, usePreventIOSZoom } from '@deriv/components';
-
-import AmountMobile from 'Modules/Trading/Components/Form/TradeParams/amount-mobile.jsx';
-import Barrier from 'Modules/Trading/Components/Form/TradeParams/barrier.jsx';
+import AmountMobile from 'Modules/Trading/Components/Form/TradeParams/amount-mobile';
+import Barrier from 'Modules/Trading/Components/Form/TradeParams/barrier';
import DurationMobile from 'Modules/Trading/Components/Form/TradeParams/Duration/duration-mobile.jsx';
-import LastDigit from 'Modules/Trading/Components/Form/TradeParams/last-digit.jsx';
+import LastDigit from 'Modules/Trading/Components/Form/TradeParams/last-digit';
+import { TTextValueStrings } from 'Types';
import { observer, useStore } from '@deriv/stores';
import { useTraderStore } from 'Stores/useTraderStores';
import React from 'react';
import classNames from 'classnames';
import { localize } from '@deriv/translations';
+type TTradeParamsModal = {
+ is_open: boolean;
+ tab_index: number;
+ toggleModal: () => void;
+};
+
+type TTradeParamsMobile = {
+ currency: string;
+ toggleModal: () => void;
+ isVisible: (component_key: string) => boolean;
+ setAmountTabIdx: (amount_tab_idx?: number) => void;
+ amount_tab_idx?: number;
+ setTradeParamTabIdx: (trade_param_tab_idx: number) => void;
+ trade_param_tab_idx: number;
+ setDurationTabIdx: (duration_tab_idx?: number) => void;
+ duration_unit: string;
+ duration_units_list: TTextValueStrings[];
+ duration_value: number;
+ duration_tab_idx?: number;
+ has_amount_error: boolean;
+ has_duration_error: boolean;
+ // amount
+ setAmountError: (has_error: boolean) => void;
+ setSelectedAmount: (basis: string, selected_basis_value: string | number) => void;
+ stake_value: number;
+ payout_value: number;
+ // duration
+ setDurationError: (has_error: boolean) => void;
+ setSelectedDuration: (selected_duration_unit: string, selected_duration: number) => void;
+ t_duration: number;
+ s_duration: number;
+ m_duration: number;
+ h_duration: number;
+ d_duration: number;
+};
+
+type TReducer = Pick<
+ TTradeParamsMobile,
+ | 'trade_param_tab_idx'
+ | 'duration_tab_idx'
+ | 'amount_tab_idx'
+ | 'has_amount_error'
+ | 'has_duration_error'
+ | 't_duration'
+ | 's_duration'
+ | 'm_duration'
+ | 'h_duration'
+ | 'd_duration'
+ | 'stake_value'
+ | 'payout_value'
+> & { curr_duration_unit: string; curr_duration_value: number };
+
const DEFAULT_DURATION = Object.freeze({
t: 5,
s: 15,
@@ -20,20 +71,21 @@ const DEFAULT_DURATION = Object.freeze({
d: 1,
});
-const reducer = (state, payload) => {
+const reducer = (state: TReducer, payload: Partial) => {
return {
...state,
...payload,
};
};
-const makeGetDefaultDuration = (trade_duration, trade_duration_unit) => duration_unit =>
- trade_duration_unit === duration_unit ? trade_duration : DEFAULT_DURATION[duration_unit];
+const makeGetDefaultDuration = (trade_duration: number, trade_duration_unit: string) => (duration_unit: string) =>
+ trade_duration_unit === duration_unit
+ ? trade_duration
+ : DEFAULT_DURATION[duration_unit as keyof typeof DEFAULT_DURATION];
-const TradeParamsModal = observer(({ is_open, toggleModal, tab_index }) => {
- const { client, ui } = useStore();
+const TradeParamsModal = observer(({ is_open, toggleModal, tab_index }: TTradeParamsModal) => {
+ const { client } = useStore();
const { currency } = client;
- const { enableApp, disableApp } = ui;
const { amount, form_components, duration, duration_unit, duration_units_list } = useTraderStore();
// eslint-disable-next-line react-hooks/exhaustive-deps
const getDefaultDuration = React.useCallback(makeGetDefaultDuration(duration, duration_unit), []);
@@ -61,19 +113,20 @@ const TradeParamsModal = observer(({ is_open, toggleModal, tab_index }) => {
React.useEffect(() => {
setSelectedDuration(duration_unit, duration);
- setDurationTabIdx(undefined);
+ setDurationTabIdx();
// duration and duration_unit can be changed in trade-store when contract type is changed
}, [duration, duration_unit]);
- const setTradeParamTabIdx = trade_param_tab_idx => dispatch({ trade_param_tab_idx });
+ const setTradeParamTabIdx = (trade_param_tab_idx: number) => dispatch({ trade_param_tab_idx });
- const setDurationTabIdx = duration_tab_idx => dispatch({ duration_tab_idx });
+ const setDurationTabIdx = (duration_tab_idx?: number) => dispatch({ duration_tab_idx });
- const setAmountTabIdx = amount_tab_idx => dispatch({ amount_tab_idx });
+ const setAmountTabIdx = (amount_tab_idx?: number) => dispatch({ amount_tab_idx });
- const setSelectedAmount = (basis, selected_basis_value) => dispatch({ [`${basis}_value`]: selected_basis_value });
+ const setSelectedAmount = (basis: string, selected_basis_value: string | number) =>
+ dispatch({ [`${basis}_value`]: selected_basis_value });
- const setSelectedDuration = (selected_duration_unit, selected_duration) => {
+ const setSelectedDuration = (selected_duration_unit: string, selected_duration: number) => {
dispatch({
[`${selected_duration_unit}_duration`]: selected_duration,
curr_duration_unit: selected_duration_unit,
@@ -81,24 +134,21 @@ const TradeParamsModal = observer(({ is_open, toggleModal, tab_index }) => {
});
};
- const setAmountError = has_error => {
+ const setAmountError = (has_error: boolean) => {
dispatch({ has_amount_error: has_error });
};
- const setDurationError = has_error => {
+ const setDurationError = (has_error: boolean) => {
dispatch({ has_duration_error: has_error });
};
- const isVisible = component_key => form_components.includes(component_key);
-
+ const isVisible = (component_key: string): boolean => form_components.includes(component_key);
return (
}
- disableApp={disableApp}
toggleModal={toggleModal}
height='auto'
width='calc(100vw - 32px)'
@@ -172,7 +222,7 @@ const TradeParamsMobile = observer(
m_duration,
h_duration,
d_duration,
- }) => {
+ }: TTradeParamsMobile) => {
const { basis_list, basis, expiry_epoch, is_turbos, is_vanilla } = useTraderStore();
const getDurationText = () => {
const duration = duration_units_list.find(d => d.value === duration_unit);
@@ -188,7 +238,7 @@ const TradeParamsMobile = observer(
return ;
};
- const getHeaderContent = tab_key => {
+ const getHeaderContent = (tab_key: string) => {
switch (tab_key) {
case 'duration':
return (
@@ -229,9 +279,10 @@ const TradeParamsMobile = observer(
onTabItemClick={setTradeParamTabIdx}
top
>
- {isVisible('duration') && (
+ {isVisible('duration') ? (
is migrated to TS
toggleModal={toggleModal}
amount_tab_idx={amount_tab_idx}
duration_tab_idx={duration_tab_idx}
@@ -249,8 +300,8 @@ const TradeParamsMobile = observer(
expiry_epoch={expiry_epoch}
/>
- )}
- {isVisible('amount') && (
+ ) : null}
+ {isVisible('amount') ? (
- )}
+ ) : null}
);
}
@@ -273,10 +326,10 @@ const TradeParamsMobile = observer(
export const LastDigitMobile = observer(() => {
const { form_components } = useTraderStore();
- return form_components.includes('last_digit') && ;
+ return form_components.includes('last_digit') ? : null;
});
export const BarrierMobile = observer(() => {
const { form_components } = useTraderStore();
- return form_components.includes('barrier') && ;
+ return form_components.includes('barrier') ? : null;
});
diff --git a/packages/trader/src/Modules/Trading/Containers/trade-params.jsx b/packages/trader/src/Modules/Trading/Containers/trade-params.tsx
similarity index 86%
rename from packages/trader/src/Modules/Trading/Containers/trade-params.jsx
rename to packages/trader/src/Modules/Trading/Containers/trade-params.tsx
index 6941ca692129..a00d1e44f459 100644
--- a/packages/trader/src/Modules/Trading/Containers/trade-params.jsx
+++ b/packages/trader/src/Modules/Trading/Containers/trade-params.tsx
@@ -1,11 +1,10 @@
-import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
-import Amount from 'Modules/Trading/Components/Form/TradeParams/amount.jsx';
-import Barrier from 'Modules/Trading/Components/Form/TradeParams/barrier.jsx';
+import Amount from 'Modules/Trading/Components/Form/TradeParams/amount';
+import Barrier from 'Modules/Trading/Components/Form/TradeParams/barrier';
import BarrierSelector from 'Modules/Trading/Components/Form/TradeParams/Turbos/barrier-selector';
import Duration from 'Modules/Trading/Components/Form/TradeParams/Duration';
-import LastDigit from 'Modules/Trading/Components/Form/TradeParams/last-digit.jsx';
+import LastDigit from 'Modules/Trading/Components/Form/TradeParams/last-digit';
import CancelDeal from 'Modules/Trading/Components/Form/TradeParams/Multiplier/cancel-deal.jsx';
import Accumulator from 'Modules/Trading/Components/Form/TradeParams/Accumulator/accumulator';
import StopLoss from 'Modules/Trading/Components/Form/TradeParams/Multiplier/stop-loss.jsx';
@@ -18,15 +17,22 @@ import { observer } from '@deriv/stores';
import { useTraderStore } from 'Stores/useTraderStores';
import Fieldset from 'App/Components/Form/fieldset';
-const TradeParams = observer(({ is_minimized }) => {
+type TTradeParams = {
+ is_minimized?: boolean;
+};
+
+const TradeParams = observer(({ is_minimized = false }: TTradeParams) => {
const { form_components } = useTraderStore();
- const isVisible = component_key => {
+ const isVisible = (component_key: string) => {
return form_components.includes(component_key);
};
return (
- {isVisible('duration') && }
+ {isVisible('duration') && (
+ // @ts-expect-error: TODO: check if TS error is gone after is migrated to TS
+
+ )}
{isVisible('barrier') && }
{isVisible('last_digit') && }
{isVisible('accumulator') && }
@@ -46,8 +52,5 @@ const TradeParams = observer(({ is_minimized }) => {
);
});
-TradeParams.propTypes = {
- is_minimized: PropTypes.bool,
-};
export default TradeParams;
diff --git a/packages/trader/src/Modules/Trading/Containers/trade.jsx b/packages/trader/src/Modules/Trading/Containers/trade.jsx
index c01c0eed96ed..9b57197c5570 100644
--- a/packages/trader/src/Modules/Trading/Containers/trade.jsx
+++ b/packages/trader/src/Modules/Trading/Containers/trade.jsx
@@ -4,7 +4,7 @@ import { DesktopWrapper, Div100vhContainer, MobileWrapper, SwipeableWrapper } fr
import { getDecimalPlaces, isDesktop, isMobile } from '@deriv/shared';
import ChartLoader from 'App/Components/Elements/chart-loader';
import PositionsDrawer from 'App/Components/Elements/PositionsDrawer';
-import MarketIsClosedOverlay from 'App/Components/Elements/market-is-closed-overlay.jsx';
+import MarketIsClosedOverlay from 'App/Components/Elements/market-is-closed-overlay';
import Test from './test.jsx';
import { ChartBottomWidgets, ChartTopWidgets, DigitsWidget } from './chart-widgets.jsx';
import FormLayout from '../Components/Form/form-layout';
@@ -300,7 +300,6 @@ const ChartTrade = observer(props => {
wsSubscribe,
active_symbols,
has_alternative_source,
- refToAddTick,
} = useTraderStore();
const settings = {
@@ -391,7 +390,6 @@ const ChartTrade = observer(props => {
onExportLayout={exportLayout}
shouldFetchTradingTimes={!end_epoch}
hasAlternativeSource={has_alternative_source}
- refToAddTick={refToAddTick}
getMarketsOrder={getMarketsOrder}
should_zoom_out_on_yaxis={is_accumulator}
yAxisMargin={{
diff --git a/packages/trader/src/Modules/Trading/Helpers/contract-type.tsx b/packages/trader/src/Modules/Trading/Helpers/contract-type.tsx
index aba9e38fee31..36dd8cf923f8 100644
--- a/packages/trader/src/Modules/Trading/Helpers/contract-type.tsx
+++ b/packages/trader/src/Modules/Trading/Helpers/contract-type.tsx
@@ -5,7 +5,7 @@ import { TContractType, TContractCategory, TList } from '../Components/Form/Cont
type TContractTypesList = {
[key: string]: {
name: string;
- categories: TContractType[];
+ categories: DeepRequired;
};
};
diff --git a/packages/trader/src/Stores/Modules/SmartChart/chart-barrier-store.ts b/packages/trader/src/Stores/Modules/SmartChart/chart-barrier-store.ts
index 493dfe14a2b4..7f3e2adb9f0f 100644
--- a/packages/trader/src/Stores/Modules/SmartChart/chart-barrier-store.ts
+++ b/packages/trader/src/Stores/Modules/SmartChart/chart-barrier-store.ts
@@ -29,7 +29,7 @@ export class ChartBarrierStore {
onChartBarrierChange: TOnChartBarrierChange | null;
constructor(
- high_barrier: string | number,
+ high_barrier?: string | number,
low_barrier?: string | number,
onChartBarrierChange: TOnChartBarrierChange = null,
{ color, line_style, not_draggable }: TChartBarrierStoreOptions = {}
diff --git a/packages/trader/src/Stores/Modules/Trading/Actions/purchase.ts b/packages/trader/src/Stores/Modules/Trading/Actions/purchase.ts
index f2a8062a8ebc..cc2b463fede0 100644
--- a/packages/trader/src/Stores/Modules/Trading/Actions/purchase.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Actions/purchase.ts
@@ -1,11 +1,20 @@
-import { Buy, BuyContractRequest } from '@deriv/api-types';
+import { Buy, BuyContractResponse, BuyContractRequest } from '@deriv/api-types';
import { WS } from '@deriv/shared';
+type TResponse = BuyContractResponse & {
+ echo_req: Buy;
+ error?: {
+ code: string;
+ message: string;
+ details?: BuyContractResponse['buy'] & { field: string };
+ };
+};
+
export const processPurchase = async (
proposal_id: string,
- price: BuyContractRequest['price'],
- passthrough: BuyContractRequest['passthrough']
-): Promise =>
+ price: string | number,
+ passthrough?: BuyContractRequest['passthrough']
+): Promise =>
WS.buy({
proposal_id,
price,
diff --git a/packages/trader/src/Stores/Modules/Trading/Actions/start-date.ts b/packages/trader/src/Stores/Modules/Trading/Actions/start-date.ts
index 9be02fc3e422..62d9950f5e04 100644
--- a/packages/trader/src/Stores/Modules/Trading/Actions/start-date.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Actions/start-date.ts
@@ -38,7 +38,6 @@ export const onChangeStartDate = async (store: TTradeStore) => {
export const onChangeExpiry = async (store: TTradeStore) => {
const { start_time, expiry_date, expiry_type, expiry_time, start_date, symbol, sessions } = store;
-
const trading_times = await ContractType.getTradingTimes(expiry_date, symbol);
const obj_market_open_times = { market_open_times: trading_times.open };
const obj_market_close_times = { market_close_times: trading_times.close };
diff --git a/packages/trader/src/Stores/Modules/Trading/Constants/validation-rules.ts b/packages/trader/src/Stores/Modules/Trading/Constants/validation-rules.ts
index 6911efae718e..cbd1835ba444 100644
--- a/packages/trader/src/Stores/Modules/Trading/Constants/validation-rules.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Constants/validation-rules.ts
@@ -4,231 +4,208 @@ import { isSessionAvailable } from '../Helpers/start-date';
import { TTradeStore } from 'Types';
import type { TRuleOptions } from 'Utils/Validator/validator';
+type TValidationRules = {
+ [key: string]: {
+ rules?: Array[];
+ trigger?: string;
+ };
+};
+
const tradeSpecificBarrierCheck = (is_vanilla: boolean, input: number) => is_vanilla || input !== 0;
-export const getValidationRules = () =>
- ({
- amount: {
- rules: [
- ['req', { message: localize('Amount is a required field.') }],
- ['number', { min: 0, type: 'float' }],
- ],
- },
- barrier_1: {
- rules: [
- [
- 'req',
- {
- condition: (store: TTradeStore) =>
- store.barrier_count && store.form_components.indexOf('barrier') > -1,
- message: localize('Barrier is a required field.'),
- },
- ],
- ['barrier', { condition: (store: TTradeStore) => store.barrier_count }],
- [
- 'custom',
- {
- func: (
- value: TTradeStore['barrier_1'],
- options: Partial,
- store: TTradeStore,
- inputs: Pick
- ) => (store.barrier_count > 1 ? +value > +inputs.barrier_2 : true),
- message: localize('Higher barrier must be higher than lower barrier.'),
- },
- ],
- [
- 'custom',
- {
- func: (
- value: TTradeStore['barrier_1'],
- options: Partial,
- store: TTradeStore,
- inputs: Pick
- ) =>
- /^[+-]/.test(inputs.barrier_1)
- ? tradeSpecificBarrierCheck(store.is_vanilla, +inputs.barrier_1)
- : true,
- message: localize('Barrier cannot be zero.'),
- },
- ],
- ],
- trigger: 'barrier_2',
- },
- barrier_2: {
- rules: [
- [
- 'req',
- {
- condition: (store: TTradeStore) =>
- store.barrier_count > 1 && store.form_components.indexOf('barrier') > -1,
- message: localize('Barrier is a required field.'),
- },
- ],
- ['barrier', { condition: (store: TTradeStore) => store.barrier_count }],
- [
- 'custom',
- {
- func: (
- value: TTradeStore['barrier_2'],
- options: Partial,
- store: TTradeStore,
- inputs: Pick
- ) =>
- (/^[+-]/g.test(inputs.barrier_1) && /^[+-]/g.test(value)) ||
- (/^(?![+-])/g.test(inputs.barrier_1) && /^(?![+-])/g.test(value)),
- message: localize('Both barriers should be relative or absolute'),
- },
- ],
- [
- 'custom',
- {
- func: (
- value: TTradeStore['barrier_2'],
- options: Partial,
- store: TTradeStore,
- inputs: Pick
- ) => +inputs.barrier_1 > +value,
- message: localize('Lower barrier must be lower than higher barrier.'),
- },
- ],
- ],
- trigger: 'barrier_1',
- },
- duration: {
- rules: [['req', { message: localize('Duration is a required field.') }]],
- },
- start_date: {
- trigger: 'start_time',
- },
- expiry_date: {
- trigger: 'expiry_time',
- },
- start_time: {
- rules: [
- [
- 'custom',
- {
- func: (value: TTradeStore['start_time'], options: Partial, store: TTradeStore) =>
- store.contract_start_type === 'spot' || isTimeValid(value ?? ''),
- message: localize('Please enter the start time in the format "HH:MM".'),
- },
- ],
- [
- 'custom',
- {
- func: (value: TTradeStore['start_time'], options: Partial, store: TTradeStore) =>
- store.contract_start_type === 'spot' || isHourValid(value ?? ''),
- message: localize('Hour must be between 0 and 23.'),
- },
- ],
- [
- 'custom',
- {
- func: (value: TTradeStore['start_time'], options: Partial, store: TTradeStore) =>
- store.contract_start_type === 'spot' || isMinuteValid(value ?? ''),
- message: localize('Minute must be between 0 and 59.'),
- },
- ],
- [
- 'custom',
- {
- func: (
- value: TTradeStore['start_time'],
- options: Partial,
- store: TTradeStore
- ) => {
- if (store.contract_start_type === 'spot') return true;
- if (!isTimeValid(value ?? '')) return false;
- const start_moment = toMoment(store.start_date);
- const start_moment_clone = start_moment.clone();
- const [h, m] = value?.split(':') ?? [];
- return isSessionAvailable(
- store.sessions,
- start_moment_clone.hour(+h).minute(+m),
- start_moment
- );
- },
- message: localize('Start time cannot be in the past.'),
- },
- ],
- ],
- },
- expiry_time: {
- rules: [
- [
- 'custom',
- {
- func: (value: TTradeStore['expiry_time'], options: Partial, store: TTradeStore) =>
- store.contract_start_type === 'spot' || isTimeValid(value ?? ''),
- message: localize('Please enter the start time in the format "HH:MM".'),
- },
- ],
- [
- 'custom',
- {
- func: (value: TTradeStore['expiry_time'], options: Partial, store: TTradeStore) =>
- store.contract_start_type === 'spot' || isHourValid(value ?? ''),
- message: localize('Hour must be between 0 and 23.'),
- },
- ],
- [
- 'custom',
- {
- func: (value: TTradeStore['expiry_time'], options: Partial, store: TTradeStore) =>
- store.contract_start_type === 'spot' || isMinuteValid(value ?? ''),
- message: localize('Minute must be between 0 and 59.'),
- },
- ],
- [
- 'custom',
- {
- func: (
- value: TTradeStore['expiry_time'],
- options: Partial,
- store: TTradeStore
- ) => {
- if (store.contract_start_type === 'spot') return true;
- if (!isTimeValid(value ?? '')) return false;
- const start_moment = toMoment(store.start_date);
- const start_moment_clone = start_moment.clone();
- const [h, m] = value?.split(':') ?? [];
- return isSessionAvailable(
- store.sessions,
- start_moment_clone.hour(+h).minute(+m),
- start_moment
- );
- },
- message: localize('Expiry time cannot be in the past.'),
- },
- ],
+export const getValidationRules = (): TValidationRules => ({
+ amount: {
+ rules: [
+ ['req', { message: localize('Amount is a required field.') }],
+ ['number', { min: 0, type: 'float' }],
+ ],
+ },
+ barrier_1: {
+ rules: [
+ [
+ 'req',
+ {
+ condition: store => !!store.barrier_count && store.form_components.indexOf('barrier') > -1,
+ message: localize('Barrier is a required field.'),
+ },
+ ],
+ ['barrier', { condition: (store: TTradeStore) => !!store.barrier_count }],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['barrier_1'], options, store, inputs) =>
+ Number(store?.barrier_count) > 1 ? +value > Number(inputs?.barrier_2) : true,
+ message: localize('Higher barrier must be higher than lower barrier.'),
+ },
],
- },
- ...getMultiplierValidationRules(),
- } as const);
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['barrier_1'], options, store, inputs) =>
+ /^[+-]/.test(inputs?.barrier_1 ?? '')
+ ? tradeSpecificBarrierCheck(!!store?.is_vanilla, Number(inputs?.barrier_1))
+ : true,
+ message: localize('Barrier cannot be zero.'),
+ },
+ ],
+ ],
+ trigger: 'barrier_2',
+ },
+ barrier_2: {
+ rules: [
+ [
+ 'req',
+ {
+ condition: store => store.barrier_count > 1 && store.form_components.indexOf('barrier') > -1,
+ message: localize('Barrier is a required field.'),
+ },
+ ],
+ ['barrier', { condition: (store: TTradeStore) => !!store.barrier_count }],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['barrier_2'], options, store, inputs) =>
+ (/^[+-]/g.test(inputs?.barrier_1 ?? '') && /^[+-]/g.test(value)) ||
+ (/^(?![+-])/g.test(inputs?.barrier_1 ?? '') && /^(?![+-])/g.test(value)),
+ message: localize('Both barriers should be relative or absolute'),
+ },
+ ],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['barrier_2'], options, store, inputs) =>
+ Number(inputs?.barrier_1) > +value,
+ message: localize('Lower barrier must be lower than higher barrier.'),
+ },
+ ],
+ ],
+ trigger: 'barrier_1',
+ },
+ duration: {
+ rules: [['req', { message: localize('Duration is a required field.') }]],
+ },
+ start_date: {
+ trigger: 'start_time',
+ },
+ expiry_date: {
+ trigger: 'expiry_time',
+ },
+ start_time: {
+ rules: [
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['start_time'], options, store) =>
+ store?.contract_start_type === 'spot' || isTimeValid(value ?? ''),
+ message: localize('Please enter the start time in the format "HH:MM".'),
+ },
+ ],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['start_time'], options, store) =>
+ store?.contract_start_type === 'spot' || isHourValid(value ?? ''),
+ message: localize('Hour must be between 0 and 23.'),
+ },
+ ],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['start_time'], options, store) =>
+ store?.contract_start_type === 'spot' || isMinuteValid(value ?? ''),
+ message: localize('Minute must be between 0 and 59.'),
+ },
+ ],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['start_time'], options, store) => {
+ if (store?.contract_start_type === 'spot') return true;
+ if (!isTimeValid(value ?? '')) return false;
+ const start_moment = toMoment(store?.start_date);
+ const start_moment_clone = start_moment.clone();
+ const [h, m] = value?.split(':') ?? [];
+ return isSessionAvailable(
+ store?.sessions,
+ start_moment_clone.hour(+h).minute(+m),
+ start_moment
+ );
+ },
+ message: localize('Start time cannot be in the past.'),
+ },
+ ],
+ ],
+ },
+ expiry_time: {
+ rules: [
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['expiry_time'], options, store) =>
+ store?.contract_start_type === 'spot' || isTimeValid(value ?? ''),
+ message: localize('Please enter the start time in the format "HH:MM".'),
+ },
+ ],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['expiry_time'], options, store) =>
+ store?.contract_start_type === 'spot' || isHourValid(value ?? ''),
+ message: localize('Hour must be between 0 and 23.'),
+ },
+ ],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['expiry_time'], options, store) =>
+ store?.contract_start_type === 'spot' || isMinuteValid(value ?? ''),
+ message: localize('Minute must be between 0 and 59.'),
+ },
+ ],
+ [
+ 'custom',
+ {
+ func: (value: TTradeStore['expiry_time'], options, store) => {
+ if (store?.contract_start_type === 'spot') return true;
+ if (!isTimeValid(value ?? '')) return false;
+ const start_moment = toMoment(store?.start_date);
+ const start_moment_clone = start_moment.clone();
+ const [h, m] = value?.split(':') ?? [];
+ return isSessionAvailable(
+ store?.sessions,
+ start_moment_clone.hour(+h).minute(+m),
+ start_moment
+ );
+ },
+ message: localize('Expiry time cannot be in the past.'),
+ },
+ ],
+ ],
+ },
+ ...getMultiplierValidationRules(),
+});
-export const getMultiplierValidationRules = () =>
- ({
- stop_loss: {
- rules: [
- [
- 'req',
- {
- condition: (store: TTradeStore) => store.has_stop_loss && !store.stop_loss,
- message: localize('Please enter a stop loss amount.'),
- },
- ],
- ],
- },
- take_profit: {
- rules: [
- [
- 'req',
- {
- condition: (store: TTradeStore) => store.has_take_profit && !store.take_profit,
- message: localize('Please enter a take profit amount.'),
- },
- ],
+export const getMultiplierValidationRules = () => ({
+ stop_loss: {
+ rules: [
+ [
+ 'req',
+ {
+ condition: (store: TTradeStore) => store.has_stop_loss && !store.stop_loss,
+ message: localize('Please enter a stop loss amount.'),
+ },
+ ],
+ ],
+ },
+ take_profit: {
+ rules: [
+ [
+ 'req',
+ {
+ condition: (store: TTradeStore) => store.has_take_profit && !store.take_profit,
+ message: localize('Please enter a take profit amount.'),
+ },
],
- },
- } as const);
+ ],
+ },
+});
diff --git a/packages/trader/src/Stores/Modules/Trading/Helpers/allow-equals.ts b/packages/trader/src/Stores/Modules/Trading/Helpers/allow-equals.ts
index 189936dfe2c9..8d2eb0bdbdbf 100644
--- a/packages/trader/src/Stores/Modules/Trading/Helpers/allow-equals.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Helpers/allow-equals.ts
@@ -1,11 +1,10 @@
import { isEmptyObject, getPropertyValue } from '@deriv/shared';
import { ContractType } from 'Stores/Modules/Trading/Helpers/contract-type';
-import { PriceProposalRequest } from '@deriv/api-types';
import { TTradeStore } from 'Types';
type THasDurationForCallPutEqual = {
contract_type_list: TTradeStore['contract_types_list'];
- duration_unit: string;
+ duration_unit: TTradeStore['duration_unit'];
contract_start_type: string;
};
@@ -26,7 +25,6 @@ export const hasDurationForCallPutEqual = (
if (!contract_type_list || !duration_unit || !contract_start_type) return false;
const contract_list = Object.keys(contract_type_list || {}).reduce((key, list) => {
- // @ts-expect-error the key always exists in the object, hence can ignore the TS error.
const item: THasDurationForCallPutEqual['contract_type_list']['Ups & Downs'] = contract_type_list[list];
return [...key, ...item.categories.map(contract => contract.value)];
}, []);
diff --git a/packages/trader/src/Stores/Modules/Trading/Helpers/chart.ts b/packages/trader/src/Stores/Modules/Trading/Helpers/chart.ts
index c06061a0ab86..9f9d97eec88b 100644
--- a/packages/trader/src/Stores/Modules/Trading/Helpers/chart.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Helpers/chart.ts
@@ -1,16 +1,11 @@
-type TPayload = {
- data?: {
- action: string;
- chart_type_name?: string;
- indicator_type_name?: string;
- indicators_category_name?: string;
- market_type_name?: string;
- search_string?: string;
- subform_name?: string;
- tab_market_name?: string;
- time_interval_name?: string;
- };
- event_type: string;
+import type { TEvents } from '@deriv/analytics';
+
+export type TPayload = {
+ data: Omit<
+ Partial,
+ 'action'
+ > & { action: string };
+ event_type: 'ce_chart_types_form' | 'ce_market_types_form' | 'ce_indicators_types_form';
};
type TStateChangeOption = {
@@ -75,7 +70,7 @@ export const SUBFORM_NAME = {
const getChartTypeFormAnalyticsData = (state: keyof typeof STATE_TYPES, option: TStateChangeOption = {}) => {
const { chart_type_name = '', is_open, time_interval_name } = option;
const chart_event_type = 'ce_chart_types_form';
- const payload = {
+ const payload: TPayload = {
data: {
action: '',
chart_type_name,
@@ -107,9 +102,9 @@ const getIndicatorTypeFormAnalyticsData = (state: keyof typeof STATE_TYPES, opti
const indicators_subform = is_info_open ? SUBFORM_NAME.INDICATORS_INFO : SUBFORM_NAME.INDICATORS_TYPE;
const info_open_close_action = is_info_open ? ACTION.INFO_OPEN : ACTION.INFO_CLOSE;
const open_close_action = is_open ? ACTION.OPEN : ACTION.CLOSE;
- const payload: TPayload = {
+ const payload = {
event_type: indicators_event_type,
- };
+ } as TPayload;
if (
(state === STATE_TYPES.INDICATOR_SEARCH && !option.search_string) ||
((state === STATE_TYPES.INDICATOR_ADDED ||
@@ -183,9 +178,9 @@ const getMarketTypeFormAnalyticsData = (state: keyof typeof STATE_TYPES, option:
const market_event_type = 'ce_market_types_form';
const favorites_action = is_favorite ? ACTION.ADD_TO_FAVORITES : ACTION.DELETE_FROM_FAVORITES;
const open_close_action = is_open ? ACTION.OPEN : ACTION.CLOSE;
- const payload: TPayload = {
+ const payload = {
event_type: market_event_type,
- };
+ } as TPayload;
if (
(state === STATE_TYPES.MARKET_SEARCH && !option.search_string) ||
(state === STATE_TYPES.FAVORITE_MARKETS_TOGGLE && !market_type_name)
diff --git a/packages/trader/src/Stores/Modules/Trading/Helpers/contract-type.ts b/packages/trader/src/Stores/Modules/Trading/Helpers/contract-type.ts
index 35f9b6c9210f..f49fb573e61a 100644
--- a/packages/trader/src/Stores/Modules/Trading/Helpers/contract-type.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Helpers/contract-type.ts
@@ -159,7 +159,7 @@ export const ContractType = (() => {
return trade_types;
};
- const getArrayDefaultValue = (arr_new_values: Array, value: string | number) =>
+ const getArrayDefaultValue = (arr_new_values: Array, value: T): T =>
arr_new_values.indexOf(value) !== -1 ? value : arr_new_values[0];
const getContractValues = (store: TTradeStore): TContractValues | Record => {
@@ -292,7 +292,7 @@ export const ContractType = (() => {
};
const getDurationMinMax = (contract_type: string, contract_start_type: string, contract_expiry_type?: string) => {
- let duration_min_max: TTradeStore['duration_min_max'] | TTradeStore['duration_min_max'][string] =
+ let duration_min_max: TTradeStore['duration_min_max'] =
getPropertyValue(available_contract_types, [
contract_type,
'config',
@@ -302,7 +302,12 @@ export const ContractType = (() => {
]) || {};
if (contract_expiry_type) {
- duration_min_max = 'contract_expiry_type' in duration_min_max ? duration_min_max[contract_expiry_type] : {};
+ duration_min_max =
+ 'contract_expiry_type' in duration_min_max
+ ? (duration_min_max as unknown as { [key: string]: TTradeStore['duration_min_max'] })[
+ contract_expiry_type
+ ]
+ : {};
}
return { duration_min_max };
@@ -579,7 +584,7 @@ export const ContractType = (() => {
moment_obj.minute(Math.ceil(moment_obj.minute() / 5) * 5);
const getTradeTypes = (contract_type: string) => ({
- trade_types: getPropertyValue(available_contract_types, [contract_type, 'config', 'trade_types']) as string[],
+ trade_types: getPropertyValue(available_contract_types, [contract_type, 'config', 'trade_types']),
});
const getBarriers = (contract_type: string, expiry_type: string, stored_barrier_value?: string) => {
diff --git a/packages/trader/src/Stores/Modules/Trading/Helpers/limit-orders.ts b/packages/trader/src/Stores/Modules/Trading/Helpers/limit-orders.ts
index 2020d20c37bb..a7a0183a7638 100644
--- a/packages/trader/src/Stores/Modules/Trading/Helpers/limit-orders.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Helpers/limit-orders.ts
@@ -2,11 +2,10 @@ import { isMultiplierContract, BARRIER_COLORS, BARRIER_LINE_STYLES } from '@deri
import { ChartBarrierStore } from '../../SmartChart/chart-barrier-store';
import { removeBarrier } from '../../SmartChart/Helpers/barriers';
import { useStore } from '@deriv/stores';
+import { getProposalInfo } from './proposal';
-const isLimitOrderBarrierSupported = (
- contract_type: string,
- contract_info: ReturnType['portfolio']['all_positions'][0]['contract_info']
-) => isMultiplierContract(contract_type) && contract_info.limit_order;
+const isLimitOrderBarrierSupported = (contract_type: string, contract_info: ReturnType) =>
+ isMultiplierContract(contract_type) && contract_info.limit_order;
export const LIMIT_ORDER_TYPES = {
STOP_OUT: 'stop_out',
@@ -18,14 +17,14 @@ type TBarrier = ChartBarrierStore & { key?: string };
type TSetLimitOrderBarriers = {
barriers: TBarrier[];
- contract_type: string;
- contract_info: Parameters[1];
+ contract_type?: string;
+ contract_info?: ReturnType;
is_over: boolean;
};
export const setLimitOrderBarriers = ({
barriers,
- contract_type,
- contract_info = {},
+ contract_type = '',
+ contract_info = {} as ReturnType,
is_over,
}: TSetLimitOrderBarriers) => {
if (is_over && isLimitOrderBarrierSupported(contract_type, contract_info)) {
@@ -53,7 +52,6 @@ export const setLimitOrderBarriers = ({
barrier.onChange({
high: obj_limit_order.value,
- low: undefined, //TODO: wait until ChartBarrierStore is ts migrated and 'low' can be an optional parameter
});
} else {
const obj_barrier = {
@@ -87,7 +85,7 @@ export const setLimitOrderBarriers = ({
*/
export const getLimitOrder = (
contract_update: Pick<
- ReturnType['contract_trade'],
+ ReturnType['contract_trade']['contracts'][number],
| 'has_contract_update_stop_loss'
| 'has_contract_update_take_profit'
| 'contract_update_stop_loss'
diff --git a/packages/trader/src/Stores/Modules/Trading/Helpers/logic.ts b/packages/trader/src/Stores/Modules/Trading/Helpers/logic.ts
index b586a0425592..e1cd547ee251 100644
--- a/packages/trader/src/Stores/Modules/Trading/Helpers/logic.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Helpers/logic.ts
@@ -1,5 +1,5 @@
-import { TTradeStore } from 'Types';
+import { TContractInfo } from '@deriv/shared';
import ServerTime from '_common/base/server_time';
-export const isCancellationExpired = (contract_info: TTradeStore['proposal_info'][string]) =>
+export const isCancellationExpired = (contract_info: TContractInfo) =>
!!contract_info.cancellation?.date_expiry && contract_info.cancellation.date_expiry < ServerTime.get().unix();
diff --git a/packages/trader/src/Stores/Modules/Trading/Helpers/process.ts b/packages/trader/src/Stores/Modules/Trading/Helpers/process.ts
index 9c4afbcc970d..bab8b78af2da 100644
--- a/packages/trader/src/Stores/Modules/Trading/Helpers/process.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Helpers/process.ts
@@ -23,7 +23,7 @@ const processInSequence = async (
});
};
-export const processTradeParams = async (store: TTradeStore, new_state: DeepPartial) => {
+export const processTradeParams = async (store: TTradeStore, new_state: Partial) => {
const functions = getMethodsList(store, new_state);
await processInSequence(store, functions);
diff --git a/packages/trader/src/Stores/Modules/Trading/Helpers/proposal.ts b/packages/trader/src/Stores/Modules/Trading/Helpers/proposal.ts
index 0ae9ff9fde8c..7231a2f97d9f 100644
--- a/packages/trader/src/Stores/Modules/Trading/Helpers/proposal.ts
+++ b/packages/trader/src/Stores/Modules/Trading/Helpers/proposal.ts
@@ -71,7 +71,7 @@ export const getProposalInfo = (
const is_stake = contract_basis?.value === 'stake';
- const price = is_stake ? stake : proposal[contract_basis?.value as keyof Proposal];
+ const price = is_stake ? stake : (proposal[contract_basis?.value as keyof Proposal] as string | number);
let has_increased = false;
if (price !== undefined && price !== null) {
diff --git a/packages/trader/src/Stores/Modules/Trading/trade-store.js b/packages/trader/src/Stores/Modules/Trading/trade-store.ts
similarity index 82%
rename from packages/trader/src/Stores/Modules/Trading/trade-store.js
rename to packages/trader/src/Stores/Modules/Trading/trade-store.ts
index d20856b83796..0e304c394dc4 100644
--- a/packages/trader/src/Stores/Modules/Trading/trade-store.js
+++ b/packages/trader/src/Stores/Modules/Trading/trade-store.ts
@@ -1,5 +1,4 @@
import * as Symbol from './Actions/symbol';
-
import {
WS,
cloneObject,
@@ -21,7 +20,6 @@ import {
isTurbosContract,
isVanillaContract,
pickDefaultSymbol,
- removeBarrier,
resetEndTimeOnVolatilityIndices,
showDigitalOptionsUnavailableError,
showUnavailableLocationError,
@@ -32,6 +30,7 @@ import {
BARRIER_LINE_STYLES,
} from '@deriv/shared';
import { RudderStack } from '@deriv/analytics';
+import type { TEvents } from '@deriv/analytics';
import { localize } from '@deriv/translations';
import { getValidationRules, getMultiplierValidationRules } from 'Stores/Modules/Trading/Constants/validation-rules';
import { ContractType } from 'Stores/Modules/Trading/Helpers/contract-type';
@@ -45,13 +44,136 @@ import { action, computed, makeObservable, observable, override, reaction, runIn
import { createProposalRequests, getProposalErrorField, getProposalInfo } from './Helpers/proposal';
import { getHoveredColor } from './Helpers/barrier-utils';
import BaseStore from '../../base-store';
+import { TTextValueNumber, TTextValueStrings } from 'Types';
import { ChartBarrierStore } from '../SmartChart/chart-barrier-store';
import debounce from 'lodash.debounce';
import { setLimitOrderBarriers } from './Helpers/limit-orders';
-import { STATE_TYPES, getChartAnalyticsData } from './Helpers/chart';
+import type { TCoreStores } from '@deriv/stores/types';
+import {
+ ActiveSymbols,
+ ActiveSymbolsRequest,
+ Buy,
+ BuyContractResponse,
+ History,
+ PriceProposalRequest,
+ PriceProposalResponse,
+ ServerTimeRequest,
+ TickSpotData,
+ TicksHistoryRequest,
+ TicksHistoryResponse,
+ TicksStreamResponse,
+ TradingTimesRequest,
+} from '@deriv/api-types';
+import { STATE_TYPES, TPayload, getChartAnalyticsData } from './Helpers/chart';
+
+type TBarriers = Array<
+ ChartBarrierStore & {
+ hideOffscreenBarrier?: boolean;
+ isSingleBarrier?: boolean;
+ }
+>;
+type TChartLayout = {
+ adj: boolean;
+ aggregationType: string;
+ animation?: boolean;
+ candleWidth: number;
+ chartScale: string;
+ chartType: string;
+ crosshair: number;
+ extended: boolean;
+ flipped: boolean;
+ interval: number;
+ marketSessions: Partial>;
+ outliers: boolean;
+ panels: {
+ chart: {
+ chartName: string;
+ display: string;
+ index: number;
+ percent: number;
+ yAxis: {
+ name: string;
+ position: null;
+ };
+ yaxisLHS: string[];
+ yaxisRHS: string[];
+ };
+ };
+ periodicity: number;
+ previousMaxTicks?: number;
+ range: Partial>;
+ setSpan: Partial>;
+ studies?: Partial>;
+ symbols: [
+ {
+ interval: number;
+ periodicity: number;
+ setSpan: Partial>;
+ symbol: string;
+ symbolObject: ActiveSymbols[number];
+ timeUnit: string;
+ }
+ ];
+ timeUnit: string;
+ volumeUnderlay: boolean;
+};
+type TChartStateChangeOption = { symbol: string | undefined; isClosed: boolean };
+type TContractDataForGTM = Omit, 'cancellation' | 'limit_order'> &
+ ReturnType & {
+ buy_price: number;
+ };
+type TPrevChartLayout =
+ | (TChartLayout & {
+ isDone?: VoidFunction;
+ is_used?: boolean;
+ })
+ | null;
+type TContractTypesList = {
+ [key: string]: {
+ name: string;
+ categories: TTextValueStrings[];
+ };
+};
+type TDurationMinMax = {
+ [key: string]: { min: number; max: number };
+};
+type TResponse = Res & {
+ echo_req: Req;
+ error?: {
+ code: string;
+ message: string;
+ details?: Res[K] & { field: string };
+ };
+};
+type TProposalInfo = {
+ [key: string]: ReturnType;
+};
+type TStakeBoundary = Record<
+ string,
+ {
+ min_stake?: number;
+ max_stake?: number;
+ }
+>;
+type TTicksHistoryResponse = TicksHistoryResponse | TicksStreamResponse;
+type TToastBoxListItem = {
+ component: JSX.Element | null;
+ contract_types: TTextValueStrings[];
+ icon: string;
+ key: string;
+ label: string;
+};
+type TToastBoxObject = {
+ key?: boolean;
+ buy_price?: string;
+ currency?: string;
+ contract_type?: string;
+ list?: Array;
+};
+type TBarriersData = Record | { barrier: string; barrier_choices: string[] };
const store_name = 'trade_store';
-const g_subscribers_map = {}; // blame amin.m
+const g_subscribers_map: Partial>> = {}; // blame amin.m
export default class TradeStore extends BaseStore {
// Control values
@@ -62,53 +184,53 @@ export default class TradeStore extends BaseStore {
has_equals_only = false;
// Underlying
- symbol;
+ symbol = '';
is_market_closed = false;
previous_symbol = '';
- active_symbols = [];
+ active_symbols: ActiveSymbols = [];
- form_components = [];
+ form_components: string[] = [];
// Contract Type
contract_expiry_type = '';
contract_start_type = '';
contract_type = '';
- contract_types_list = {};
- trade_types = {};
+ contract_types_list: TContractTypesList = {};
+ trade_types: { [key: string]: string } = {};
// Amount
amount = 10;
basis = '';
- basis_list = [];
+ basis_list: Array = [];
currency = '';
- stake_boundary = {};
+ stake_boundary: Partial = {};
// Duration
duration = 5;
- duration_min_max = {};
+ duration_min_max: TDurationMinMax = {};
duration_unit = '';
- duration_units_list = [];
- expiry_date = '';
- expiry_epoch = '';
- expiry_time = '';
- expiry_type = 'duration';
+ duration_units_list: Array = [];
+ expiry_date: string | null = '';
+ expiry_epoch: number | string = '';
+ expiry_time: string | null = '';
+ expiry_type: string | null = 'duration';
// Barrier
barrier_1 = '';
barrier_2 = '';
barrier_count = 0;
- barriers = [];
+ main_barrier: ChartBarrierStore | null = null;
+ barriers: TBarriers = [];
hovered_barrier = '';
- main_barrier = null;
- barrier_choices = [];
+ barrier_choices: string[] = [];
// Start Time
- start_date = Number(0); // Number(0) refers to 'now'
- start_dates_list = [];
- start_time = null;
- sessions = [];
+ start_date = 0; // 0 refers to 'now'
+ start_dates_list: Array<{ text: string; value: number }> = [];
+ start_time: string | null = null;
+ sessions: Array<{ open: moment.Moment; close: moment.Moment }> = [];
- market_open_times = [];
+ market_open_times: string[] = [];
// End Date Time
/**
* An array that contains market closing time.
@@ -116,68 +238,70 @@ export default class TradeStore extends BaseStore {
* e.g. ["04:00:00", "08:00:00"]
*
*/
- market_close_times = [];
+ market_close_times: string[] = [];
// Last Digit
last_digit = 5;
is_mobile_digit_view_selected = false;
// Purchase
- proposal_info = {};
- purchase_info = {};
+ proposal_info: TProposalInfo = {};
+ purchase_info: Partial = {};
// Chart loader observables
- is_chart_loading;
+ is_chart_loading?: boolean;
should_show_active_symbols_loading = false;
// Accumulator trade params
- accumulator_range_list = [];
+ accumulator_range_list: number[] = [];
growth_rate = 0.03;
maximum_payout = 0;
maximum_ticks = 0;
- ticks_history_stats = {};
+ ticks_history_stats: {
+ ticks_stayed_in?: number[];
+ last_tick_epoch?: number;
+ } = {};
tick_size_barrier = 0;
// Multiplier trade params
- multiplier;
- multiplier_range_list = [];
- stop_loss;
- take_profit;
+ multiplier = 0;
+ multiplier_range_list: TTextValueNumber[] = [];
+ stop_loss?: string;
+ take_profit?: string;
has_stop_loss = false;
has_take_profit = false;
has_cancellation = false;
- commission;
- cancellation_price;
- stop_out;
- expiration;
- hovered_contract_type;
+ commission?: string | number;
+ cancellation_price?: number;
+ stop_out?: number;
+ expiration?: number;
+ hovered_contract_type?: string | null;
cancellation_duration = '60m';
- cancellation_range_list = [];
+ cancellation_range_list: Array = [];
// Turbos trade params
- long_barriers = {};
- short_barriers = {};
+ long_barriers: TBarriersData = {};
+ short_barriers: TBarriersData = {};
// Vanilla trade params
- strike_price_choices = {};
+ strike_price_choices: TBarriersData = {};
// Mobile
is_trade_params_expanded = true;
//Toastbox
- contract_purchase_toast_box;
+ contract_purchase_toast_box?: TToastBoxObject;
- addTickByProposal = () => null;
debouncedProposal = debounce(this.requestProposal, 500);
- proposal_requests = {};
+ proposal_requests: Record> = {};
is_purchasing_contract = false;
- initial_barriers;
+ initial_barriers?: { barrier_1: string; barrier_2: string };
is_initial_barrier_applied = false;
should_skip_prepost_lifecycle = false;
- constructor({ root_store }) {
+ constructor({ root_store }: { root_store: TCoreStores }) {
const local_storage_properties = [
'amount',
'currency',
@@ -337,7 +461,6 @@ export default class TradeStore extends BaseStore {
resetErrorServices: action.bound,
resetPreviousSymbol: action.bound,
setActiveSymbols: action.bound,
- setAllowEqual: action.bound,
setBarrierChoices: action.bound,
setChartStatus: action.bound,
setContractPurchaseToastbox: action.bound,
@@ -347,14 +470,12 @@ export default class TradeStore extends BaseStore {
setMarketStatus: action.bound,
setMobileDigitView: action.bound,
setPreviousSymbol: action.bound,
- setPurchaseSpotBarrier: action.bound,
setSkipPrePostLifecycle: action.bound,
setStakeBoundary: action.bound,
setTradeStatus: action.bound,
show_digits_stats: computed,
themeChangeListener: action.bound,
updateBarrierColor: action.bound,
- updateLimitOrderBarriers: action.bound,
updateStore: action.bound,
updateSymbol: action.bound,
});
@@ -427,7 +548,7 @@ export default class TradeStore extends BaseStore {
}
);
when(
- () => this.accumulator_range_list.length,
+ () => !!this.accumulator_range_list.length,
() => this.setDefaultGrowthRate()
);
}
@@ -464,14 +585,14 @@ export default class TradeStore extends BaseStore {
}
}
- setSkipPrePostLifecycle(should_skip) {
+ setSkipPrePostLifecycle(should_skip: boolean) {
if (!!should_skip !== !!this.should_skip_prepost_lifecycle) {
// to skip assignment if no change is made
this.should_skip_prepost_lifecycle = should_skip;
}
}
- setTradeStatus(status) {
+ setTradeStatus(status: boolean) {
this.is_trade_enabled = status;
}
@@ -531,7 +652,7 @@ export default class TradeStore extends BaseStore {
return;
}
- if (!active_symbols || !active_symbols.length) {
+ if (!active_symbols?.length) {
await WS.wait('get_settings');
/*
* This logic is related to EU country checks
@@ -564,7 +685,9 @@ export default class TradeStore extends BaseStore {
runInAction(() => {
const contract_categories = ContractType.getContractCategories();
this.processNewValuesAsync({
- ...contract_categories,
+ ...(contract_categories as Pick & {
+ has_only_forward_starting_contracts: boolean;
+ }),
...ContractType.getContractType(contract_categories.contract_types_list, this.contract_type),
});
this.processNewValuesAsync(ContractType.getContractValues(this));
@@ -603,7 +726,7 @@ export default class TradeStore extends BaseStore {
);
}
- async onChangeMultiple(values) {
+ async onChangeMultiple(values: Partial) {
Object.keys(values).forEach(name => {
if (!(name in this)) {
throw new Error(`Invalid Argument: ${name}`);
@@ -614,7 +737,7 @@ export default class TradeStore extends BaseStore {
this.validateAllProperties(); // then run validation before sending proposal
}
- async onChange(e) {
+ async onChange(e: { target: { name: string; value: unknown } }) {
const { name, value } = e.target;
if (name === 'symbol' && value) {
// set trade params skeleton and chart loader to true until processNewValuesAsync resolves
@@ -627,7 +750,7 @@ export default class TradeStore extends BaseStore {
} else if (name === 'currency') {
// Only allow the currency dropdown change if client is not logged in
if (!this.root_store.client.is_logged_in) {
- this.root_store.client.selectCurrency(value);
+ this.root_store.client.selectCurrency(value as string);
}
} else if (name === 'expiry_date') {
this.expiry_time = null;
@@ -645,19 +768,15 @@ export default class TradeStore extends BaseStore {
this.root_store.common.setSelectedContractType(this.contract_type);
}
- setHoveredBarrier(hovered_value) {
+ setHoveredBarrier(hovered_value: string) {
this.hovered_barrier = hovered_value;
}
- setPreviousSymbol(symbol) {
+ setPreviousSymbol(symbol: string) {
if (this.previous_symbol !== symbol) this.previous_symbol = symbol;
}
- setAllowEqual(is_equal) {
- this.is_equal = is_equal;
- }
-
- setIsTradeParamsExpanded(value) {
+ setIsTradeParamsExpanded(value: boolean) {
this.is_trade_params_expanded = value;
}
@@ -665,7 +784,7 @@ export default class TradeStore extends BaseStore {
this.setMarketStatus(isMarketClosed(this.active_symbols, this.previous_symbol));
await Symbol.onChangeSymbolAsync(this.previous_symbol);
- await this.updateSymbol(this.symbol);
+ this.updateSymbol(this.symbol);
this.setChartStatus(false);
runInAction(() => {
@@ -673,18 +792,18 @@ export default class TradeStore extends BaseStore {
});
}
- updateBarrierColor(is_dark_mode) {
+ updateBarrierColor(is_dark_mode: boolean) {
if (this.main_barrier) {
this.main_barrier.updateBarrierColor(is_dark_mode);
}
}
- onHoverPurchase(is_over, contract_type) {
+ onHoverPurchase(is_over: boolean, contract_type?: string) {
if (this.is_accumulator) return;
if (this.is_purchase_enabled && this.main_barrier && !this.is_multiplier) {
- this.main_barrier.updateBarrierShade(is_over, contract_type);
+ this.main_barrier.updateBarrierShade(is_over, contract_type ?? '');
} else if (!is_over && this.main_barrier && !this.is_multiplier) {
- this.main_barrier.updateBarrierShade(false, contract_type);
+ this.main_barrier.updateBarrierShade(false, contract_type ?? '');
}
this.hovered_contract_type = is_over ? contract_type : null;
@@ -692,44 +811,7 @@ export default class TradeStore extends BaseStore {
barriers: this.root_store.portfolio.barriers,
is_over,
contract_type,
- contract_info: this.proposal_info[contract_type],
- });
- }
-
- setPurchaseSpotBarrier(is_over, position) {
- const key = 'PURCHASE_SPOT_BARRIER';
- if (!is_over) {
- removeBarrier(this.root_store.portfolio.barriers, key);
- return;
- }
-
- let purchase_spot_barrier = this.root_store.portfolio.barriers.find(b => b.key === key);
- if (purchase_spot_barrier) {
- if (purchase_spot_barrier.high !== +position.contract_info.entry_spot) {
- purchase_spot_barrier.onChange({
- high: position.contract_info.entry_spot,
- });
- }
- } else {
- purchase_spot_barrier = new ChartBarrierStore(position.contract_info.entry_spot);
- purchase_spot_barrier.key = key;
- purchase_spot_barrier.draggable = false;
- purchase_spot_barrier.hideOffscreenBarrier = true;
- purchase_spot_barrier.isSingleBarrier = true;
- purchase_spot_barrier.updateBarrierColor(this.root_store.ui.is_dark_mode_on);
- this.barriers.push(purchase_spot_barrier);
- this.root_store.portfolio.barriers.push(purchase_spot_barrier);
- }
- }
-
- updateLimitOrderBarriers(is_over, position) {
- const contract_info = position.contract_info;
- const { barriers } = this;
- setLimitOrderBarriers({
- barriers,
- contract_info,
- contract_type: contract_info.contract_type,
- is_over,
+ contract_info: this.proposal_info[contract_type ?? ''],
});
}
@@ -755,19 +837,18 @@ export default class TradeStore extends BaseStore {
return this.root_store.portfolio.barriers && toJS(this.root_store.portfolio.barriers);
}
- setMainBarrier = proposal_info => {
+ setMainBarrier = (proposal_info: PriceProposalRequest) => {
if (!proposal_info) {
return;
}
- const { barrier, contract_type, high_barrier, low_barrier } = proposal_info;
-
+ const { contract_type, barrier, barrier2 } = proposal_info;
if (isBarrierSupported(contract_type)) {
const color = this.root_store.ui.is_dark_mode_on ? BARRIER_COLORS.DARK_GRAY : BARRIER_COLORS.GRAY;
// create barrier only when it's available in response
this.main_barrier = new ChartBarrierStore(
- this.hovered_barrier || barrier || high_barrier,
- low_barrier,
+ this.hovered_barrier || barrier,
+ barrier2,
this.onChartBarrierChange,
{
color: this.hovered_barrier ? getHoveredColor(contract_type) : color,
@@ -783,14 +864,14 @@ export default class TradeStore extends BaseStore {
onPurchase = debounce(this.processPurchase, 300);
- processPurchase(proposal_id, price, type) {
+ processPurchase(proposal_id: string, price: string | number, type: string) {
if (!this.is_purchase_enabled) return;
if (proposal_id) {
this.is_purchase_enabled = false;
this.is_purchasing_contract = true;
const is_tick_contract = this.duration_unit === 't';
processPurchase(proposal_id, price).then(
- action(response => {
+ action((response: TResponse) => {
if (!this.is_trade_component_mounted) {
this.enablePurchase();
this.is_purchasing_contract = false;
@@ -820,7 +901,7 @@ export default class TradeStore extends BaseStore {
if (this.proposal_info[type] && this.proposal_info[type].id !== proposal_id) {
throw new Error('Proposal ID does not match.');
}
- const contract_data = {
+ const contract_data: TContractDataForGTM = {
...this.proposal_requests[type],
...this.proposal_info[type],
buy_price: response.buy.buy_price,
@@ -831,8 +912,8 @@ export default class TradeStore extends BaseStore {
if (contract_id) {
const shortcode = response.buy.shortcode;
const { category, underlying } = extractInfoFromShortcode(shortcode);
- const is_digit_contract = isDigitContractType(category.toUpperCase());
- const contract_type = category.toUpperCase();
+ const is_digit_contract = isDigitContractType(category?.toUpperCase() ?? '');
+ const contract_type = category?.toUpperCase();
this.root_store.contract_trade.addContract({
contract_id,
start_time,
@@ -886,10 +967,10 @@ export default class TradeStore extends BaseStore {
const el_purchase_value = document.getElementsByClassName('trade-container__price-info');
const el_purchase_buttons = document.getElementsByClassName('btn-purchase');
[].forEach.bind(el_purchase_buttons, el => {
- el.classList.add('btn-purchase--disabled');
+ (el as HTMLButtonElement).classList.add('btn-purchase--disabled');
})();
[].forEach.bind(el_purchase_value, el => {
- el.classList.add('trade-container__price-info--fade');
+ (el as HTMLDivElement).classList.add('trade-container__price-info--fade');
})();
};
@@ -898,11 +979,11 @@ export default class TradeStore extends BaseStore {
* @param {Object} new_state - new values to update the store with
* @return {Object} returns the object having only those values that are updated
*/
- updateStore(new_state) {
+ updateStore(new_state: Partial) {
Object.keys(cloneObject(new_state) || {}).forEach(key => {
if (key === 'root_store' || ['validation_rules', 'validation_errors', 'currency'].indexOf(key) > -1) return;
- if (JSON.stringify(this[key]) === JSON.stringify(new_state[key])) {
- delete new_state[key];
+ if (JSON.stringify(this[key as keyof this]) === JSON.stringify(new_state[key as keyof TradeStore])) {
+ delete new_state[key as keyof TradeStore];
} else {
if (key === 'symbol') {
this.is_purchase_enabled = false;
@@ -913,7 +994,7 @@ export default class TradeStore extends BaseStore {
new_state.start_date = parseInt(new_state.start_date);
}
- this[key] = new_state[key];
+ this[key as 'currency'] = new_state[key as keyof TradeStore] as TradeStore['currency'];
// validation is done in mobx intercept (base_store.js)
// when barrier_1 is set, it is compared with store.barrier_2 (which is not updated yet)
@@ -926,9 +1007,9 @@ export default class TradeStore extends BaseStore {
}
async processNewValuesAsync(
- obj_new_values = {},
+ obj_new_values: Partial = {},
is_changed_by_user = false,
- obj_old_values = {},
+ obj_old_values: Partial | null = {},
should_forget_first = true
) {
// To switch to rise_fall_equal contract type when allow equal is checked on first page refresh or
@@ -962,7 +1043,7 @@ export default class TradeStore extends BaseStore {
savePreviousChartMode('', null);
}
- if (/\bduration\b/.test(Object.keys(obj_new_values))) {
+ if (/\bduration\b/.test(Object.keys(obj_new_values) as unknown as string)) {
// TODO: fix this in input-field.jsx
if (typeof obj_new_values.duration === 'string') {
obj_new_values.duration = +obj_new_values.duration;
@@ -974,27 +1055,27 @@ export default class TradeStore extends BaseStore {
this.forgetAllProposal();
this.proposal_requests = {};
}
- if (is_changed_by_user && /\bcurrency\b/.test(Object.keys(obj_new_values))) {
+ if (is_changed_by_user && /\bcurrency\b/.test(Object.keys(obj_new_values) as unknown as string)) {
const prev_currency = obj_old_values?.currency || this.currency;
const has_currency_changed = obj_new_values.currency !== prev_currency;
const should_reset_stake =
- isCryptocurrency(obj_new_values.currency) ||
+ isCryptocurrency(obj_new_values.currency ?? '') ||
// For switch between fiat and crypto and vice versa
- isCryptocurrency(obj_new_values.currency) !== isCryptocurrency(prev_currency);
+ isCryptocurrency(obj_new_values.currency ?? '') !== isCryptocurrency(prev_currency);
if (has_currency_changed && should_reset_stake) {
- obj_new_values.amount = obj_new_values.amount || getMinPayout(obj_new_values.currency);
+ obj_new_values.amount = obj_new_values.amount || getMinPayout(obj_new_values.currency ?? '');
}
- this.currency = obj_new_values.currency;
+ this.currency = obj_new_values.currency ?? '';
}
let has_only_forward_starting_contracts;
if (Object.keys(obj_new_values).includes('symbol')) {
this.setPreviousSymbol(this.symbol);
- await Symbol.onChangeSymbolAsync(obj_new_values.symbol);
- this.setMarketStatus(isMarketClosed(this.active_symbols, obj_new_values.symbol));
+ await Symbol.onChangeSymbolAsync(obj_new_values.symbol ?? '');
+ this.setMarketStatus(isMarketClosed(this.active_symbols, obj_new_values.symbol ?? ''));
has_only_forward_starting_contracts =
ContractType.getContractCategories().has_only_forward_starting_contracts;
}
@@ -1005,7 +1086,10 @@ export default class TradeStore extends BaseStore {
const new_state = this.updateStore(cloneObject(obj_new_values));
- if (is_changed_by_user || /\b(symbol|contract_types_list)\b/.test(Object.keys(new_state))) {
+ if (
+ is_changed_by_user ||
+ /\b(symbol|contract_types_list)\b/.test(Object.keys(new_state) as unknown as string)
+ ) {
this.updateStore({
// disable purchase button(s), clear contract info
is_purchase_enabled: false,
@@ -1030,7 +1114,7 @@ export default class TradeStore extends BaseStore {
...(!this.is_initial_barrier_applied ? this.initial_barriers : {}),
});
this.is_initial_barrier_applied = true;
- if (/\b(contract_type|currency)\b/.test(Object.keys(new_state))) {
+ if (/\b(contract_type|currency)\b/.test(Object.keys(new_state) as unknown as string)) {
this.validateAllProperties();
}
this.debouncedProposal();
@@ -1051,11 +1135,11 @@ export default class TradeStore extends BaseStore {
return isDigitTradeType(this.contract_type);
}
- setMobileDigitView(bool) {
+ setMobileDigitView(bool: boolean) {
this.is_mobile_digit_view_selected = bool;
}
- pushPurchaseDataToGtm(contract_data) {
+ pushPurchaseDataToGtm(contract_data: TContractDataForGTM) {
const data = {
event: 'buy_contract',
bom_ui: 'new',
@@ -1105,7 +1189,7 @@ export default class TradeStore extends BaseStore {
}
if (!isEmptyObject(requests)) {
- this.proposal_requests = requests;
+ this.proposal_requests = requests as Record>;
this.purchase_info = {};
Object.keys(this.proposal_requests).forEach(type => {
WS.subscribeProposal(this.proposal_requests[type], this.onProposalResponse);
@@ -1119,11 +1203,11 @@ export default class TradeStore extends BaseStore {
if (length > 0) WS.forgetAll('proposal');
}
- setMarketStatus(status) {
+ setMarketStatus(status: boolean) {
this.is_market_closed = status;
}
- onProposalResponse(response) {
+ onProposalResponse(response: TResponse) {
const { contract_type } = response.echo_req;
const prev_proposal_info = getPropertyValue(this.proposal_info, contract_type) || {};
const obj_prev_contract_basis = getPropertyValue(prev_proposal_info, 'obj_contract_basis') || {};
@@ -1155,11 +1239,11 @@ export default class TradeStore extends BaseStore {
if (this.is_accumulator && this.proposal_info?.ACCU) {
const {
barrier_spot_distance,
- maximum_ticks,
+ maximum_ticks = 0,
ticks_stayed_in,
- tick_size_barrier,
+ tick_size_barrier = 0,
last_tick_epoch,
- maximum_payout,
+ maximum_payout = 0,
high_barrier,
low_barrier,
spot_time,
@@ -1189,10 +1273,9 @@ export default class TradeStore extends BaseStore {
}
if (this.hovered_contract_type === contract_type) {
- this.addTickByProposal(response);
setLimitOrderBarriers({
barriers: this.root_store.portfolio.barriers,
- contract_info: this.proposal_info[this.hovered_contract_type],
+ contract_info: this.proposal_info[this.hovered_contract_type ?? ''],
contract_type,
is_over: true,
});
@@ -1233,7 +1316,7 @@ export default class TradeStore extends BaseStore {
if ((this.is_turbos || this.is_vanilla) && response.error.details?.barrier_choices) {
const { barrier_choices, max_stake, min_stake } = response.error.details;
this.setStakeBoundary(contract_type, min_stake, max_stake);
- this.setBarrierChoices(barrier_choices);
+ this.setBarrierChoices(barrier_choices as string[]);
if (!this.barrier_choices.includes(this.barrier_1)) {
// Since on change of duration `proposal` API call is made which returns a new set of barrier values.
// The new list is set and the mid value is assigned
@@ -1250,8 +1333,8 @@ export default class TradeStore extends BaseStore {
} else {
this.validateAllProperties();
if (this.is_turbos || this.is_vanilla) {
- const { max_stake, min_stake, barrier_choices } = response.proposal;
- this.setBarrierChoices(barrier_choices);
+ const { max_stake, min_stake, barrier_choices } = response.proposal ?? {};
+ this.setBarrierChoices(barrier_choices as string[]);
this.setStakeBoundary(contract_type, min_stake, max_stake);
}
}
@@ -1261,15 +1344,15 @@ export default class TradeStore extends BaseStore {
}
}
- onChartBarrierChange(barrier_1, barrier_2) {
+ onChartBarrierChange(barrier_1: string, barrier_2?: string) {
this.processNewValuesAsync({ barrier_1, barrier_2 }, true);
}
onAllowEqualsChange() {
- this.processNewValuesAsync({ contract_type: parseInt(this.is_equal) ? 'rise_fall_equal' : 'rise_fall' }, true);
+ this.processNewValuesAsync({ contract_type: this.is_equal ? 'rise_fall_equal' : 'rise_fall' }, true);
}
- updateSymbol(underlying) {
+ updateSymbol(underlying: string) {
if (!underlying) return;
this.onChange({
target: {
@@ -1287,7 +1370,7 @@ export default class TradeStore extends BaseStore {
if (!this.validation_rules.duration) return;
- const index = this.validation_rules.duration.rules.findIndex(item => item[0] === 'number');
+ const index = this.validation_rules.duration.rules?.findIndex(item => item[0] === 'number');
const limits = this.duration_min_max[this.contract_expiry_type] || false;
if (limits) {
@@ -1296,10 +1379,10 @@ export default class TradeStore extends BaseStore {
max: convertDurationLimit(+limits.max, this.duration_unit),
};
- if (index > -1) {
- this.validation_rules.duration.rules[index][1] = duration_options;
+ if (Number(index) > -1 && this.validation_rules.duration.rules) {
+ this.validation_rules.duration.rules[Number(index)][1] = duration_options;
} else {
- this.validation_rules.duration.rules.push(['number', duration_options]);
+ this.validation_rules.duration.rules?.push(['number', duration_options]);
}
this.validateProperty('duration', this.duration);
}
@@ -1352,11 +1435,11 @@ export default class TradeStore extends BaseStore {
return Promise.resolve();
}
- networkStatusChangeListener(is_online) {
+ networkStatusChangeListener(is_online: boolean) {
this.setTradeStatus(is_online);
}
- themeChangeListener(is_dark_mode_on) {
+ themeChangeListener(is_dark_mode_on: boolean) {
this.updateBarrierColor(is_dark_mode_on);
}
@@ -1383,11 +1466,11 @@ export default class TradeStore extends BaseStore {
});
}
- setChartStatus(status) {
+ setChartStatus(status: boolean) {
this.is_chart_loading = status;
}
- async initAccountCurrency(new_currency) {
+ async initAccountCurrency(new_currency: string) {
if (this.currency === new_currency) return;
await this.processNewValuesAsync({ currency: new_currency }, true, { currency: this.currency }, false);
@@ -1422,7 +1505,7 @@ export default class TradeStore extends BaseStore {
}
}
- prev_chart_layout = null;
+ prev_chart_layout: TPrevChartLayout = null;
get chart_layout() {
let layout = null;
@@ -1433,38 +1516,40 @@ export default class TradeStore extends BaseStore {
}
get is_crypto_multiplier() {
- return this.contract_type === 'multiplier' && /^cry/.test(this.symbol);
+ return this.contract_type === 'multiplier' && this.symbol.startsWith('cry');
}
- exportLayout(layout) {
+ exportLayout(layout: TChartLayout) {
delete layout.previousMaxTicks; // TODO: fix it in smartcharts
this.prev_chart_layout = layout;
- this.prev_chart_layout.isDone = () => {
- this.prev_chart_layout.is_used = true;
- this.setChartStatus(false);
- };
+ if (this.prev_chart_layout) {
+ this.prev_chart_layout.isDone = () => {
+ if (this.prev_chart_layout) this.prev_chart_layout.is_used = true;
+ this.setChartStatus(false);
+ };
+ }
}
// ---------- WS ----------
- wsSubscribe = (req, callback) => {
- const passthrough_callback = (...args) => {
+ wsSubscribe = (req: TicksHistoryRequest, callback: (response: TTicksHistoryResponse) => void) => {
+ const passthrough_callback = (...args: [TTicksHistoryResponse]) => {
callback(...args);
if (this.is_accumulator) {
let current_spot_data = {};
if ('tick' in args[0]) {
- const { epoch, quote, symbol } = args[0].tick;
+ const { epoch, quote, symbol } = args[0].tick as TickSpotData;
if (this.symbol !== symbol) return;
current_spot_data = {
current_spot: quote,
current_spot_time: epoch,
};
} else if ('history' in args[0]) {
- const { prices, times } = args[0].history;
+ const { prices, times } = args[0].history as History;
const symbol = args[0].echo_req.ticks_history;
if (this.symbol !== symbol) return;
current_spot_data = {
- current_spot: prices[prices.length - 1],
- current_spot_time: times[times.length - 1],
+ current_spot: prices?.[prices?.length - 1],
+ current_spot_time: times?.[times?.length - 1],
};
} else {
return;
@@ -1479,21 +1564,21 @@ export default class TradeStore extends BaseStore {
}
};
- wsForget = req => {
+ wsForget = (req: TicksHistoryRequest) => {
const key = JSON.stringify(req);
if (g_subscribers_map[key]) {
- g_subscribers_map[key].unsubscribe();
+ g_subscribers_map[key]?.unsubscribe();
delete g_subscribers_map[key];
}
// WS.forget('ticks_history', callback, match);
};
- wsForgetStream = stream_id => {
+ wsForgetStream = (stream_id: string) => {
WS.forgetStream(stream_id);
};
- wsSendRequest = req => {
- if (req.time) {
+ wsSendRequest = (req: TradingTimesRequest | ActiveSymbolsRequest | ServerTimeRequest) => {
+ if ('time' in req) {
return ServerTime.timePromise().then(server_time => {
if (server_time) {
return {
@@ -1504,16 +1589,16 @@ export default class TradeStore extends BaseStore {
return WS.time();
});
}
- if (req.active_symbols) {
+ if ('active_symbols' in req) {
return WS.activeSymbols('brief');
}
- if (req.trading_times) {
+ if ('trading_times' in req) {
return WS.tradingTimes(req.trading_times);
}
return WS.storage.send(req);
};
- chartStateChange(state, option) {
+ chartStateChange(state: string, option?: TChartStateChangeOption) {
if (
state === STATE_TYPES.MARKET_STATE_CHANGE &&
this.is_trade_component_mounted &&
@@ -1522,20 +1607,16 @@ export default class TradeStore extends BaseStore {
) {
this.prepareTradeStore(false);
}
- const { data, event_type } = getChartAnalyticsData(state, option);
+ const { data, event_type } = getChartAnalyticsData(state as keyof typeof STATE_TYPES, option) as TPayload;
if (data) {
RudderStack.track(event_type, {
...data,
device_type: isMobile() ? 'mobile' : 'desktop',
form_name: 'default',
- });
+ } as TEvents['ce_chart_types_form']);
}
}
- refToAddTick = ref => {
- this.addTickByProposal = ref;
- };
-
get has_alternative_source() {
return this.is_multiplier && !!this.hovered_contract_type;
}
@@ -1556,23 +1637,26 @@ export default class TradeStore extends BaseStore {
return isVanillaContract(this.contract_type);
}
- setContractPurchaseToastbox(response) {
- const list = getAvailableContractTypes(this.contract_types_list, unsupported_contract_types_list);
+ setContractPurchaseToastbox(response: Buy) {
+ const list = getAvailableContractTypes(
+ this.contract_types_list,
+ unsupported_contract_types_list
+ ) as Array;
- return (this.contract_purchase_toast_box = {
+ this.contract_purchase_toast_box = {
key: true,
buy_price: formatMoney(this.root_store.client.currency, response.buy_price, true, 0, 0),
contract_type: this.contract_type,
currency: getCurrencyDisplayCode(this.root_store.client.currency),
list,
- });
+ };
}
clearContractPurchaseToastBox() {
this.contract_purchase_toast_box = undefined;
}
- async getFirstOpenMarket(markets_to_search) {
+ async getFirstOpenMarket(markets_to_search: string[]) {
if (this.active_symbols?.length) {
return findFirstOpenMarket(this.active_symbols, markets_to_search);
}
@@ -1584,7 +1668,11 @@ export default class TradeStore extends BaseStore {
return findFirstOpenMarket(active_symbols, markets_to_search);
}
- setBarrierChoices(barrier_choices) {
+ setStakeBoundary(type: string, min_stake?: number, max_stake?: number) {
+ if (min_stake && max_stake) this.stake_boundary[type] = { min_stake, max_stake };
+ }
+
+ setBarrierChoices(barrier_choices: string[]) {
this.barrier_choices = barrier_choices ?? [];
if (this.is_turbos) {
const stored_barriers_data = { barrier: this.barrier_1, barrier_choices };
@@ -1598,8 +1686,4 @@ export default class TradeStore extends BaseStore {
this.strike_price_choices = { barrier: this.barrier_1, barrier_choices };
}
}
-
- setStakeBoundary(type, min_stake, max_stake) {
- if (min_stake && max_stake) this.stake_boundary[type] = { min_stake, max_stake };
- }
}
diff --git a/packages/trader/src/Stores/base-store.ts b/packages/trader/src/Stores/base-store.ts
index 704efb2175f2..c66f6937d334 100644
--- a/packages/trader/src/Stores/base-store.ts
+++ b/packages/trader/src/Stores/base-store.ts
@@ -7,7 +7,7 @@ import { getValidationRules } from './Modules/Trading/Constants/validation-rules
type TValidationRules = ReturnType | Record;
type TBaseStoreOptions = {
- root_store?: TCoreStores;
+ root_store: TCoreStores;
local_storage_properties?: string[];
session_storage_properties?: string[];
validation_rules?: TValidationRules;
@@ -33,21 +33,21 @@ export default class BaseStore {
logout_listener: null | (() => Promise) = null;
local_storage_properties: string[];
networkStatusChangeDisposer: null | (() => void) = null;
- network_status_change_listener: null | ((is_online?: boolean) => void) = null;
+ network_status_change_listener: null | ((is_online: boolean) => void) = null;
partial_fetch_time = 0;
preSwitchAccountDisposer: null | (() => void) = null;
pre_switch_account_listener: null | (() => Promise) = null;
realAccountSignupEndedDisposer: null | (() => void) = null;
real_account_signup_ended_listener: null | (() => Promise) = null;
- root_store?: TCoreStores;
+ root_store: TCoreStores;
session_storage_properties: string[];
store_name = '';
switchAccountDisposer: null | (() => void) = null;
switch_account_listener: null | (() => Promise) = null;
themeChangeDisposer: null | (() => void) = null;
- theme_change_listener: null | ((is_dark_mode_on?: boolean) => void) = null;
+ theme_change_listener: null | ((is_dark_mode_on: boolean) => void) = null;
validation_errors: { [key: string]: string[] } = {};
- validation_rules: TValidationRules = {};
+ validation_rules: TValidationRules | Record = {};
/**
* Constructor of the base class that gets properties' name of child which should be saved in storages
*
@@ -58,7 +58,7 @@ export default class BaseStore {
* @property {Object} validation_rules - An object that contains the validation rules for each property of the store.
* @property {String} store_name - Explicit store name for browser application storage (to bypass minification)
*/
- constructor(options: TBaseStoreOptions = {}) {
+ constructor(options = {} as TBaseStoreOptions) {
makeObservable(this, {
validation_errors: observable,
validation_rules: observable,
@@ -268,7 +268,7 @@ export default class BaseStore {
*
*/
validateProperty(property: string, value: T[keyof T]) {
- const validation_rules_for_property = this.validation_rules[property as keyof TValidationRules];
+ const validation_rules_for_property = this.validation_rules[property] ?? {};
const trigger = 'trigger' in validation_rules_for_property ? validation_rules_for_property.trigger : undefined;
const inputs = { [property]: value ?? this[property as keyof this] };
const validation_rules = {
@@ -315,13 +315,13 @@ export default class BaseStore {
this.switch_account_listener = listener;
this.switchAccountDisposer = when(
- () => !!this.root_store?.client.switch_broadcast,
+ () => !!this.root_store.client.switch_broadcast,
() => {
try {
const result = this.switch_account_listener?.();
if (result?.then && typeof result.then === 'function') {
result.then(() => {
- this.root_store?.client.switchEndSignal();
+ this.root_store.client.switchEndSignal();
this.onSwitchAccount(this.switch_account_listener);
});
} else {
@@ -343,13 +343,13 @@ export default class BaseStore {
if (listener) {
this.pre_switch_account_listener = listener;
this.preSwitchAccountDisposer = when(
- () => !!this.root_store?.client.pre_switch_broadcast,
+ () => !!this.root_store.client.pre_switch_broadcast,
() => {
try {
const result = this.pre_switch_account_listener?.();
if (result?.then && typeof result.then === 'function') {
result.then(() => {
- this.root_store?.client.setPreSwitchAccount(false);
+ this.root_store.client.setPreSwitchAccount(false);
this.onPreSwitchAccount(this.pre_switch_account_listener);
});
} else {
@@ -369,13 +369,13 @@ export default class BaseStore {
onLogout(listener: null | (() => Promise)): void {
this.logoutDisposer = when(
- () => !!this.root_store?.client.has_logged_out,
+ () => !!this.root_store.client.has_logged_out,
async () => {
try {
const result = this.logout_listener?.();
if (result?.then && typeof result.then === 'function') {
result.then(() => {
- this.root_store?.client.setLogout(false);
+ this.root_store.client.setLogout(false);
this.onLogout(this.logout_listener);
});
} else {
@@ -395,13 +395,13 @@ export default class BaseStore {
onClientInit(listener: null | (() => Promise)): void {
this.clientInitDisposer = when(
- () => !!this.root_store?.client.initialized_broadcast,
+ () => !!this.root_store.client.initialized_broadcast,
async () => {
try {
const result = this.client_init_listener?.();
if (result?.then && typeof result.then === 'function') {
result.then(() => {
- this.root_store?.client.setInitialized(false);
+ this.root_store.client.setInitialized(false);
this.onClientInit(this.client_init_listener);
});
} else {
@@ -419,9 +419,9 @@ export default class BaseStore {
this.client_init_listener = listener;
}
- onNetworkStatusChange(listener: null | ((is_online?: boolean) => void)): void {
+ onNetworkStatusChange(listener: null | ((is_online: boolean) => void)): void {
this.networkStatusChangeDisposer = reaction(
- () => this.root_store?.common.is_network_online,
+ () => this.root_store.common.is_network_online,
is_online => {
try {
this.network_status_change_listener?.(is_online);
@@ -438,9 +438,9 @@ export default class BaseStore {
this.network_status_change_listener = listener;
}
- onThemeChange(listener: null | ((is_dark_mode_on?: boolean) => void)): void {
+ onThemeChange(listener: null | ((is_dark_mode_on: boolean) => void)): void {
this.themeChangeDisposer = reaction(
- () => this.root_store?.ui.is_dark_mode_on,
+ () => this.root_store.ui.is_dark_mode_on,
is_dark_mode_on => {
try {
this.theme_change_listener?.(is_dark_mode_on);
@@ -459,13 +459,13 @@ export default class BaseStore {
onRealAccountSignupEnd(listener: null | (() => Promise)): void {
this.realAccountSignupEndedDisposer = when(
- () => !!this.root_store?.ui.has_real_account_signup_ended,
+ () => !!this.root_store.ui.has_real_account_signup_ended,
() => {
try {
const result = this.real_account_signup_ended_listener?.();
if (result?.then && typeof result.then === 'function') {
result.then(() => {
- this.root_store?.ui.setRealAccountSignupEnd(false);
+ this.root_store.ui.setRealAccountSignupEnd(false);
this.onRealAccountSignupEnd(this.real_account_signup_ended_listener);
});
} else {
@@ -545,7 +545,7 @@ export default class BaseStore {
assertHasValidCache(loginid: string, ...reactions: VoidFunction[]): void {
// account was changed when this was unmounted.
- if (this.root_store?.client.loginid !== loginid) {
+ if (this.root_store.client.loginid !== loginid) {
reactions.forEach(act => act());
this.partial_fetch_time = 0;
}
diff --git a/packages/trader/src/Stores/useTraderStores.tsx b/packages/trader/src/Stores/useTraderStores.tsx
index ff5ab4b5becd..5e4db0cd77c2 100644
--- a/packages/trader/src/Stores/useTraderStores.tsx
+++ b/packages/trader/src/Stores/useTraderStores.tsx
@@ -1,128 +1,8 @@
import React from 'react';
import { useStore } from '@deriv/stores';
import TradeStore from './Modules/Trading/trade-store';
-import moment from 'moment';
-type TTextValueStrings = {
- text: string;
- value: string;
-};
-
-type TContractTypesList = {
- name: string;
- categories: TTextValueStrings[];
-};
-
-type TContractCategoriesList = {
- Multipliers: TContractTypesList;
- 'Ups & Downs': TContractTypesList;
- 'Highs & Lows': TContractTypesList;
- 'Ins & Outs': TContractTypesList;
- 'Look Backs': TContractTypesList;
- Digits: TContractTypesList;
- Vanillas: TContractTypesList;
- Accumulators: TContractTypesList;
-};
-
-type TToastBoxListItem = {
- contract_category: string;
- contract_types: [
- {
- text: string;
- value: string;
- }
- ];
-};
-
-type TToastBoxObject = {
- key?: boolean;
- buy_price?: number;
- currency?: string;
- contract_type?: string;
- list?: TToastBoxListItem[];
-};
-
-type TOverrideTradeStore = Omit<
- TradeStore,
- | 'accumulator_range_list'
- | 'barriers'
- | 'basis_list'
- | 'cancellation_price'
- | 'cancellation_range_list'
- | 'clearContractPurchaseToastBox'
- | 'contract_purchase_toast_box'
- | 'contract_types_list'
- | 'duration_min_max'
- | 'duration_units_list'
- | 'expiry_date'
- | 'expiry_time'
- | 'expiry_type'
- | 'form_components'
- | 'market_close_times'
- | 'market_open_times'
- | 'multiplier_range_list'
- | 'multiplier'
- | 'sessions'
- | 'setIsTradeParamsExpanded'
- | 'start_dates_list'
- | 'start_time'
- | 'symbol'
- | 'take_profit'
- | 'proposal_info'
- | 'trade_types'
- | 'ticks_history_stats'
-> & {
- accumulator_range_list?: number[];
- basis_list: Array;
- cancellation_price?: number;
- cancellation_range_list: Array;
- clearContractPurchaseToastBox: () => void;
- contract_purchase_toast_box: TToastBoxObject;
- contract_types_list: TContractCategoriesList;
- duration_min_max: {
- [key: string]: { min: number; max: number };
- };
- duration_units_list: Array;
- expiry_date: string | null;
- expiry_time: string | null;
- expiry_type: string | null;
- form_components: string[];
- long_barriers: Record | { barrier: string; barrier_choices: string[] };
- market_open_times: string[];
- market_close_times: string[];
- multiplier: number;
- multiplier_range_list: number[];
- proposal_info: {
- [key: string]: {
- has_error?: boolean;
- id: string;
- has_increased?: boolean;
- message?: string;
- cancellation?: {
- ask_price: number;
- date_expiry: number;
- };
- growth_rate?: number;
- returns?: string;
- stake: string;
- };
- };
- sessions: Array<{ open: moment.Moment; close: moment.Moment }>;
- setIsTradeParamsExpanded: (value: boolean) => void;
- short_barriers: Record | { barrier: string; barrier_choices: string[] };
- strike_price_choices: Record | { barrier: string; barrier_choices: string[] };
- start_dates_list: Array<{ text: string; value: number }>;
- start_time?: string | null;
- symbol: string;
- take_profit?: string;
- ticks_history_stats: {
- ticks_stayed_in?: number[];
- last_tick_epoch?: number;
- };
- trade_types: { [key: string]: string };
-};
-
-const TraderStoreContext = React.createContext(null);
+const TraderStoreContext = React.createContext(null);
export const TraderStoreProvider = ({ children }: React.PropsWithChildren) => {
const { modules } = useStore();
diff --git a/packages/trader/src/Types/common-prop.type.ts b/packages/trader/src/Types/common-prop.type.ts
index bc38b04c55e2..d2252c3012d8 100644
--- a/packages/trader/src/Types/common-prop.type.ts
+++ b/packages/trader/src/Types/common-prop.type.ts
@@ -1,19 +1,16 @@
import { useTraderStore } from 'Stores/useTraderStores';
-export type TProposalTypeInfo = {
- has_error?: boolean;
- id: string;
- has_increased?: boolean;
- message?: string;
- cancellation?: {
- ask_price: number;
- date_expiry: number;
- };
- growth_rate?: number;
- returns?: string;
- stake: string;
+export type TTextValueStrings = {
+ text: string;
+ value: string;
+};
+export type TTextValueNumber = {
+ text: string;
+ value: number;
};
+export type TProposalTypeInfo = TTradeStore['proposal_info'][string];
+
export type TError = {
error?: {
code?: string;
diff --git a/packages/trader/src/Utils/Validator/validator.ts b/packages/trader/src/Utils/Validator/validator.ts
index c0a840093d41..c51f76b38287 100644
--- a/packages/trader/src/Utils/Validator/validator.ts
+++ b/packages/trader/src/Utils/Validator/validator.ts
@@ -6,8 +6,8 @@ type TOptions = {
[key: string]: unknown;
decimals?: string | number;
is_required?: boolean;
- max?: number | string;
- min?: number | string;
+ max?: number | string | null;
+ min?: number | string | null;
name1?: string;
name2?: string;
regex?: RegExp;
@@ -17,9 +17,14 @@ type TOptions = {
type TInitPreBuildDVRs = ReturnType;
export type TRuleOptions = {
- func: (value: string | number, options?: TOptions, store?: TTradeStore, inputs?: unknown) => boolean;
- condition: (store: TTradeStore) => boolean;
- message: string;
+ func?: (
+ value: T,
+ options?: TOptions,
+ store?: TTradeStore,
+ inputs?: Pick
+ ) => boolean | { is_ok: boolean; message: string };
+ condition?: (store: TTradeStore) => boolean;
+ message?: string;
} & TOptions;
type TRule = string | Array;
@@ -30,13 +35,13 @@ type TValidationResult = {
};
class Validator {
- input: Partial;
+ input: Pick;
rules: Partial;
store: TTradeStore;
errors: Errors;
error_count: number;
- constructor(input: Partial, rules: Partial, store: TTradeStore) {
+ constructor(input: Pick, rules: Partial, store: TTradeStore) {
this.input = input;
this.rules = rules;
this.store = store;
@@ -99,8 +104,8 @@ class Validator {
let is_valid, error_message;
if (ruleObject.name === 'number') {
- const { is_ok, message }: TValidationResult = ruleObject.validator(
- this.input[attribute as keyof TTradeStore],
+ const { is_ok, message } = ruleObject.validator(
+ this.input[attribute as keyof TTradeStore] as string,
ruleObject.options,
this.store,
this.input
@@ -109,7 +114,7 @@ class Validator {
error_message = message;
} else {
is_valid = ruleObject.validator(
- this.input[attribute as keyof TTradeStore],
+ this.input[attribute as keyof TTradeStore] as string,
ruleObject.options,
this.store,
this.input
@@ -152,12 +157,7 @@ class Validator {
: (
getPreBuildDVRs() as unknown as {
[key: string]: {
- func: (
- value: string | number,
- options?: TRuleOptions,
- store?: TTradeStore,
- inputs?: unknown
- ) => boolean | { is_ok: boolean; message: string };
+ func: TRuleOptions['func'];
};
}
)[rule_object_name].func,