diff --git a/libs/deal-ticket/src/components/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket.tsx index 8daf81b18..eeffb3220 100644 --- a/libs/deal-ticket/src/components/deal-ticket.tsx +++ b/libs/deal-ticket/src/components/deal-ticket.tsx @@ -43,22 +43,22 @@ export const DealTicket = ({ const step = toDecimal(market.positionDecimalPlaces); const orderType = watch('type'); const orderTimeInForce = watch('timeInForce'); - const invalidText = useOrderValidation({ + const { message, isDisabled: disabled } = useOrderValidation({ step, market, orderType, orderTimeInForce, fieldErrors: errors, }); - const isDisabled = transactionStatus === 'pending' || Boolean(invalidText); + const isDisabled = transactionStatus === 'pending' || disabled; const onSubmit = useCallback( (order: Order) => { - if (!isDisabled && !invalidText) { + if (!isDisabled) { submit(order); } }, - [isDisabled, invalidText, submit] + [isDisabled, submit] ); return ( @@ -118,9 +118,12 @@ export const DealTicket = ({ > {transactionStatus === 'pending' ? t('Pending...') : t('Place order')} - {invalidText && ( - - {invalidText} + {message && ( + + {message} )} diff --git a/libs/orders/src/lib/order-hooks/use-order-validation.tsx b/libs/orders/src/lib/order-hooks/use-order-validation.tsx index c5436b960..09733ac14 100644 --- a/libs/orders/src/lib/order-hooks/use-order-validation.tsx +++ b/libs/orders/src/lib/order-hooks/use-order-validation.tsx @@ -28,33 +28,105 @@ export const useOrderValidation = ({ }: ValidationProps) => { const { keypair } = useVegaWallet(); - const invalidText = useMemo(() => { + const { message, isDisabled } = useMemo(() => { if (!keypair) { - return t('No public key selected'); + return { message: t('No public key selected'), isDisabled: true }; } if (keypair.tainted) { - return t('Selected public key has been tainted'); + return { + isDisabled: true, + message: t('Selected public key has been tainted'), + }; + } + + if ([MarketState.Cancelled, MarketState.Rejected].includes(market.state)) { + return { + isDisabled: true, + message: t( + `This market is ${market.state.toLowerCase()} and not accepting orders` + ), + }; + } + + if ( + [ + MarketState.Cancelled, + MarketState.Closed, + MarketState.Proposed, + MarketState.Settled, + ].includes(market.state) + ) { + return { + isDisabled: true, + message: t( + `This market is ${market.state.toLowerCase()} and only accepting liquidity orders` + ), + }; } if (market.state !== MarketState.Active) { if (market.state === MarketState.Suspended) { - return t('Market is currently suspended'); + if (market.tradingMode === MarketTradingMode.Continuous) { + if (orderType !== OrderType.Limit) { + return { + isDisabled: true, + message: t( + 'Only limit orders are permitted when market is in auction' + ), + }; + } + + if ( + [ + OrderTimeInForce.FOK, + OrderTimeInForce.IOC, + OrderTimeInForce.GFN, + ].includes(orderTimeInForce) + ) { + return { + isDisabled: true, + message: t( + 'Only GTT, GTC and GFA are permitted when market is in auction' + ), + }; + } + } + + return { + isDisabled: false, + message: t( + 'This market is currently suspended and only accepting liquidity orders' + ), + }; } if ( market.state === MarketState.Proposed || market.state === MarketState.Pending ) { - return t('Market is not active yet'); + return { + isDisabled: false, + message: t( + 'This market is not active yet and can accept only liquidity orders' + ), + }; } - return t('Market is no longer active'); + return { + isDisabled: true, + message: t('This market is no longer active.'), + }; } if (market.tradingMode !== MarketTradingMode.Continuous) { if (orderType !== OrderType.Limit) { - return t('Only limit orders are permitted when market is in auction'); + return { + isDisabled: true, + message: t( + 'Only limit orders are permitted when market is in auction' + ), + }; } if ( @@ -64,26 +136,41 @@ export const useOrderValidation = ({ OrderTimeInForce.GFN, ].includes(orderTimeInForce) ) { - return t( - 'Only GTT, GTC and GFA are permitted when market is in auction' - ); + return { + isDisabled: true, + message: t( + 'Only GTT, GTC and GFA are permitted when market is in auction' + ), + }; } } if (fieldErrors?.size?.type === 'required') { - return t('An amount needs to be provided'); + return { + isDisabled: true, + message: t('An amount needs to be provided'), + }; } if (fieldErrors?.size?.type === 'min') { - return t(`The amount cannot be lower than "${step}"`); + return { + isDisabled: true, + message: t(`The amount cannot be lower than "${step}"`), + }; } if (fieldErrors?.price?.type === 'required') { - return t('A price needs to be provided'); + return { + isDisabled: true, + message: t('A price needs to be provided'), + }; } if (fieldErrors?.price?.type === 'min') { - return t(`The price cannot be negative`); + return { + isDisabled: true, + message: t(`The price cannot be negative`), + }; } if ( @@ -91,14 +178,20 @@ export const useOrderValidation = ({ fieldErrors?.size?.message === ERROR_SIZE_DECIMAL ) { if (market.positionDecimalPlaces === 0) { - return t('No decimal amounts allowed for this order'); + return { + isDisabled: true, + message: t('No decimal amounts allowed for this order'), + }; } - return t( - `The amount field only takes up to ${market.positionDecimalPlaces} decimals` - ); + return { + isDisabled: true, + message: t( + `The amount field only takes up to ${market.positionDecimalPlaces} decimals` + ), + }; } - return ''; + return { isDisabled: false, message: '' }; }, [ keypair, step, @@ -110,5 +203,5 @@ export const useOrderValidation = ({ orderTimeInForce, ]); - return invalidText; + return { message, isDisabled }; };