diff --git a/package-lock.json b/package-lock.json index 82c18a6ee58e..e4ee164e959d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@contentpass/zxcvbn": "^4.4.3", "@deriv/api-types": "^1.0.11", "@deriv/deriv-api": "^1.0.11", - "@deriv/deriv-charts": "1.1.6", + "@deriv/deriv-charts": "1.1.8", "@deriv/js-interpreter": "^3.0.0", "@deriv/ui": "^0.0.15", "@enykeev/react-virtualized": "^9.22.4-mirror.1", @@ -2810,9 +2810,9 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@deriv/deriv-charts": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@deriv/deriv-charts/-/deriv-charts-1.1.6.tgz", - "integrity": "sha512-O3mzhzehIk48eeaRwn5LODSUwBqGD2J6EN7x0es+PtBcPSIS5QhPS4I3ke6730fLebB7mk7UPBtGTKR3WKR8ww==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@deriv/deriv-charts/-/deriv-charts-1.1.8.tgz", + "integrity": "sha512-IBAHcWK99sl8SefAb9zPxKV4AX3EauxELNOpxx5DmeHlq/peOnL5qf2HN7fRq/uOtZvn5Ol1QRnJAFsSFU2irA==", "dependencies": { "@welldone-software/why-did-you-render": "^3.3.8", "classnames": "^2.3.1", @@ -49118,9 +49118,9 @@ } }, "@deriv/deriv-charts": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@deriv/deriv-charts/-/deriv-charts-1.1.6.tgz", - "integrity": "sha512-O3mzhzehIk48eeaRwn5LODSUwBqGD2J6EN7x0es+PtBcPSIS5QhPS4I3ke6730fLebB7mk7UPBtGTKR3WKR8ww==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@deriv/deriv-charts/-/deriv-charts-1.1.8.tgz", + "integrity": "sha512-IBAHcWK99sl8SefAb9zPxKV4AX3EauxELNOpxx5DmeHlq/peOnL5qf2HN7fRq/uOtZvn5Ol1QRnJAFsSFU2irA==", "requires": { "@welldone-software/why-did-you-render": "^3.3.8", "classnames": "^2.3.1", diff --git a/packages/account/src/Components/address-details/__tests__/address-details.spec.js b/packages/account/src/Components/address-details/__tests__/address-details.spec.js index dc6e12ff7ea7..1038ac9a35a9 100644 --- a/packages/account/src/Components/address-details/__tests__/address-details.spec.js +++ b/packages/account/src/Components/address-details/__tests__/address-details.spec.js @@ -55,6 +55,7 @@ describe('', () => { address_state: 'Default test state', }, validate: jest.fn(), + disabled_items: [], }; const svgCommonRenderCheck = () => { @@ -262,4 +263,19 @@ describe('', () => { expect(address_state_input.value).toBe('State 1'); }); }); + + it('should disable the field if it is immuatble from BE', async () => { + mock_props.disabled_items = ['address_line_1', 'address_line_2']; + mock_props.value.address_state = ''; + + render(); + + expect(screen.getByPlaceholderText(address_line_1)).toBeDisabled(); + expect(screen.getByPlaceholderText(address_line_2)).toBeDisabled(); + await waitFor(() => { + expect(screen.getByRole('textbox', { name: 'State/Province' })).toBeEnabled(); + }); + expect(screen.getByPlaceholderText(address_town)).toBeEnabled(); + expect(screen.getByPlaceholderText(address_postcode)).toBeEnabled(); + }); }); diff --git a/packages/account/src/Components/address-details/address-details.jsx b/packages/account/src/Components/address-details/address-details.jsx index 5488ff485048..798ca66f7459 100644 --- a/packages/account/src/Components/address-details/address-details.jsx +++ b/packages/account/src/Components/address-details/address-details.jsx @@ -51,6 +51,7 @@ const AddressDetails = ({ is_gb_residence, onSubmitEnabledChange, selected_step_ref, + disabled_items, has_real_account, ...props }) => { @@ -159,7 +160,10 @@ const AddressDetails = ({ } maxLength={255} placeholder={localize('First line of address')} - disabled={props.value?.address_line_1 && has_real_account} + disabled={ + disabled_items.includes('address_line_1') || + (props.value?.address_line_1 && has_real_account) + } /> {!has_fetched_states_list && (
@@ -214,7 +224,8 @@ const AddressDetails = ({ }} list_portal_id={is_appstore ? '' : 'modal_root'} disabled={ - props.value?.address_state && has_real_account + disabled_items.includes('address_state') || + (props.value?.address_state && has_real_account) } /> @@ -234,7 +245,8 @@ const AddressDetails = ({ setAddressStateToDisplay(''); }} disabled={ - props.value?.address_state && has_real_account + disabled_items.includes('address_state') || + (props.value?.address_state && has_real_account) } /> @@ -247,7 +259,10 @@ const AddressDetails = ({ name='address_state' label={localize('State/Province')} placeholder={localize('State/Province')} - disabled={props.value?.address_state && has_real_account} + disabled={ + disabled_items.includes('address_state') || + (props.value?.address_state && has_real_account) + } /> )}
diff --git a/packages/account/src/Components/personal-details/__tests__/personal-details.spec.js b/packages/account/src/Components/personal-details/__tests__/personal-details.spec.js index 3ca03272bcc1..e14d980ccf9a 100644 --- a/packages/account/src/Components/personal-details/__tests__/personal-details.spec.js +++ b/packages/account/src/Components/personal-details/__tests__/personal-details.spec.js @@ -384,8 +384,6 @@ describe('', () => { 'first_name', 'last_name', 'date_of_birth', - 'place_of_birth', - 'citizen', 'account_opening_reason', ]} /> @@ -397,7 +395,7 @@ describe('', () => { expect(screen.getByTestId('last_name')).toBeDisabled(); expect(screen.getByTestId('date_of_birth')).toBeDisabled(); expect(screen.getByTestId('place_of_birth')).not.toBeDisabled(); - expect(screen.getByTestId('citizenship')).toBeEnabled(); // citizenship value is empty, so enable the field + expect(screen.getByTestId('citizenship')).toBeEnabled(); // citizenship value is not disabled by BE, so enable the field }); it('should disable citizen field if the client is_fully_authenticated', () => { diff --git a/packages/account/src/Components/personal-details/personal-details.jsx b/packages/account/src/Components/personal-details/personal-details.jsx index 879855526a6f..2f0e82b7e77d 100644 --- a/packages/account/src/Components/personal-details/personal-details.jsx +++ b/packages/account/src/Components/personal-details/personal-details.jsx @@ -316,8 +316,7 @@ const PersonalDetails = ({ @@ -529,6 +528,9 @@ const PersonalDetails = ({ {...field} required data_testid='tax_residence_mobile' + disabled={disabled_items.includes( + 'tax_residence' + )} />
@@ -651,6 +654,7 @@ const PersonalDetails = ({ setFieldTouched('employment_status', true); handleChange(e); }} + disabled={disabled_items.includes('employment_status')} /> @@ -742,6 +746,9 @@ const PersonalDetails = ({ {...field} required data_testid='account_opening_reason_mobile' + disabled={disabled_items.includes( + 'account_opening_reason' + )} /> diff --git a/packages/account/src/Components/trading-assessment/trading-assessment-dropdown.jsx b/packages/account/src/Components/trading-assessment/trading-assessment-dropdown.jsx index 2b843df82ba8..c7c26e01a5fd 100644 --- a/packages/account/src/Components/trading-assessment/trading-assessment-dropdown.jsx +++ b/packages/account/src/Components/trading-assessment/trading-assessment-dropdown.jsx @@ -4,7 +4,14 @@ import { DesktopWrapper, Dropdown, MobileWrapper, Text, SelectNative } from '@de import { localize, getLanguage } from '@deriv/translations'; import classNames from 'classnames'; -const TradingAssessmentDropdown = ({ item_list, onChange, values, setFieldValue, setEnableNextSection }) => { +const TradingAssessmentDropdown = ({ + disabled_items, + item_list, + onChange, + values, + setFieldValue, + setEnableNextSection, +}) => { React.useEffect(() => { checkIfAllFieldsFilled(); }, [values]); @@ -44,6 +51,7 @@ const TradingAssessmentDropdown = ({ item_list, onChange, values, setFieldValue, list={question?.answer_options} onChange={e => onChange(e, question.form_control, setFieldValue)} value={values[question.form_control]} + disabled={disabled_items.includes(question.form_control)} /> @@ -60,6 +68,7 @@ const TradingAssessmentDropdown = ({ item_list, onChange, values, setFieldValue, }} value={values[question.form_control]} hide_top_placeholder + disabled={disabled_items.includes(question.form_control)} /> diff --git a/packages/account/src/Components/trading-assessment/trading-assessment-form.jsx b/packages/account/src/Components/trading-assessment/trading-assessment-form.jsx index 9b5661dd5066..55fe6d1d54a8 100644 --- a/packages/account/src/Components/trading-assessment/trading-assessment-form.jsx +++ b/packages/account/src/Components/trading-assessment/trading-assessment-form.jsx @@ -10,6 +10,7 @@ import TradingAssessmentDropdown from './trading-assessment-dropdown.jsx'; const TradingAssessmentForm = ({ assessment_questions, class_name, + disabled_items, form_value, onSubmit, onCancel, @@ -143,6 +144,7 @@ const TradingAssessmentForm = ({ values={values} setFieldValue={setFieldValue} setEnableNextSection={setIsSectionFilled} + disabled_items={disabled_items ?? []} /> ) : ( )}
diff --git a/packages/account/src/Components/trading-assessment/trading-assessment-new-user.jsx b/packages/account/src/Components/trading-assessment/trading-assessment-new-user.jsx index 530ebbf67e15..df28a12ad0d9 100644 --- a/packages/account/src/Components/trading-assessment/trading-assessment-new-user.jsx +++ b/packages/account/src/Components/trading-assessment/trading-assessment-new-user.jsx @@ -3,6 +3,7 @@ import TradingAssessmentForm from './trading-assessment-form'; const TradingAssessmentNewUser = ({ assessment_questions, + disabled_items, goToNextStep, goToPreviousStep, onSave, @@ -39,6 +40,7 @@ const TradingAssessmentNewUser = ({ onSubmit={handleSubmit} onCancel={handleCancel} setSubSectionIndex={setSubSectionIndex} + disabled_items={disabled_items} /> ); }; diff --git a/packages/account/src/Components/trading-assessment/trading-assessment-radio-buttons.jsx b/packages/account/src/Components/trading-assessment/trading-assessment-radio-buttons.jsx index bdc9551ba43b..8d95b0829338 100644 --- a/packages/account/src/Components/trading-assessment/trading-assessment-radio-buttons.jsx +++ b/packages/account/src/Components/trading-assessment/trading-assessment-radio-buttons.jsx @@ -2,7 +2,15 @@ import React from 'react'; import { Field } from 'formik'; import { Text, RadioGroup } from '@deriv/components'; -const TradingAssessmentRadioButton = ({ text, list, onChange, values, form_control, setEnableNextSection }) => { +const TradingAssessmentRadioButton = ({ + disabled_items, + text, + list, + onChange, + values, + form_control, + setEnableNextSection, +}) => { React.useEffect(() => { setEnableNextSection(!!values[form_control]); }, [form_control]); @@ -31,6 +39,7 @@ const TradingAssessmentRadioButton = ({ text, list, onChange, values, form_contr key={answer.value} label={answer?.text} value={answer?.value} + disabled={disabled_items.includes(form_control)} /> ))} diff --git a/packages/account/src/Configs/address-details-config.js b/packages/account/src/Configs/address-details-config.js index 199aafa40fd6..aeee513b9aba 100644 --- a/packages/account/src/Configs/address-details-config.js +++ b/packages/account/src/Configs/address-details-config.js @@ -137,6 +137,7 @@ const addressDetailsConfig = ( ) => { const is_svg = upgrade_info?.can_upgrade_to === 'svg'; const config = address_details_config({ account_settings, is_svg }); + const disabled_items = account_settings.immutable_fields; const is_mf = real_account_signup_target === 'maltainvest'; return { @@ -152,6 +153,7 @@ const addressDetailsConfig = ( transformConfig(transformForResidence(config, residence), real_account_signup_target) ), is_svg, + disabled_items, is_mf, }, passthrough: ['residence_list', 'is_fully_authenticated', 'has_real_account'], diff --git a/packages/account/src/Configs/personal-details-config.js b/packages/account/src/Configs/personal-details-config.js index a994b15edf82..c73127c7911f 100644 --- a/packages/account/src/Configs/personal-details-config.js +++ b/packages/account/src/Configs/personal-details-config.js @@ -6,8 +6,6 @@ const personal_details_config = ({ residence_list, account_settings, is_appstore return {}; } - const disabled_items = account_settings.immutable_fields; // immutable fields set by BE - // minimum characters required is 9 numbers (excluding +- signs or space) const min_phone_number = 9; const max_phone_number = 35; @@ -134,7 +132,7 @@ const personal_details_config = ({ residence_list, account_settings, is_appstore ], }, employment_status: { - default_value: '', + default_value: account_settings.employment_status ?? '', supported_in: ['maltainvest'], rules: [['req', localize('Employment status is required.')]], }, @@ -158,7 +156,7 @@ const personal_details_config = ({ residence_list, account_settings, is_appstore return config; }; - return [getConfig(), disabled_items]; + return [getConfig()]; }; const personalDetailsConfig = ( @@ -166,12 +164,13 @@ const personalDetailsConfig = ( PersonalDetails, is_appstore = false ) => { - const [config, disabled_items] = personal_details_config({ + const [config] = personal_details_config({ residence_list, account_settings, is_appstore, real_account_signup_target, }); + const disabled_items = account_settings.immutable_fields; return { header: { active_title: is_appstore ? localize('A few personal details') : localize('Complete your personal details'), diff --git a/packages/account/src/Configs/trading-assessment-config.js b/packages/account/src/Configs/trading-assessment-config.js index e526ad205658..30124a640a64 100644 --- a/packages/account/src/Configs/trading-assessment-config.js +++ b/packages/account/src/Configs/trading-assessment-config.js @@ -254,55 +254,73 @@ export const trading_assessment_questions = () => [ const default_form_config = { supported_in: ['maltainvest'], - default_value: '', }; -export const trading_assessment_form_config = { - risk_tolerance: { - ...default_form_config, - }, - source_of_experience: { - ...default_form_config, - }, - cfd_experience: { - ...default_form_config, - }, - cfd_frequency: { - ...default_form_config, - }, - trading_experience_financial_instruments: { - ...default_form_config, - }, - trading_frequency_financial_instruments: { - ...default_form_config, - }, - cfd_trading_definition: { - ...default_form_config, - }, - leverage_impact_trading: { - ...default_form_config, - }, - leverage_trading_high_risk_stop_loss: { - ...default_form_config, - }, - required_initial_margin: { - ...default_form_config, - }, +export const getTradingAssessmentFormConfig = financial_assessment => { + return { + risk_tolerance: { + ...default_form_config, + default_value: financial_assessment?.risk_tolerance ?? '', + }, + source_of_experience: { + ...default_form_config, + default_value: financial_assessment?.source_of_experience ?? '', + }, + cfd_experience: { + ...default_form_config, + default_value: financial_assessment?.cfd_experience ?? '', + }, + cfd_frequency: { + ...default_form_config, + default_value: financial_assessment?.cfd_frequency ?? '', + }, + trading_experience_financial_instruments: { + ...default_form_config, + default_value: financial_assessment?.trading_experience_financial_instruments ?? '', + }, + trading_frequency_financial_instruments: { + ...default_form_config, + default_value: financial_assessment?.trading_frequency_financial_instruments ?? '', + }, + cfd_trading_definition: { + ...default_form_config, + default_value: financial_assessment?.cfd_trading_definition ?? '', + }, + leverage_impact_trading: { + ...default_form_config, + default_value: financial_assessment?.leverage_impact_trading ?? '', + }, + leverage_trading_high_risk_stop_loss: { + ...default_form_config, + default_value: financial_assessment?.leverage_trading_high_risk_stop_loss ?? '', + }, + required_initial_margin: { + ...default_form_config, + default_value: financial_assessment?.required_initial_margin ?? '', + }, + }; }; -const tradingAssessmentConfig = ({ real_account_signup_target, setSubSectionIndex }, TradingAssessmentNewUser) => ({ - header: { - active_title: localize('Complete your trading assessment'), - title: localize('Trading assessment'), - }, - body: TradingAssessmentNewUser, - form_value: getDefaultFields(real_account_signup_target, trading_assessment_form_config), - props: { - validate: generateValidationFunction(real_account_signup_target, trading_assessment_form_config), - assessment_questions: trading_assessment_questions(), - setSubSectionIndex, - }, - sub_step_count: trading_assessment_questions().length, -}); +const tradingAssessmentConfig = ( + { real_account_signup_target, financial_assessment, account_settings, setSubSectionIndex }, + TradingAssessmentNewUser +) => { + const trading_assessment_form_config = getTradingAssessmentFormConfig(financial_assessment); + return { + header: { + active_title: localize('Complete your trading assessment'), + title: localize('Trading assessment'), + }, + body: TradingAssessmentNewUser, + form_value: getDefaultFields(real_account_signup_target, trading_assessment_form_config), + props: { + validate: generateValidationFunction(real_account_signup_target, trading_assessment_form_config), + assessment_questions: trading_assessment_questions(), + disabled_items: account_settings?.immutable_fields, + setSubSectionIndex, + }, + sub_step_count: trading_assessment_questions().length, + }; +}; export default tradingAssessmentConfig; diff --git a/packages/bot-web-ui/package.json b/packages/bot-web-ui/package.json index d5b4794b91e5..4f8571e7241e 100644 --- a/packages/bot-web-ui/package.json +++ b/packages/bot-web-ui/package.json @@ -66,7 +66,7 @@ "dependencies": { "@deriv/bot-skeleton": "^1.0.0", "@deriv/components": "^1.0.0", - "@deriv/deriv-charts": "1.1.6", + "@deriv/deriv-charts": "1.1.8", "@deriv/shared": "^1.0.0", "@deriv/translations": "^1.0.0", "classnames": "^2.2.6", diff --git a/packages/cashier/src/components/email-verification-empty-state/__tests__/email-verification-empty-state.test.tsx b/packages/cashier/src/components/email-verification-empty-state/__tests__/email-verification-empty-state.test.tsx index 7dfd6b4a24e2..87a157bc470a 100644 --- a/packages/cashier/src/components/email-verification-empty-state/__tests__/email-verification-empty-state.test.tsx +++ b/packages/cashier/src/components/email-verification-empty-state/__tests__/email-verification-empty-state.test.tsx @@ -2,8 +2,6 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import EmailVerificationEmptyState from '../email-verification-empty-state'; import { TRootStore } from 'Types'; -import { useVerifyEmail } from '@deriv/hooks'; -import { VerifyEmail } from '@deriv/api-types'; import CashierProviders from '../../../cashier-providers'; const mock_store: DeepPartial = { @@ -13,18 +11,8 @@ const mock_store: DeepPartial = { }; describe('EmailVerificationEmptyState', () => { - const verify: ReturnType = { - is_loading: false, - error: '', - data: {} as VerifyEmail, - counter: 58, - is_counter_running: true, - sent_count: 2, - has_been_sent: true, - send: jest.fn(), - }; test('should disable resend button after sending the request', () => { - render(, { + render(, { wrapper: ({ children }) => {children}, }); diff --git a/packages/cashier/src/components/email-verification-empty-state/email-verification-empty-state.tsx b/packages/cashier/src/components/email-verification-empty-state/email-verification-empty-state.tsx index 9494cc8b8bda..479417cee08a 100644 --- a/packages/cashier/src/components/email-verification-empty-state/email-verification-empty-state.tsx +++ b/packages/cashier/src/components/email-verification-empty-state/email-verification-empty-state.tsx @@ -1,15 +1,17 @@ import React from 'react'; -import { useVerifyEmail } from '@deriv/hooks'; +import { useVerifyEmail, TEmailVerificationType } from '@deriv/hooks'; import { localize } from '@deriv/translations'; import EmptyState from 'Components/empty-state'; import EmailVerificationResendEmptyState from './email-verification-resend-empty-state'; import './email-verification-empty-state.scss'; type TEmailVerificationEmptyStateProps = { - verify: ReturnType; + type: TEmailVerificationType; }; -const EmailVerificationEmptyState = ({ verify }: TEmailVerificationEmptyStateProps) => { +const EmailVerificationEmptyState = ({ type }: TEmailVerificationEmptyStateProps) => { + const verify = useVerifyEmail(type); + const action = { label: localize("Didn't receive the email?"), onClick: verify.send, diff --git a/packages/cashier/src/pages/payment-agent/payment-agent-list/withdrawal-tab.tsx b/packages/cashier/src/pages/payment-agent/payment-agent-list/withdrawal-tab.tsx index 2de771ef96a2..265e2f567265 100644 --- a/packages/cashier/src/pages/payment-agent/payment-agent-list/withdrawal-tab.tsx +++ b/packages/cashier/src/pages/payment-agent/payment-agent-list/withdrawal-tab.tsx @@ -23,7 +23,8 @@ const WithdrawalTab = observer(() => { // match the behavior of the `Withdrawal` page and first inform the user. if (verify.error && 'code' in verify.error) return ; - if (!verify.is_loading && verify.has_been_sent) return ; + if (!verify.is_loading && verify.has_been_sent) + return ; if (verification_code || payment_agent.is_withdraw) return ; diff --git a/packages/cashier/src/pages/withdrawal/withdrawal-verification-email/withdrawal-verification-email.tsx b/packages/cashier/src/pages/withdrawal/withdrawal-verification-email/withdrawal-verification-email.tsx index 58342dcc63bf..678cca20fc09 100644 --- a/packages/cashier/src/pages/withdrawal/withdrawal-verification-email/withdrawal-verification-email.tsx +++ b/packages/cashier/src/pages/withdrawal/withdrawal-verification-email/withdrawal-verification-email.tsx @@ -21,7 +21,7 @@ const WithdrawalVerificationEmail = observer(() => { if (verify.error) return ; - if (verify.has_been_sent) return ; + if (verify.has_been_sent) return ; return ( <> diff --git a/packages/components/src/components/contract-card/contract-card-items/__tests__/tick-counter-bar.spec.js b/packages/components/src/components/contract-card/contract-card-items/__tests__/tick-counter-bar.spec.js new file mode 100644 index 000000000000..31326a484c88 --- /dev/null +++ b/packages/components/src/components/contract-card/contract-card-items/__tests__/tick-counter-bar.spec.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import TickCounterBar from '../tick-counter-bar'; + +describe('TickCounterBar', () => { + const mock_props = { + current_tick: 12345, + label: 'Ticks', + max_ticks_duration: 67890, + }; + it('should render properly', () => { + render(); + + const ticks_info_el = screen.getByText('12345/67890 Ticks'); + expect(ticks_info_el).toHaveClass('dc-tick-counter-bar__text'); + }); +}); diff --git a/packages/components/src/components/contract-card/contract-card-items/accumulator-card-body.jsx b/packages/components/src/components/contract-card/contract-card-items/accumulator-card-body.jsx new file mode 100644 index 000000000000..d984ef1df89a --- /dev/null +++ b/packages/components/src/components/contract-card/contract-card-items/accumulator-card-body.jsx @@ -0,0 +1,129 @@ +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { isCryptocurrency, getLimitOrderAmount, isValidToSell } from '@deriv/shared'; +import ContractCardItem from './contract-card-item.jsx'; +import ToggleCardDialog from './toggle-card-dialog.jsx'; +import Icon from '../../icon'; +import MobileWrapper from '../../mobile-wrapper'; +import Money from '../../money'; +import { ResultStatusIcon } from '../result-overlay/result-overlay.jsx'; + +const AccumulatorCardBody = ({ + addToast, + connectWithContractUpdate, + contract_info, + contract_update, + currency, + current_focus, + error_message_alignment, + getCardLabels, + getContractById, + indicative, + is_sold, + onMouseLeave, + removeToast, + setCurrentFocus, + status, + is_positions, +}) => { + const { buy_price, profit, limit_order, sell_price } = contract_info; + const { take_profit } = getLimitOrderAmount(contract_update || limit_order); + const is_valid_to_sell = isValidToSell(contract_info); + const { CURRENT_STAKE, STAKE, TAKE_PROFIT, TOTAL_PROFIT_LOSS } = getCardLabels(); + + return ( + +
+ + + + +
0, + 'dc-contract-card--loss': +profit < 0, + })} + > + +
+
+ {status === 'profit' && } + {status === 'loss' && } +
+
+ 0} + > + +
+ {status === 'profit' && } + {status === 'loss' && } +
+
+ + {take_profit ? : -} + {is_valid_to_sell && ( + + )} + +
+ {!!is_sold && ( + +
+ 0} /> +
+
+ )} +
+ ); +}; + +AccumulatorCardBody.propTypes = { + addToast: PropTypes.func, + connectWithContractUpdate: PropTypes.func, + contract_info: PropTypes.object, + contract_update: PropTypes.object, + currency: PropTypes.string, + current_focus: PropTypes.string, + error_message_alignment: PropTypes.string, + getCardLabels: PropTypes.func, + getContractById: PropTypes.func, + indicative: PropTypes.number, + is_positions: PropTypes.bool, + is_sold: PropTypes.bool, + onMouseLeave: PropTypes.func, + removeToast: PropTypes.func, + setCurrentFocus: PropTypes.func, + status: PropTypes.string, +}; + +export default React.memo(AccumulatorCardBody); diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-body.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-body.jsx index d92a15eead0c..577dc781b3aa 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-body.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-body.jsx @@ -1,19 +1,8 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; -import { - isCryptocurrency, - getCancellationPrice, - getIndicativePrice, - getLimitOrderAmount, - getCurrentTick, - getDisplayStatus, - isValidToCancel, - isValidToSell, - shouldShowCancellation, -} from '@deriv/shared'; +import { isCryptocurrency, getIndicativePrice, getCurrentTick, getDisplayStatus } from '@deriv/shared'; import ContractCardItem from './contract-card-item.jsx'; -import ToggleCardDialog from './toggle-card-dialog.jsx'; import CurrencyBadge from '../../currency-badge'; import DesktopWrapper from '../../desktop-wrapper'; import Icon from '../../icon'; @@ -21,224 +10,9 @@ import MobileWrapper from '../../mobile-wrapper'; import Money from '../../money'; import { ResultStatusIcon } from '../result-overlay/result-overlay.jsx'; import ProgressSliderMobile from '../../progress-slider-mobile'; - -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; - const contract_value = is_sold ? sell_price : bid_price; - - return ( - - -
- - - - - - - - - - - - - - - -
- 0} - > - -
- {status === 'profit' && } - {status === 'loss' && } -
-
-
- -
-
- - - - - - - -
- -
- - - - - - - -
- - {is_sold ? ( - - ) : ( - progress_slider - )} - 0} - > - -
- {status === 'profit' && } - {status === 'loss' && } -
-
-
-
-
- ); -}; - -const MultiplierCardBody = ({ - addToast, - contract_info, - contract_update, - connectWithContractUpdate, - currency, - current_focus, - error_message_alignment, - getCardLabels, - getContractById, - has_progress_slider, - progress_slider, - is_mobile, - is_sold, - onMouseLeave, - removeToast, - setCurrentFocus, - should_show_cancellation_warning, - status, - toggleCancellationWarning, -}) => { - const { buy_price, bid_price, profit, limit_order, underlying } = contract_info; - - const { take_profit, stop_loss } = getLimitOrderAmount(contract_update || limit_order); - const cancellation_price = getCancellationPrice(contract_info); - const is_valid_to_cancel = isValidToCancel(contract_info); - const is_valid_to_sell = isValidToSell(contract_info); - - return ( - -
- - - - -
0, - 'dc-contract-card--loss': +profit < 0, - })} - > - -
-
- - {cancellation_price ? ( - - ) : ( - - {shouldShowCancellation(underlying) ? - : getCardLabels().NOT_AVAILABLE} - - )} - - - - - {has_progress_slider && is_mobile && !is_sold && ( - {progress_slider} - )} -
- - {take_profit ? : -} - - - {stop_loss ? ( - - - - - - ) : ( - - - )} - - {(is_valid_to_sell || is_valid_to_cancel) && ( - - )} -
-
- 0} - > - -
- {status === 'profit' && } - {status === 'loss' && } -
-
-
- ); -}; +import AccumulatorCardBody from './accumulator-card-body.jsx'; +import MultiplierCardBody from './multiplier-card-body.jsx'; +import VanillaOptionsCardBody from './vanilla-options-card-body.jsx'; const ContractCardBody = ({ addToast, @@ -251,8 +25,10 @@ const ContractCardBody = ({ getCardLabels, getContractById, has_progress_slider, + is_accumulator, is_mobile, is_multiplier, + is_positions, is_sold, is_vanilla, onMouseLeave, @@ -266,6 +42,8 @@ const ContractCardBody = ({ const indicative = getIndicativePrice(contract_info); const { buy_price, sell_price, payout, profit, tick_count, date_expiry, purchase_time } = contract_info; const current_tick = tick_count ? getCurrentTick(contract_info) : null; + const { INDICATIVE_PRICE, PAYOUT, POTENTIAL_PAYOUT, POTENTIAL_PROFIT_LOSS, PROFIT_LOSS, PURCHASE_PRICE } = + getCardLabels(); const progress_slider_mobile_el = ( ); - const card_body = is_multiplier ? ( - - ) : is_vanilla ? ( - - ) : ( - -
- 0} - > - -
- {status === 'profit' && } - {status === 'loss' && } -
-
- - -
+ ); + } else if (is_accumulator) { + card_body = ( + + ); + } else if (is_vanilla) { + card_body = ( + + ); + } else { + card_body = ( + +
+ 0} > - {status === 'profit' && } - {status === 'loss' && } -
- - - - - - - -
- -
- {is_sold ? ( - - ) : ( - progress_slider_mobile_el - )} + +
+ {status === 'profit' && } + {status === 'loss' && } +
+ + + +
+ {status === 'profit' && } + {status === 'loss' && } +
+
+ + + + + +
-
- - ); + +
+ {is_sold ? ( + + ) : ( + progress_slider_mobile_el + )} +
+
+ + ); + } return ( @@ -393,9 +200,12 @@ ContractCardBody.propTypes = { error_message_alignment: PropTypes.string, getCardLabels: PropTypes.func, getContractById: PropTypes.func, + is_accumulator: PropTypes.bool, is_mobile: PropTypes.bool, is_multiplier: PropTypes.bool, + is_positions: PropTypes.bool, is_sold: PropTypes.bool, + is_vanilla: PropTypes.bool, onMouseLeave: PropTypes.func, removeToast: PropTypes.func, server_time: PropTypes.object, diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-footer.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-footer.jsx index b9a9084a7765..c58cca53cfc3 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-footer.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-footer.jsx @@ -12,6 +12,7 @@ const CardFooter = ({ is_multiplier, is_positions, is_sell_requested, + measure, onClickCancel, onClickSell, onFooterEntered, @@ -70,6 +71,7 @@ const CardFooter = ({ contract_info={contract_info} is_sell_requested={is_sell_requested} getCardLabels={getCardLabels} + measure={measure} onClickSell={onClickSell} />
@@ -85,6 +87,7 @@ CardFooter.propTypes = { is_multiplier: PropTypes.bool, is_positions: PropTypes.bool, is_sell_requested: PropTypes.bool, + measure: PropTypes.func, onClickCancel: PropTypes.func, onClickSell: PropTypes.func, onFooterEntered: PropTypes.func, diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-header.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-header.jsx index eca978b4915e..48953bf84814 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-header.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-header.jsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; import { CSSTransition } from 'react-transition-group'; -import { isHighLow, getCurrentTick, isBot } from '@deriv/shared'; +import { isHighLow, getCurrentTick, getGrowthRatePercentage, isBot, isAccumulatorContract } from '@deriv/shared'; import ContractTypeCell from './contract-type-cell.jsx'; import Button from '../../button'; import Icon from '../../icon'; @@ -10,6 +10,7 @@ import Text from '../../text'; import ProgressSlider from '../../progress-slider'; import DesktopWrapper from '../../desktop-wrapper'; import MobileWrapper from '../../mobile-wrapper'; +import TickCounterBar from './tick-counter-bar.jsx'; const ContractCardHeader = ({ contract_info, @@ -20,21 +21,48 @@ const ContractCardHeader = ({ id, is_mobile, is_sell_requested, + is_sold: is_contract_sold, is_valid_to_sell, onClickSell, server_time, }) => { const current_tick = contract_info.tick_count ? getCurrentTick(contract_info) : null; - const { underlying, multiplier, contract_type, shortcode, purchase_time, date_expiry, tick_count, is_sold } = - contract_info; + const { + growth_rate, + underlying, + multiplier, + contract_type, + shortcode, + purchase_time, + date_expiry, + tick_count, + tick_passed, + } = contract_info; const { is_pathname_bot } = isBot(); + const is_sold = !!contract_info.is_sold || is_contract_sold; + const is_accumulator = isAccumulatorContract(contract_type); + const contract_type_list_info = [ + { + is_param_displayed: multiplier, + displayed_param: `x${multiplier}`, + }, + { + is_param_displayed: is_accumulator, + displayed_param: `${getGrowthRatePercentage(growth_rate)}%`, + }, + ]; + const displayed_trade_param = + contract_type_list_info.find(contract_type_item_info => contract_type_item_info.is_param_displayed) + ?.displayed_param || ''; return ( <>
@@ -43,11 +71,16 @@ const ContractCardHeader = ({ {display_name || contract_info.display_name}
-
+
@@ -78,13 +111,20 @@ const ContractCardHeader = ({ ) : null} + {!is_sold && is_accumulator && ( + + )}
{(!has_progress_slider || !!is_sold) &&
} - {has_progress_slider && !is_sold && ( + {has_progress_slider && !is_sold && !is_accumulator && ( { +const ContractCardSell = ({ contract_info, getCardLabels, is_sell_requested, measure, onClickSell }) => { const is_valid_to_sell = isValidToSell(contract_info); const should_show_sell = hasContractEntered(contract_info) && isOpen(contract_info); @@ -14,6 +14,10 @@ const ContractCardSell = ({ contract_info, getCardLabels, is_sell_requested, onC ev.preventDefault(); }; + React.useEffect(() => { + measure?.(); + }, [should_show_sell, measure]); + return ( should_show_sell && ( @@ -39,6 +43,7 @@ ContractCardSell.propTypes = { contract_info: PropTypes.object, getCardLabels: PropTypes.func, is_sell_requested: PropTypes.any, + measure: PropTypes.func, onClickSell: PropTypes.func, }; diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-type-cell.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-type-cell.jsx index a5f2983e5e26..678b9a57c16d 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-type-cell.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-type-cell.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { isVanillaContract } from '@deriv/shared'; -const ContractTypeCell = ({ getContractTypeDisplay, is_high_low, multiplier, type }) => ( +const ContractTypeCell = ({ displayed_trade_param, getContractTypeDisplay, is_high_low, type }) => (
{getContractTypeDisplay(type, is_high_low) || ''}
- {multiplier &&
x{multiplier}
} + {displayed_trade_param && ( +
{displayed_trade_param}
+ )}
); ContractTypeCell.propTypes = { + displayed_trade_param: PropTypes.string, getContractTypeDisplay: PropTypes.func, is_high_low: PropTypes.bool, - multiplier: PropTypes.number, type: PropTypes.string, }; diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-update-form.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-update-form.jsx index 6bd9097f114a..8d421265d63f 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-update-form.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-update-form.jsx @@ -23,6 +23,7 @@ const ContractUpdateForm = props => { current_focus, error_message_alignment, getCardLabels, + is_accumulator, onMouseLeave, removeToast, setCurrentFocus, @@ -63,7 +64,9 @@ const ContractUpdateForm = props => { const is_take_profit_valid = has_contract_update_take_profit ? contract_update_take_profit > 0 : isValid(stop_loss); const is_stop_loss_valid = has_contract_update_stop_loss ? contract_update_stop_loss > 0 : isValid(take_profit); - const is_valid_contract_update = is_valid_to_cancel ? false : !!(is_take_profit_valid || is_stop_loss_valid); + const is_valid_accu_contract_update = is_accumulator && !!is_take_profit_valid; + const is_valid_contract_update = + is_valid_accu_contract_update || (is_valid_to_cancel ? false : !!(is_take_profit_valid || is_stop_loss_valid)); const getStateToCompare = _state => { const props_to_pick = [ @@ -116,7 +119,7 @@ const ContractUpdateForm = props => { onChange={onChange} error_message_alignment={error_message_alignment || 'right'} value={contract_profit_or_loss.contract_update_take_profit} - is_disabled={!!is_valid_to_cancel} + is_disabled={!is_accumulator && !!is_valid_to_cancel} setCurrentFocus={setCurrentFocus} /> ); @@ -173,9 +176,13 @@ const ContractUpdateForm = props => {
-
+
{take_profit_input}
-
{stop_loss_input}
+ {!is_accumulator &&
{stop_loss_input}
}