From 55b29ba8d8aca922a9adb121626a4b043de642e8 Mon Sep 17 00:00:00 2001 From: Akmal Djumakhodjaev Date: Wed, 25 Oct 2023 17:22:52 +0800 Subject: [PATCH] Akmal | Likhith / feat: vanilla financials (#8355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Akmal / content updates for EU clients (#38) * feat: convert vanilla options component * Revert "Akmal / content updates for EU clients (#38)" * fix: import from shared * likhith / feat: ✨ incorporate vanilla financials * fix: content changes for EU * feat: add unit tests for vanilla options * fix: reuse types * fix: add empty line * fix: remove commented line * chore: refactor test cases * chore: fix datatypes according to latest changes * fix: datatypes warnings * chore: fix formatting * fix: return missing props * feat: update infobox longcode description * feat: remove all payout formatting for vanillas * fix: circle ci warning * fix: execute sell even if bid price is zero * fix: show appropriate error message when trade falls on weekend * chore: make use of useTraderStore hook * feat: trigger vercel * feat: trigger vercel * chore: remove unused logic * feat: content updates for vanilla financial markets * fix: type * fix: circle ci errors after merge * fix: other circle ci issues * feat: improve solution * feat: refactor test cases * feat: small improvements * feat: trigger circle ci * feat: trigger circle ci * fix: code formatting * fix: code formatting * fix: merge conflict * fix: review comments * fix: mobile bug * chore: format code * chore: code suggestions * chore: code suggestions * fix: remove unused variable * fix: data type * fix: resolve issues after merge * fix: circle ci issue * feat: trigger circle ci * feat: modify test cases * chore: remove unused function * feat: refactor vanilla fx logic for contract glossary and description * fix: apply circle ci suggestions * fix: add a key * fix: remove unused variables * feat: add a type * fix: apply review suggestions * fix: new label for trade categories * fix: typescript types * fix: issues after resolving conflicts * fix: test case * feat: refractor the code * fix: circle ci warning * feat: add observer * fix: issues after merge * chore: fix import * fix: refactor logic after conflicts * chore: resolve conflicts --- .../vanilla-options-card-body.spec.tsx | 71 +++++++++++++++ ...body.jsx => vanilla-options-card-body.tsx} | 53 ++++++----- .../core/src/Stores/contract-replay-store.js | 2 +- .../shared/src/utils/constants/contract.ts | 5 +- .../shared/src/utils/contract/contract.tsx | 15 ++++ .../ContractAudit/contract-details.tsx | 19 ++-- .../ContractDrawer/contract-drawer.tsx | 16 ++-- .../Trading/Categories/trade-categories.tsx | 73 ++++++++++----- .../Elements/payout-per-point-mobile.tsx | 16 +++- .../Components/Elements/purchase-button.tsx | 9 +- .../Components/Elements/purchase-fieldset.tsx | 12 ++- .../contract-type-glossary.tsx | 90 ++++++++++++++++++- .../ContractTypeInfo/contract-type-info.tsx | 5 ++ .../__tests__/contract-type-info.spec.tsx | 1 + .../ContractType/contract-type-display.tsx | 4 +- .../Form/Purchase/contract-info.tsx | 35 ++++++-- .../Modules/Trading/Containers/purchase.tsx | 16 ++-- .../Modules/Trading/Helpers/contract-type.tsx | 3 +- .../src/Stores/Modules/Trading/trade-store.ts | 7 ++ 19 files changed, 363 insertions(+), 89 deletions(-) create mode 100644 packages/components/src/components/contract-card/contract-card-items/__tests__/vanilla-options-card-body.spec.tsx rename packages/components/src/components/contract-card/contract-card-items/{vanilla-options-card-body.jsx => vanilla-options-card-body.tsx} (75%) diff --git a/packages/components/src/components/contract-card/contract-card-items/__tests__/vanilla-options-card-body.spec.tsx b/packages/components/src/components/contract-card/contract-card-items/__tests__/vanilla-options-card-body.spec.tsx new file mode 100644 index 000000000000..7960b467b3be --- /dev/null +++ b/packages/components/src/components/contract-card/contract-card-items/__tests__/vanilla-options-card-body.spec.tsx @@ -0,0 +1,71 @@ +import React from 'react'; +import { render, RenderResult } from '@testing-library/react'; +import VanillaOptionsCardBody, { TVanillaOptionsCardBodyProps } from '../vanilla-options-card-body'; + +describe('VanillaOptionsCardBody', () => { + const mock_props: TVanillaOptionsCardBodyProps = { + contract_info: { + buy_price: 100, + bid_price: 105, + entry_spot_display_value: '110', + barrier: '120', + sell_price: 95, + profit: -5, + status: 'loss', + }, + currency: 'USD', + getCardLabels: () => ({ + CONTRACT_VALUE: 'Contract Value', + ENTRY_SPOT: 'Entry Spot', + PURCHASE_PRICE: 'Purchase Price', + STRIKE: 'Strike', + TOTAL_PROFIT_LOSS: 'Total Profit/Loss', + }), + is_sold: true, + progress_slider: null, + status: 'loss', + }; + it('should render the correct content for a sold contract', async () => { + // Render the component with the provided props + const { getByText, getByTestId }: RenderResult = render( + + ); + + const indicative_movement = getByTestId('dc-contract-card__indicative--movement'); + + // Test that the correct elements are present in the component + expect(getByText(mock_props.getCardLabels().CONTRACT_VALUE)).toBeInTheDocument(); + expect(getByText(mock_props.getCardLabels().ENTRY_SPOT)).toBeInTheDocument(); + expect(getByText(mock_props.getCardLabels().PURCHASE_PRICE)).toBeInTheDocument(); + expect(getByText(mock_props.getCardLabels().STRIKE)).toBeInTheDocument(); + expect(getByText(mock_props.getCardLabels().TOTAL_PROFIT_LOSS)).toBeInTheDocument(); + expect(indicative_movement).toHaveClass('dc-contract-card__indicative--movement-complete'); + expect(indicative_movement.querySelector('.dc-icon.dc-icon--red')).toBeInTheDocument(); + }); + + it('should render the correct content for an unsold contract', async () => { + mock_props.contract_info.profit = 5; + mock_props.contract_info.status = 'profit'; + mock_props.is_sold = false; + mock_props.progress_slider =
; + mock_props.status = 'profit'; + delete mock_props.contract_info.sell_price; + + + // Render the component with the provided props + const { getByText, getByTestId }: RenderResult = render( + + ); + + const indicative_movement = getByTestId('dc-contract-card__indicative--movement'); + + // Test that the correct elements are present in the component + expect(getByText(mock_props. getCardLabels().CONTRACT_VALUE)).toBeInTheDocument(); + expect(getByText(mock_props. getCardLabels().ENTRY_SPOT)).toBeInTheDocument(); + expect(getByText(mock_props. getCardLabels().PURCHASE_PRICE)).toBeInTheDocument(); + expect(getByText(mock_props. getCardLabels().STRIKE)).toBeInTheDocument(); + expect(getByText(mock_props. getCardLabels().TOTAL_PROFIT_LOSS)).toBeInTheDocument(); + expect(indicative_movement).not.toHaveClass('dc-contract-card__indicative--movement-complete'); + expect(indicative_movement.querySelector('.dc-icon.dc-icon--green')).toBeInTheDocument(); + }); +}); diff --git a/packages/components/src/components/contract-card/contract-card-items/vanilla-options-card-body.jsx b/packages/components/src/components/contract-card/contract-card-items/vanilla-options-card-body.tsx similarity index 75% rename from packages/components/src/components/contract-card/contract-card-items/vanilla-options-card-body.jsx rename to packages/components/src/components/contract-card/contract-card-items/vanilla-options-card-body.tsx index 696f2cd76407..f817b4f3cbd9 100644 --- a/packages/components/src/components/contract-card/contract-card-items/vanilla-options-card-body.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/vanilla-options-card-body.tsx @@ -1,16 +1,34 @@ import classNames from 'classnames'; -import PropTypes from 'prop-types'; import React from 'react'; import { getDisplayStatus, isCryptocurrency } from '@deriv/shared'; +import { TContractInfo } from '@deriv/shared/src/utils/contract/contract-types'; import DesktopWrapper from '../../desktop-wrapper'; import MobileWrapper from '../../mobile-wrapper'; import ContractCardItem from './contract-card-item'; import Icon from '../../icon'; import Money from '../../money'; import { ResultStatusIcon } from '../result-overlay/result-overlay'; +import { TGetCardLables } from '../../types'; -const VanillaOptionsCardBody = ({ contract_info, currency, getCardLabels, is_sold, progress_slider, status }) => { - const { buy_price, bid_price, entry_spot_display_value, barrier, sell_price, profit } = contract_info; +export type TVanillaOptionsCardBodyProps = { + contract_info: TContractInfo; + currency: string; + getCardLabels: TGetCardLables; + is_sold: boolean; + progress_slider: React.ReactNode; + status?: string; +}; + +const VanillaOptionsCardBody: React.FC = ({ + contract_info, + currency, + getCardLabels, + is_sold, + progress_slider, + status, +}) => { + const { buy_price, bid_price, entry_spot_display_value, barrier, sell_price, profit }: TContractInfo = + contract_info; const contract_value = is_sold ? sell_price : bid_price; const { CONTRACT_VALUE, ENTRY_SPOT, PURCHASE_PRICE, STRIKE, TOTAL_PROFIT_LOSS } = getCardLabels(); @@ -27,25 +45,26 @@ const VanillaOptionsCardBody = ({ contract_info, currency, getCardLabels, is_sol - + {entry_spot_display_value && } - + {barrier && }
0} + is_loss={Number(profit) < 0} + is_won={Number(profit) > 0} >
{status === 'profit' && } {status === 'loss' && } @@ -60,7 +79,9 @@ const VanillaOptionsCardBody = ({ contract_info, currency, getCardLabels, is_sol - + {entry_spot_display_value && ( + + )}
@@ -70,7 +91,7 @@ const VanillaOptionsCardBody = ({ contract_info, currency, getCardLabels, is_sol
- + {barrier && } @@ -86,14 +107,15 @@ const VanillaOptionsCardBody = ({ contract_info, currency, getCardLabels, is_sol className='dc-contract-card-item__total-profit-loss' header={TOTAL_PROFIT_LOSS} is_crypto={isCryptocurrency(currency)} - is_loss={+profit < 0} - is_won={+profit > 0} + is_loss={Number(profit) < 0} + is_won={Number(profit) > 0} >
{status === 'profit' && } {status === 'loss' && } @@ -105,13 +127,4 @@ const VanillaOptionsCardBody = ({ contract_info, currency, getCardLabels, is_sol ); }; -VanillaOptionsCardBody.propTypes = { - contract_info: PropTypes.object, - currency: PropTypes.string, - getCardLabels: PropTypes.func, - is_sold: PropTypes.bool, - progress_slider: PropTypes.node, - status: PropTypes.string, -}; - export default React.memo(VanillaOptionsCardBody); diff --git a/packages/core/src/Stores/contract-replay-store.js b/packages/core/src/Stores/contract-replay-store.js index 6ec6aa998e50..3d029b39b784 100644 --- a/packages/core/src/Stores/contract-replay-store.js +++ b/packages/core/src/Stores/contract-replay-store.js @@ -255,7 +255,7 @@ export default class ContractReplayStore extends BaseStore { onClickSell(contract_id) { const { bid_price } = this.contract_info; - if (contract_id && bid_price) { + if (contract_id && (bid_price || bid_price === 0)) { this.is_sell_requested = true; WS.sell(contract_id, bid_price).then(this.handleSell); } diff --git a/packages/shared/src/utils/constants/contract.ts b/packages/shared/src/utils/constants/contract.ts index 9ce99b24f057..23d0011dadd8 100644 --- a/packages/shared/src/utils/constants/contract.ts +++ b/packages/shared/src/utils/constants/contract.ts @@ -7,10 +7,11 @@ import { shouldShowCancellation, shouldShowExpiration, TURBOS, VANILLALONG } fro export const getLocalizedBasis = () => ({ accumulator: localize('Accumulators'), - payout: localize('Payout'), + multiplier: localize('Multiplier'), + payout_per_pip: localize('Payout per pip'), payout_per_point: localize('Payout per point'), + payout: localize('Payout'), stake: localize('Stake'), - multiplier: localize('Multiplier'), turbos: localize('Turbos'), } as const); diff --git a/packages/shared/src/utils/contract/contract.tsx b/packages/shared/src/utils/contract/contract.tsx index d414cd2d84f5..ab75dc558875 100644 --- a/packages/shared/src/utils/contract/contract.tsx +++ b/packages/shared/src/utils/contract/contract.tsx @@ -12,6 +12,17 @@ type TGetAccuBarriersDTraderTimeout = (params: { underlying: string; }) => number; +// Trade types that are considered as vanilla financials +export const VANILLA_FX_SYMBOLS = [ + 'frxAUDUSD', + 'frxEURUSD', + 'frxGBPUSD', + 'frxUSDCAD', + 'frxUSDJPY', + 'frxXAUUSD', + 'frxXAGUSD', +] as const; + // animation correction time is an interval in ms between ticks receival from API and their actual visual update on the chart export const ANIMATION_CORRECTION_TIME = 200; export const DELAY_TIME_1S_SYMBOL = 500; @@ -26,6 +37,7 @@ export const TURBOS = { export const VANILLALONG = { CALL: 'vanillalongcall', PUT: 'vanillalongput', + FX: 'vanilla_fx', } as const; export const getContractStatus = ({ contract_type, exit_tick_time, profit, status }: TContractInfo) => { @@ -81,6 +93,9 @@ export const isTurbosContract = (contract_type = '') => /TURBOS/i.test(contract_ export const isVanillaContract = (contract_type = '') => /VANILLA/i.test(contract_type); +export const isVanillaFxContract = (contract_type = '', symbol = '') => + isVanillaContract(contract_type) && VANILLA_FX_SYMBOLS.includes(symbol as typeof VANILLA_FX_SYMBOLS[number]); + export const isSmartTraderContract = (contract_type = '') => /RUN|EXPIRY|RANGE|UPORDOWN|ASIAN/i.test(contract_type); export const isAsiansContract = (contract_type = '') => /ASIAN/i.test(contract_type); diff --git a/packages/trader/src/App/Components/Elements/ContractAudit/contract-details.tsx b/packages/trader/src/App/Components/Elements/ContractAudit/contract-details.tsx index b75b67a33900..87c7b23dadb9 100644 --- a/packages/trader/src/App/Components/Elements/ContractAudit/contract-details.tsx +++ b/packages/trader/src/App/Components/Elements/ContractAudit/contract-details.tsx @@ -5,16 +5,18 @@ import { epochToMoment, getCancellationPrice, getCurrencyDisplayCode, + getLocalizedBasis, hasTwoBarriers, isAccumulatorContract, + isEndedBeforeCancellationExpired, isMobile, isMultiplierContract, isSmartTraderContract, isAsiansContract, isTurbosContract, - isUserSold, - isEndedBeforeCancellationExpired, isUserCancelled, + isUserSold, + isVanillaFxContract, toGMTFormat, TContractInfo, } from '@deriv/shared'; @@ -49,17 +51,18 @@ const ContractDetails = ({ commission, contract_type, currency, + date_start, + display_number_of_contracts, entry_spot_display_value, entry_tick_time, exit_tick_time, high_barrier, + low_barrier, profit, - date_start, tick_count, tick_passed, transaction_ids: { buy, sell } = {}, - low_barrier, - display_number_of_contracts, + underlying, } = contract_info; const is_profit = Number(profit) >= 0; @@ -74,6 +77,10 @@ const ContractDetails = ({ : `${tick_count} ${ticks_label}`; const { action_names, event_names, form_names, form_sources } = getRudderstackConfig(); + const vanilla_payout_text = isVanillaFxContract(contract_type, underlying) + ? getLocalizedBasis().payout_per_pip + : getLocalizedBasis().payout_per_point; + const getLabel = () => { if (isUserSold(contract_info) && isEndedBeforeCancellationExpired(contract_info)) return localize('Deal cancellation'); @@ -170,7 +177,7 @@ const ContractDetails = ({ } - label={localize('Payout per point')} + label={vanilla_payout_text} value={ display_number_of_contracts ? `${display_number_of_contracts} ${getCurrencyDisplayCode(currency)}` diff --git a/packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.tsx b/packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.tsx index 69045cc10ab8..aefdf90b8b83 100644 --- a/packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.tsx +++ b/packages/trader/src/App/Components/Elements/ContractDrawer/contract-drawer.tsx @@ -71,22 +71,22 @@ const ContractDrawer = observer( const contract_audit = ( ); diff --git a/packages/trader/src/Assets/Trading/Categories/trade-categories.tsx b/packages/trader/src/Assets/Trading/Categories/trade-categories.tsx index 7ffcfa547a8d..0aea9cb29f39 100644 --- a/packages/trader/src/Assets/Trading/Categories/trade-categories.tsx +++ b/packages/trader/src/Assets/Trading/Categories/trade-categories.tsx @@ -11,10 +11,12 @@ import MultiplierTradeDescription from './Description/multiplier-trade-descripti const TradeCategories = ({ category, onClick, + is_vanilla_fx = false, is_multiplier_fx = false, }: { category?: string; onClick: () => void; + is_vanilla_fx?: boolean; is_multiplier_fx?: boolean; }) => { let TradeTypeTemplate; @@ -410,28 +412,55 @@ const TradeCategories = ({ /> - , - ]} - /> - - - , - ]} - /> + {is_vanilla_fx ? ( + , + , + ]} + /> + ) : ( + , + ]} + /> + )} + + + {is_vanilla_fx ? ( + , + ]} + /> + ) : ( + , + ]} + /> + )} ); 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 fd24be61089d..4d6a5fe5148c 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 @@ -3,7 +3,7 @@ import { Icon, Money, Text, Popover } from '@deriv/components'; import { Localize, localize } from '@deriv/translations'; import Fieldset from 'App/Components/Form/fieldset'; import { observer } from '@deriv/stores'; -import { getContractSubtype, isVanillaContract } from '@deriv/shared'; +import { getContractSubtype, getLocalizedBasis } from '@deriv/shared'; import { useTraderStore } from 'Stores/useTraderStores'; import { TProposalTypeInfo } from 'Types'; @@ -12,7 +12,7 @@ type TProposalInfo = { }; const PayoutPerPointMobile = observer(() => { - const { currency, proposal_info, contract_type } = useTraderStore(); + const { currency, proposal_info, contract_type, is_vanilla, is_vanilla_fx } = useTraderStore(); const contract_key = contract_type?.toUpperCase(); // remove assertion and local TProposalInfo type after TS migration for trade package is complete const { has_error, has_increased, id, message, obj_contract_basis } = @@ -23,8 +23,16 @@ const PayoutPerPointMobile = observer(() => { Long: localize('For Long:'), Short: localize('For Short:'), }; - const tooltip_text = isVanillaContract(contract_type) ? ( + const vanilla_payout_message = is_vanilla_fx ? ( + ]} + /> + ) : ( + ); + const tooltip_text = is_vanilla ? ( + vanilla_payout_message ) : ( {
- {label} + {is_vanilla_fx ? getLocalizedBasis().payout_per_pip : label} void; @@ -53,8 +54,8 @@ const IconComponentWrapper = ({ type }: { type: string }) => ( ); const PurchaseButton = ({ - buy_info, basis, // mobile-only + buy_info, currency, growth_rate, has_deal_cancellation, @@ -65,13 +66,14 @@ const PurchaseButton = ({ is_high_low, is_loading, is_multiplier, - is_vanilla, is_proposal_empty, is_turbos, + is_vanilla_fx, + is_vanilla, + onClickPurchase, purchased_states_arr, setPurchaseState, should_fade, - onClickPurchase, type, }: TPurchaseButton) => { const getIconType = () => { @@ -164,6 +166,7 @@ const PurchaseButton = ({ is_loading={is_loading} is_multiplier={is_multiplier} is_turbos={is_turbos} + is_vanilla_fx={is_vanilla_fx} is_vanilla={is_vanilla} should_fade={should_fade} proposal_info={info} 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 ab121cac3621..00f6a13b259f 100644 --- a/packages/trader/src/Modules/Trading/Components/Elements/purchase-fieldset.tsx +++ b/packages/trader/src/Modules/Trading/Components/Elements/purchase-fieldset.tsx @@ -24,6 +24,7 @@ type TPurchaseFieldset = { is_multiplier: boolean; is_proposal_empty: boolean; is_proposal_error: boolean; + is_vanilla_fx?: boolean; is_vanilla: boolean; is_turbos: boolean; onClickPurchase: (proposal_id: string, price: string | number, type: string) => void; @@ -39,8 +40,8 @@ const PurchaseFieldset = ({ currency, growth_rate, has_cancellation, - info, index, + info, is_accumulator, is_beta_chart, is_disabled, @@ -48,13 +49,14 @@ const PurchaseFieldset = ({ is_loading, is_market_closed, is_multiplier, - is_vanilla, is_proposal_empty, is_proposal_error, is_turbos, - purchased_states_arr, + is_vanilla_fx, + is_vanilla, onClickPurchase, onHoverPurchase, + purchased_states_arr, setPurchaseState, type, }: TPurchaseFieldset) => { @@ -84,6 +86,7 @@ const PurchaseFieldset = ({ is_loading={is_loading} is_multiplier={is_multiplier} is_vanilla={is_vanilla} + is_vanilla_fx={is_vanilla_fx} is_proposal_empty={is_proposal_empty} is_turbos={is_turbos} purchased_states_arr={purchased_states_arr} @@ -113,12 +116,13 @@ const PurchaseFieldset = ({ { let content; + let trade_category = category; + if (trade_category === 'vanillalongcall' && is_vanilla_fx) trade_category = VANILLALONG.FX; if (category) { - switch (category) { + switch (trade_category) { case 'accumulator': content = [ { type: 'heading', text: }, @@ -246,6 +250,89 @@ const ContractTypeGlossary = ({ }, ]; break; + case VANILLALONG.FX: + content = [ + { type: 'heading', text: }, + { + type: 'paragraph', + text: ( + + ), + }, + { + type: 'list', + text: [ + , + , + ], + }, + { type: 'heading', text: }, + { + type: 'paragraph', + text: ( + ]} + /> + ), + }, + { type: 'heading', text: }, + { + type: 'paragraph', + text: ( + + ), + }, + { type: 'heading', text: }, + { + type: 'paragraph', + text: , + }, + { type: 'heading', text: }, + { + type: 'paragraph', + text: ( + + ), + }, + { + type: 'list', + text: [ + , + ], + }, + { type: 'heading', text: }, + { + type: 'paragraph', + text: ( + + ), + }, + { type: 'heading', text: }, + { + type: 'paragraph', + text: ( + + ), + }, + { type: 'heading', text: }, + { + type: 'paragraph', + text: ( + + ), + }, + ]; + break; default: content = []; break; @@ -282,7 +369,6 @@ const ContractTypeGlossary = ({ ); } - return null; })} ); diff --git a/packages/trader/src/Modules/Trading/Components/Form/ContractType/ContractTypeInfo/contract-type-info.tsx b/packages/trader/src/Modules/Trading/Components/Form/ContractType/ContractTypeInfo/contract-type-info.tsx index 91829144d8db..e8449ab23241 100644 --- a/packages/trader/src/Modules/Trading/Components/Form/ContractType/ContractTypeInfo/contract-type-info.tsx +++ b/packages/trader/src/Modules/Trading/Components/Form/ContractType/ContractTypeInfo/contract-type-info.tsx @@ -31,6 +31,9 @@ const Info = observer(({ handleSelect, item, list }: TInfo) => { const { active_symbols: { active_symbols }, ui: { is_mobile }, + modules: { + trade: { is_vanilla_fx }, + }, } = useStore(); const [selected_tab, setSelectedTab] = React.useState(TABS.DESCRIPTION); const contract_types: TContractType[] | undefined = getContractTypes(list, item)?.filter( @@ -93,12 +96,14 @@ const Info = observer(({ handleSelect, item, list }: TInfo) => { ) : ( diff --git a/packages/trader/src/Modules/Trading/Components/Form/ContractType/__tests__/contract-type-info.spec.tsx b/packages/trader/src/Modules/Trading/Components/Form/ContractType/__tests__/contract-type-info.spec.tsx index b4cc7f7f22ca..f63d1b371cb4 100644 --- a/packages/trader/src/Modules/Trading/Components/Form/ContractType/__tests__/contract-type-info.spec.tsx +++ b/packages/trader/src/Modules/Trading/Components/Form/ContractType/__tests__/contract-type-info.spec.tsx @@ -269,6 +269,7 @@ const default_mock_store = { trade: { cached_multiplier_cancellation_list: [], symbol: 'test_symbol', + is_vanilla_fx: false, }, }, active_symbols: { diff --git a/packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-display.tsx b/packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-display.tsx index c159fd14d588..a977f4da0a29 100644 --- a/packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-display.tsx +++ b/packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-display.tsx @@ -15,8 +15,8 @@ type TDisplay = { const Display = ({ is_open, name, list, onClick, value }: TDisplay) => { const getDisplayText = () => - findContractCategory(list as unknown as TList[], { value })?.contract_types?.find( - (item: TContractType) => item.value === value + findContractCategory(list as unknown as TList[], { value })?.contract_types?.find((item: TContractType) => + item.value.includes(value) )?.text; return ( diff --git a/packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.tsx b/packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.tsx index 514b537ab450..4183147eced4 100644 --- a/packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.tsx +++ b/packages/trader/src/Modules/Trading/Components/Form/Purchase/contract-info.tsx @@ -14,6 +14,7 @@ type TContractInfo = Pick< > & { has_increased?: boolean | null; is_loading: boolean; + is_vanilla_fx?: boolean; proposal_info: TProposalTypeInfo; should_fade: boolean; type: string; @@ -24,20 +25,34 @@ const ContractInfo = ({ currency, growth_rate, has_increased, - is_loading, is_accumulator, + is_loading, is_multiplier, is_turbos, + is_vanilla_fx, is_vanilla, - should_fade, proposal_info, + should_fade, type, }: TContractInfo) => { const localized_basis = getLocalizedBasis(); + const vanilla_payout_text = is_vanilla_fx ? localized_basis.payout_per_pip : localized_basis.payout_per_point; + + const vanilla_payout_message = is_vanilla_fx ? ( + ]} + /> + ) : ( + + ); + const stakeOrPayout = () => { switch (basis) { case 'stake': { - if (is_vanilla || is_turbos) { + if (is_vanilla) { + return vanilla_payout_text; + } else if (is_turbos) { return localized_basis.payout_per_point; } return localized_basis.payout; @@ -50,8 +65,16 @@ const ContractInfo = ({ } }; + const getBasisText = () => { + if (is_vanilla) { + return vanilla_payout_text; + } + + return has_error_or_not_loaded ? stakeOrPayout() : proposal_info?.obj_contract_basis?.text || ''; + }; + 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 = getBasisText(); const { message, obj_contract_basis, stake } = proposal_info; const setHintMessage = () => { @@ -66,9 +89,7 @@ const ContractInfo = ({ ); } if (is_vanilla) { - return ( - - ); + return vanilla_payout_message; } return message; diff --git a/packages/trader/src/Modules/Trading/Containers/purchase.tsx b/packages/trader/src/Modules/Trading/Containers/purchase.tsx index 7eb632d18ec2..8ccab7618c08 100644 --- a/packages/trader/src/Modules/Trading/Containers/purchase.tsx +++ b/packages/trader/src/Modules/Trading/Containers/purchase.tsx @@ -37,22 +37,23 @@ const Purchase = observer(({ is_market_closed }: { is_market_closed?: boolean }) basis, contract_type, currency, - is_accumulator, - is_multiplier, growth_rate, has_cancellation, + has_open_accu_contract, + is_accumulator, + is_multiplier, is_purchase_enabled, + is_trade_enabled, is_turbos, + is_vanilla_fx, is_vanilla, - onPurchase: onClickPurchase, onHoverPurchase, + onPurchase: onClickPurchase, proposal_info, purchase_info, symbol, - validation_errors = {}, trade_types, - is_trade_enabled, - has_open_accu_contract, + validation_errors, } = useTraderStore(); const is_high_low = /^high_low$/.test(contract_type.toLowerCase()); @@ -93,10 +94,10 @@ const Purchase = observer(({ is_market_closed }: { is_market_closed?: boolean }) basis={basis} buy_info={purchase_info} currency={currency} - growth_rate={growth_rate} info={info} key={type} index={getSortedIndex(type, index)} + growth_rate={growth_rate} has_cancellation={has_cancellation} is_accumulator={is_accumulator} is_beta_chart={is_beta_chart} @@ -107,6 +108,7 @@ const Purchase = observer(({ is_market_closed }: { is_market_closed?: boolean }) is_multiplier={is_multiplier} is_turbos={is_turbos} is_vanilla={is_vanilla} + is_vanilla_fx={is_vanilla_fx} is_proposal_empty={is_proposal_empty} is_proposal_error={!!is_proposal_error} purchased_states_arr={purchased_states_arr} diff --git a/packages/trader/src/Modules/Trading/Helpers/contract-type.tsx b/packages/trader/src/Modules/Trading/Helpers/contract-type.tsx index 81f11f3240ae..6f5a140ab6dd 100644 --- a/packages/trader/src/Modules/Trading/Helpers/contract-type.tsx +++ b/packages/trader/src/Modules/Trading/Helpers/contract-type.tsx @@ -144,7 +144,8 @@ export const getAvailableContractTypes = (contract_types_list: TContractTypesLis // ); export const findContractCategory = (list: Partial, item: TItem) => - list?.find(list_item => list_item?.contract_types?.some(i => i.value === item.value)) || ({} as TContractCategory); + list?.find(list_item => list_item?.contract_types?.some(i => i.value.includes(item.value))) || + ({} as TContractCategory); export const getContractCategoryKey = (list: TList[], item: TItem) => findContractCategory(list, item)?.key; diff --git a/packages/trader/src/Stores/Modules/Trading/trade-store.ts b/packages/trader/src/Stores/Modules/Trading/trade-store.ts index cb1ec53cb20c..efd3956e2b0b 100644 --- a/packages/trader/src/Stores/Modules/Trading/trade-store.ts +++ b/packages/trader/src/Stores/Modules/Trading/trade-store.ts @@ -18,6 +18,7 @@ import { isMarketClosed, isMobile, isTurbosContract, + isVanillaFxContract, isVanillaContract, pickDefaultSymbol, resetEndTimeOnVolatilityIndices, @@ -442,6 +443,7 @@ export default class TradeStore extends BaseStore { is_symbol_in_active_symbols: computed, is_synthetics_available: computed, is_vanilla: computed, + is_vanilla_fx: computed, loadActiveSymbols: action.bound, logoutListener: action.bound, main_barrier_flattened: computed, @@ -1320,6 +1322,7 @@ export default class TradeStore extends BaseStore { // When this happens we want to populate the list of barrier choices to choose from since the value cannot be specified manually 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 as string[]); if (!this.barrier_choices.includes(this.barrier_1)) { @@ -1645,6 +1648,10 @@ export default class TradeStore extends BaseStore { return isVanillaContract(this.contract_type); } + get is_vanilla_fx() { + return isVanillaFxContract(this.contract_type, this.symbol); + } + setContractPurchaseToastbox(response: Buy) { const list = getAvailableContractTypes( this.contract_types_list,