diff --git a/packages/stores/types.ts b/packages/stores/types.ts index e2c9cbd281f5..6ca22b550474 100644 --- a/packages/stores/types.ts +++ b/packages/stores/types.ts @@ -171,6 +171,9 @@ export type TPortfolioPosition = { contract_info: ProposalOpenContract & Portfolio1 & { contract_update?: ContractUpdate; + validation_params?: { + [key: string]: { min: string; max: string }; + }; }; current_tick?: number; details?: string; diff --git a/packages/trader/src/AppV2/Components/RiskManagementItem/__tests__/risk-management-item.spec.tsx b/packages/trader/src/AppV2/Components/RiskManagementItem/__tests__/risk-management-item.spec.tsx index 04160a775226..d265945ea85c 100644 --- a/packages/trader/src/AppV2/Components/RiskManagementItem/__tests__/risk-management-item.spec.tsx +++ b/packages/trader/src/AppV2/Components/RiskManagementItem/__tests__/risk-management-item.spec.tsx @@ -81,10 +81,18 @@ describe('RiskManagementItem component', () => { currency: 'USD', contract_id: 1, is_valid_to_cancel: 1, + validation_params: { + stop_loss: { min: '1', max: '100' }, + take_profit: { min: '1', max: '100' }, + }, }, contract: { contract_info: { contract_id: 1, + validation_params: { + stop_loss: { min: '1', max: '100' }, + take_profit: { min: '1', max: '100' }, + }, }, contract_update_history: [], contract_update_take_profit: 100, diff --git a/packages/trader/src/AppV2/Components/RiskManagementItem/risk-management-item.tsx b/packages/trader/src/AppV2/Components/RiskManagementItem/risk-management-item.tsx index e21eae5b8ef9..ccc1cbed10f1 100644 --- a/packages/trader/src/AppV2/Components/RiskManagementItem/risk-management-item.tsx +++ b/packages/trader/src/AppV2/Components/RiskManagementItem/risk-management-item.tsx @@ -21,7 +21,7 @@ type RiskManagementItemProps = { modal_body_content: React.ReactNode; is_deal_cancellation?: boolean; value?: number | null; - type?: string; + type?: 'take_profit' | 'stop_loss'; }; const RiskManagementItem = observer( @@ -31,7 +31,7 @@ const RiskManagementItem = observer( const [isEnabled, setIsEnabled] = React.useState(false); const [stepperValue, setStepperValue] = React.useState(); const { contract_info, contract } = useContractDetails(); - const { contract_type, currency } = contract_info; + const { contract_type, currency, validation_params } = contract_info; const { validation_errors, updateLimitOrder, clearContractUpdateConfigValues } = contract; const is_valid_to_cancel = isValidToCancel(contract_info); const is_accumulator = isAccumulatorContract(contract_type); @@ -49,7 +49,7 @@ const RiskManagementItem = observer( const finalValue = Math.abs(value as number); const errorKey = `contract_update_${type}` as 'contract_update_stop_loss' | 'contract_update_take_profit'; - const errorMessage = validation_errors[errorKey]?.[0] ?? ''; + const validation_error_message = validation_errors[errorKey]?.[0] ?? ''; const messageForMultiplier = is_valid_to_cancel ? ( @@ -91,6 +91,7 @@ const RiskManagementItem = observer( }; const onSave = () => { + if (error_message) return; if (isEnabled) { contract.onChange?.({ name: `has_contract_update_${type}`, @@ -99,7 +100,29 @@ const RiskManagementItem = observer( setIsEnabled(false); } updateLimitOrder(); + setIsSheetOpen(false); }; + + const min_value = type && (validation_params?.[type]?.min ?? 0); + const max_value = type && (validation_params?.[type]?.max ?? 0); + + const error_message = (() => { + const field_label = type === 'take_profit' ? localize('take profit') : localize('stop loss'); + if (stepperValue && min_value && +stepperValue < +min_value) { + return localize('Please enter a {{field_label}} amount that’s at least {{min_value}}.', { + field_label, + min_value, + }); + } + if (stepperValue && max_value && +stepperValue > +max_value) { + return localize('Maximum {{field_label}} allowed is {{max_value}}.', { + field_label, + max_value, + }); + } + return validation_error_message; + })(); + return (
@@ -163,14 +186,14 @@ const RiskManagementItem = observer( className='text-field--custom' customType='commaRemoval' decimals={getDecimalPlaces(currency)} - message={errorMessage} + message={error_message} minusDisabled={Number(stepperValue) - 1 <= 0} name={type} noStatusIcon onChange={onChange} placeholder={localize('Amount')} regex={/[^0-9.,]/g} - status={errorMessage ? 'error' : 'neutral'} + status={error_message ? 'error' : 'neutral'} textAlignment='center' inputMode='decimal' unitLeft={getCurrencyDisplayCode(currency)} @@ -187,10 +210,7 @@ const RiskManagementItem = observer( )} , onAction: onSave, diff --git a/packages/trader/src/AppV2/Components/StopLoss/__tests__/stop-loss.spec.tsx b/packages/trader/src/AppV2/Components/StopLoss/__tests__/stop-loss.spec.tsx index b34af170922c..914087bfb45b 100644 --- a/packages/trader/src/AppV2/Components/StopLoss/__tests__/stop-loss.spec.tsx +++ b/packages/trader/src/AppV2/Components/StopLoss/__tests__/stop-loss.spec.tsx @@ -34,8 +34,9 @@ describe('StopLoss component', () => { jest.clearAllMocks(); }); - it('passes correct props to RiskManagementItem component when stop loss is visible', () => { + it('passes correct validation_params prop to RiskManagementItem component', () => { render(); + expect(screen.getByText('Risk Management Item Mock')).toBeInTheDocument(); expect(screen.getByText('Stop loss')).toBeInTheDocument(); expect( diff --git a/packages/trader/src/AppV2/Components/TakeProfit/__tests__/take-profit.spec.tsx b/packages/trader/src/AppV2/Components/TakeProfit/__tests__/take-profit.spec.tsx index 1fbd210da6f7..2c8de206721b 100644 --- a/packages/trader/src/AppV2/Components/TakeProfit/__tests__/take-profit.spec.tsx +++ b/packages/trader/src/AppV2/Components/TakeProfit/__tests__/take-profit.spec.tsx @@ -34,8 +34,9 @@ describe('TakeProfit component', () => { jest.clearAllMocks(); }); - it('passes correct props to RiskManagementItem component when take profit is visible', () => { + it('passes correct validation_params prop to RiskManagementItem component', () => { render(); + expect(screen.getByText('Risk Management Item Mock')).toBeInTheDocument(); expect(screen.getByText('Take profit')).toBeInTheDocument(); expect(