Skip to content

Commit

Permalink
feat: add validation params
Browse files Browse the repository at this point in the history
  • Loading branch information
kate-deriv committed Jul 29, 2024
1 parent c108047 commit bba976e
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,79 @@ import { observer } from 'mobx-react';
import { ActionSheet, TextField, Text, ToggleSwitch, TextFieldWithSteppers } from '@deriv-com/quill-ui';
import { Localize, localize } from '@deriv/translations';
import { useTraderStore } from 'Stores/useTraderStores';
import { getCurrencyDisplayCode } from '@deriv/shared';
import { getCurrencyDisplayCode, getDecimalPlaces } from '@deriv/shared';
import Carousel from 'AppV2/Components/Carousel';
import TakeProfitHeader from './take-profit-header';

type TTakeProfitProps = {
is_minimized?: boolean;
};

//TODO: validation, max and min allow values
//TODO: enabling on click
//TODO: block "-" icon when value is 0
//TODO: add content for ACC

const TakeProfit = observer(({ is_minimized }: TTakeProfitProps) => {
const { currency, has_open_accu_contract, has_take_profit, take_profit, onChangeMultiple, onChange } =
useTraderStore();
const {
currency,
has_open_accu_contract,
has_take_profit,
take_profit,
onChangeMultiple,
onChange,
validation_params,
} = useTraderStore();

const [is_open, setIsOpen] = React.useState(false);
const [is_take_profit_enabled, setIsTakeProfitEnabled] = React.useState(has_take_profit);
const [updated_take_profit_value, setUpdatedTakeProfitValue] = React.useState<string | number | undefined>(
take_profit
);
const [error_message, setErrorMessage] = React.useState('');
const [error_message, setErrorMessage] = React.useState<React.ReactNode>();

const input_ref = React.useRef<HTMLInputElement>(null);
const focus_timeout = React.useRef<ReturnType<typeof setTimeout>>();

const min_take_profit = validation_params?.take_profit?.min;
const max_take_profit = validation_params?.take_profit?.max;
const decimal = getDecimalPlaces(currency);

const getInputMessage = () =>
is_take_profit_enabled
? error_message || (
<Localize
i18n_default_text='Acceptable range: {{min_take_profit}} to {{max_take_profit}} {{currency}}'
values={{ currency, min_take_profit, max_take_profit }}
/>
)
: '';

const isTakeProfitOutOfRange = (value = updated_take_profit_value) => {
if (!value) {
setErrorMessage(<Localize i18n_default_text='Please enter a take profit amount.' />);
return true;
}
if (Number(value) < Number(min_take_profit) || Number(value) > Number(max_take_profit)) {
setErrorMessage(
<Localize
i18n_default_text='Acceptable range: {{min_take_profit}} to {{max_take_profit}} {{currency}}'
values={{ currency, min_take_profit, max_take_profit }}
/>
);
return true;
}
setErrorMessage('');
return false;
};

const onToggleSwitch = (is_enabled: boolean) => {
setIsTakeProfitEnabled(is_enabled);

if (is_enabled) {
clearTimeout(focus_timeout.current);
focus_timeout.current = setTimeout(() => {
input_ref.current?.click();
input_ref.current?.focus();
input_ref.current?.setSelectionRange(0, 9999);
}, 150);
} else {
input_ref.current?.blur();
Expand All @@ -45,15 +85,19 @@ const TakeProfit = observer(({ is_minimized }: TTakeProfitProps) => {

const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
let { value } = e.target;
if (Number(value) <= 0) value = '0';
value = value.trim().replace(',', '.');
if (value !== '' && Number(value) <= 0) value = '0';
setUpdatedTakeProfitValue(value);
isTakeProfitOutOfRange(value);
};

const onInputClick = () => {
//TODO
};

const onSave = () => {
if (isTakeProfitOutOfRange()) return;

onChangeMultiple({
has_take_profit: is_take_profit_enabled,
...(is_take_profit_enabled ? { has_cancellation: false } : {}),
Expand Down Expand Up @@ -88,7 +132,7 @@ const TakeProfit = observer(({ is_minimized }: TTakeProfitProps) => {
<TextFieldWithSteppers
allowDecimals
disabled={!is_take_profit_enabled}
message={error_message}
message={getInputMessage()}
name='take_profit'
onChange={onInputChange}
onClick={onInputClick}
Expand All @@ -99,7 +143,7 @@ const TakeProfit = observer(({ is_minimized }: TTakeProfitProps) => {
unitLeft={currency}
variant='fill'
value={updated_take_profit_value}
// decimals={0}
decimals={decimal}
/>
</ActionSheet.Content>
<ActionSheet.Footer
Expand All @@ -108,6 +152,7 @@ const TakeProfit = observer(({ is_minimized }: TTakeProfitProps) => {
content: <Localize i18n_default_text='Save' />,
onAction: onSave,
}}
shouldCloseOnPrimaryButtonClick={false}
/>
</React.Fragment>
),
Expand Down Expand Up @@ -141,7 +186,7 @@ const TakeProfit = observer(({ is_minimized }: TTakeProfitProps) => {
label={
<Localize i18n_default_text='Take profit' key={`take-profit${is_minimized ? '-minimized' : ''}`} />
}
value={take_profit ? `${take_profit} ${getCurrencyDisplayCode(currency)}` : '-'}
value={has_take_profit && take_profit ? `${take_profit} ${getCurrencyDisplayCode(currency)}` : '-'}
className={clsx('trade-params__option', is_minimized && 'trade-params__option--minimized')}
disabled={has_open_accu_contract}
onClick={() => setIsOpen(true)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const default_mocked_props: React.ComponentProps<typeof PurchaseButton> = {
profit: '',
returns: '',
spot: 0,
validation_params: undefined,
},
is_accumulator: false,
is_disabled: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const default_mocked_props: React.ComponentProps<typeof PurchaseFieldset> = {
profit: '',
returns: '',
spot: 0,
validation_params: undefined,
},
is_accumulator: false,
is_disabled: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const mock_proposal_info: TProposalTypeInfo = {
returns: '',
stake: '',
spot: 0,
validation_params: undefined,
};

const default_mock_store = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const default_mock_props: React.ComponentProps<typeof ContractInfo> = {
profit: '',
returns: '',
spot: 0,
validation_params: undefined,
},
type: 'test_contract_type',
};
Expand Down
24 changes: 22 additions & 2 deletions packages/trader/src/Stores/Modules/Trading/Helpers/proposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,31 @@ export const getProposalErrorField = (response: PriceProposalResponse) => {
return el_error && isVisible(el_error) ? error_id : null;
};

type TValidationParams =
| {
validation_params?: {
max_payout?: string;
max_ticks?: number;
stake?: {
max: string;
min: string;
};
take_profit: {
max: string;
min: string;
};
};
}
| undefined;

type NewProposal = Proposal & TValidationParams;

export const getProposalInfo = (
store: TTradeStore,
response: PriceProposalResponse & TError,
obj_prev_contract_basis: TObjContractBasis
) => {
const proposal = response.proposal || ({} as Proposal);
const proposal = (response.proposal as NewProposal) || ({} as NewProposal);
const profit = (proposal.payout || 0) - (proposal.ask_price || 0);
const returns = (profit * 100) / (proposal.ask_price || 1);
const stake = proposal.display_value;
Expand All @@ -72,7 +91,7 @@ export const getProposalInfo = (

const is_stake = contract_basis?.value === 'stake';

const price = is_stake ? stake : (proposal[contract_basis?.value as keyof Proposal] as string | number);
const price = is_stake ? stake : (proposal[contract_basis?.value as keyof NewProposal] as string | number);

const obj_contract_basis = {
text: contract_basis?.text || '',
Expand Down Expand Up @@ -103,6 +122,7 @@ export const getProposalInfo = (
returns: `${returns.toFixed(2)}%`,
stake,
spot: proposal.spot,
validation_params: proposal?.validation_params,
...accumulators_details,
};
};
Expand Down
15 changes: 15 additions & 0 deletions packages/trader/src/Stores/Modules/Trading/trade-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ type TStakeBoundary = Record<
>;
type TTicksHistoryResponse = TicksHistoryResponse | TicksStreamResponse;
type TBarriersData = Record<string, never> | { barrier: string; barrier_choices: string[] };
type TValidationParams = ReturnType<typeof getProposalInfo>['validation_params'];

const store_name = 'trade_store';
const g_subscribers_map: Partial<Record<string, ReturnType<typeof WS.subscribeTicksHistory>>> = {}; // blame amin.m
Expand Down Expand Up @@ -245,6 +246,7 @@ export default class TradeStore extends BaseStore {
*
*/
market_close_times: string[] = [];
validation_params?: TValidationParams | Record<string, never> = {};

// Last Digit
digit_stats: number[] = [];
Expand Down Expand Up @@ -420,6 +422,7 @@ export default class TradeStore extends BaseStore {
market_open_times: observable,
maximum_payout: observable,
maximum_ticks: observable,
validation_params: observable,
multiplier_range_list: observable,
multiplier: observable,
non_available_contract_types_list: observable,
Expand Down Expand Up @@ -1373,6 +1376,16 @@ export default class TradeStore extends BaseStore {
}
this.stop_out = limit_order?.stop_out?.order_amount;
}

if (this.is_turbos && (this.proposal_info?.TURBOSSHORT || this.proposal_info?.TURBOSLONG)) {
if (this.proposal_info?.TURBOSSHORT) {
this.validation_params = this.proposal_info.TURBOSSHORT.validation_params;
}
if (this.proposal_info?.TURBOSLONG) {
this.validation_params = this.proposal_info.TURBOSLONG.validation_params;
}
}

if (this.is_accumulator && this.proposal_info?.ACCU) {
const {
barrier_spot_distance,
Expand All @@ -1384,12 +1397,14 @@ export default class TradeStore extends BaseStore {
high_barrier,
low_barrier,
spot_time,
validation_params,
} = this.proposal_info.ACCU;
this.ticks_history_stats = getUpdatedTicksHistoryStats({
previous_ticks_history_stats: this.ticks_history_stats,
new_ticks_history_stats: ticks_stayed_in,
last_tick_epoch,
});
this.validation_params = validation_params;
this.maximum_ticks = maximum_ticks;
this.maximum_payout = maximum_payout;
this.tick_size_barrier_percentage = tick_size_barrier_percentage;
Expand Down

0 comments on commit bba976e

Please sign in to comment.