From bf07dac445ea2950e17d4dcb8d57166eb40e77f6 Mon Sep 17 00:00:00 2001 From: botond <105208209+notbot00@users.noreply.github.com> Date: Tue, 31 May 2022 23:20:01 +0100 Subject: [PATCH 1/5] feat(#372): fractional orders (#486) * feat: add positionDecimalPlaces prop to market query and regenerate types * feat: add stepper to order amount input * feat: convert fractions back to integers when submitting the order * refactor: move order transformations into hooks * fix: formatting * fix: simplify toDecimal calculation * fix: remove redundant function for size calculation * fix: add new prop to e2e test mock generator * feat: add tests for order validation * fix: lint * chore: add validation to the simple trading app order form * fix: lint --- .../deal-ticket/deal-ticket-steps.tsx | 178 +++++++++------- .../mocks/generate-deal-ticket-query.ts | 1 + .../src/__generated__/DealTicketQuery.ts | 6 + .../src/components/deal-ticket-amount.tsx | 33 +++ .../deal-ticket-container.tsx | 3 +- .../deal-ticket-limit-amount.tsx} | 37 ++-- .../{ => components}/deal-ticket-manager.tsx | 4 +- .../deal-ticket-market-amount.tsx} | 29 +-- .../src/{ => components}/deal-ticket.spec.tsx | 43 ++-- .../src/components/deal-ticket.tsx | 126 +++++++++++ .../src/{ => components}/expiry-selector.tsx | 7 +- .../src/{ => components}/order-dialog.tsx | 2 +- .../src/{ => components}/side-selector.tsx | 7 +- .../time-in-force-selector.tsx | 16 +- .../src/{ => components}/type-selector.tsx | 15 +- libs/deal-ticket/src/deal-ticket-limit.tsx | 57 ----- libs/deal-ticket/src/deal-ticket-market.tsx | 49 ----- libs/deal-ticket/src/deal-ticket.tsx | 67 ------ .../src/{ => hooks}/use-order-submit.spec.tsx | 46 +++- .../src/{ => hooks}/use-order-submit.ts | 14 +- .../src/hooks/use-order-validation.spec.tsx | 196 ++++++++++++++++++ .../src/hooks/use-order-validation.tsx | 114 ++++++++++ libs/deal-ticket/src/index.ts | 27 +-- libs/deal-ticket/src/submit-button.tsx | 89 -------- libs/deal-ticket/src/use-order-state.ts | 79 ------- .../src/utils/get-default-order.ts | 28 +++ libs/deal-ticket/src/utils/validate-size.ts | 12 ++ .../__generated__/MarketList.ts | 24 +-- libs/react-helpers/src/lib/format/number.ts | 4 + 29 files changed, 765 insertions(+), 548 deletions(-) create mode 100644 libs/deal-ticket/src/components/deal-ticket-amount.tsx rename libs/deal-ticket/src/{ => components}/deal-ticket-container.tsx (95%) rename libs/deal-ticket/src/{deal-ticket-limit-form.tsx => components/deal-ticket-limit-amount.tsx} (51%) rename libs/deal-ticket/src/{ => components}/deal-ticket-manager.tsx (93%) rename libs/deal-ticket/src/{deal-ticket-market-form.tsx => components/deal-ticket-market-amount.tsx} (55%) rename libs/deal-ticket/src/{ => components}/deal-ticket.spec.tsx (80%) create mode 100644 libs/deal-ticket/src/components/deal-ticket.tsx rename libs/deal-ticket/src/{ => components}/expiry-selector.tsx (76%) rename libs/deal-ticket/src/{ => components}/order-dialog.tsx (97%) rename libs/deal-ticket/src/{ => components}/side-selector.tsx (77%) rename libs/deal-ticket/src/{ => components}/time-in-force-selector.tsx (76%) rename libs/deal-ticket/src/{ => components}/type-selector.tsx (63%) delete mode 100644 libs/deal-ticket/src/deal-ticket-limit.tsx delete mode 100644 libs/deal-ticket/src/deal-ticket-market.tsx delete mode 100644 libs/deal-ticket/src/deal-ticket.tsx rename libs/deal-ticket/src/{ => hooks}/use-order-submit.spec.tsx (79%) rename libs/deal-ticket/src/{ => hooks}/use-order-submit.ts (90%) create mode 100644 libs/deal-ticket/src/hooks/use-order-validation.spec.tsx create mode 100644 libs/deal-ticket/src/hooks/use-order-validation.tsx delete mode 100644 libs/deal-ticket/src/submit-button.tsx delete mode 100644 libs/deal-ticket/src/use-order-state.ts create mode 100644 libs/deal-ticket/src/utils/get-default-order.ts create mode 100644 libs/deal-ticket/src/utils/validate-size.ts diff --git a/apps/simple-trading-app/src/app/components/deal-ticket/deal-ticket-steps.tsx b/apps/simple-trading-app/src/app/components/deal-ticket/deal-ticket-steps.tsx index a68270fc2..1f102cabe 100644 --- a/apps/simple-trading-app/src/app/components/deal-ticket/deal-ticket-steps.tsx +++ b/apps/simple-trading-app/src/app/components/deal-ticket/deal-ticket-steps.tsx @@ -1,40 +1,54 @@ import * as React from 'react'; -import type { FormEvent } from 'react'; +import { useForm, Controller } from 'react-hook-form'; import Box from '@mui/material/Box'; import { Stepper } from '../stepper'; -import type { Order, DealTicketQuery_market } from '@vegaprotocol/deal-ticket'; +import type { DealTicketQuery_market, Order } from '@vegaprotocol/deal-ticket'; +import { Button, InputError } from '@vegaprotocol/ui-toolkit'; import { ExpirySelector, SideSelector, - SubmitButton, TimeInForceSelector, TypeSelector, - useOrderState, + getDefaultOrder, + useOrderValidation, useOrderSubmit, - DealTicketLimitForm, - DealTicketMarketForm, + DealTicketAmount, } from '@vegaprotocol/deal-ticket'; import { - OrderSide, OrderTimeInForce, OrderType, VegaTxStatus, } from '@vegaprotocol/wallet'; -import { addDecimal } from '@vegaprotocol/react-helpers'; +import { t, addDecimal, toDecimal } from '@vegaprotocol/react-helpers'; interface DealTicketMarketProps { market: DealTicketQuery_market; } -const DEFAULT_ORDER: Order = { - type: OrderType.Market, - side: OrderSide.Buy, - size: '1', - timeInForce: OrderTimeInForce.IOC, -}; - export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { - const [order, updateOrder] = useOrderState(DEFAULT_ORDER); + const { + register, + control, + handleSubmit, + watch, + formState: { errors }, + } = useForm({ + mode: 'onChange', + defaultValues: getDefaultOrder(market), + }); + + const step = toDecimal(market.positionDecimalPlaces); + const orderType = watch('type'); + const orderTimeInForce = watch('timeInForce'); + + const invalidText = useOrderValidation({ + step, + market, + orderType, + orderTimeInForce, + fieldErrors: errors, + }); + const { submit, transaction } = useOrderSubmit(market); const transactionStatus = @@ -43,39 +57,14 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { ? 'pending' : 'default'; - let ticket = null; - - if (order.type === OrderType.Market) { - ticket = ( - updateOrder({ size })} - price={ - market.depth.lastTrade - ? addDecimal(market.depth.lastTrade.price, market.decimalPlaces) - : undefined - } - quoteName={market.tradableInstrument.instrument.product.quoteName} - /> - ); - } else if (order.type === OrderType.Limit) { - ticket = ( - updateOrder({ size })} - onPriceChange={(price) => updateOrder({ price })} - /> - ); - } else { - throw new Error('Invalid ticket type'); - } - - const handleSubmit = (e: FormEvent): Promise => { - e.preventDefault(); - return submit(order); - }; + const onSubmit = React.useCallback( + (order: Order) => { + if (transactionStatus !== 'pending') { + submit(order); + } + }, + [transactionStatus, submit] + ); const steps = [ { @@ -87,9 +76,12 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { label: 'Select Order Type', description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, component: ( - updateOrder({ type })} + ( + + )} /> ), }, @@ -97,9 +89,12 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { label: 'Select Market Position', description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, component: ( - updateOrder({ side })} + ( + + )} /> ), }, @@ -107,27 +102,49 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { label: 'Select Order Size', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - component: ticket, + component: ( + + ), }, { label: 'Select Time In Force', description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, component: ( <> - updateOrder({ timeInForce })} + ( + + )} /> - {order.timeInForce === OrderTimeInForce.GTT && ( - { - if (date) { - updateOrder({ expiration: date }); - } - }} - /> - )} + {orderType === OrderType.Limit && + orderTimeInForce === OrderTimeInForce.GTT && ( + ( + + )} + /> + )} ), }, @@ -136,11 +153,22 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { description: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, component: ( - + {invalidText && ( + + {invalidText} + + )} + ), disabled: true, @@ -148,7 +176,7 @@ export const DealTicketSteps = ({ market }: DealTicketMarketProps) => { ]; return ( -
+ ); diff --git a/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts b/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts index 5ffcbae8e..961d17d0f 100644 --- a/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts +++ b/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts @@ -10,6 +10,7 @@ export const generateDealTicketQuery = ( market: { id: 'market-id', decimalPlaces: 2, + positionDecimalPlaces: 1, state: MarketState.Active, tradingMode: MarketTradingMode.Continuous, tradableInstrument: { diff --git a/libs/deal-ticket/src/__generated__/DealTicketQuery.ts b/libs/deal-ticket/src/__generated__/DealTicketQuery.ts index 87f2d3922..efb10e5c5 100644 --- a/libs/deal-ticket/src/__generated__/DealTicketQuery.ts +++ b/libs/deal-ticket/src/__generated__/DealTicketQuery.ts @@ -72,6 +72,12 @@ export interface DealTicketQuery_market { * GBX (pence) 1 4 GBP 0.000001 ( 0.0001p) */ decimalPlaces: number; + /** + * positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64). + * i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes. + * 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market. + */ + positionDecimalPlaces: number; /** * Current state of the market */ diff --git a/libs/deal-ticket/src/components/deal-ticket-amount.tsx b/libs/deal-ticket/src/components/deal-ticket-amount.tsx new file mode 100644 index 000000000..bb4350421 --- /dev/null +++ b/libs/deal-ticket/src/components/deal-ticket-amount.tsx @@ -0,0 +1,33 @@ +import type { UseFormRegister } from 'react-hook-form'; +import { OrderType } from '@vegaprotocol/wallet'; +import type { Order } from '../utils/get-default-order'; +import { DealTicketMarketAmount } from './deal-ticket-market-amount'; +import { DealTicketLimitAmount } from './deal-ticket-limit-amount'; + +export interface DealTicketAmountProps { + orderType: OrderType; + step: number; + register: UseFormRegister; + quoteName: string; + price?: string; +} + +const getAmountComponent = (type: OrderType) => { + switch (type) { + case OrderType.Market: + return DealTicketMarketAmount; + case OrderType.Limit: + return DealTicketLimitAmount; + default: { + throw new Error('Invalid ticket type'); + } + } +}; + +export const DealTicketAmount = ({ + orderType, + ...props +}: DealTicketAmountProps) => { + const AmountComponent = getAmountComponent(orderType); + return ; +}; diff --git a/libs/deal-ticket/src/deal-ticket-container.tsx b/libs/deal-ticket/src/components/deal-ticket-container.tsx similarity index 95% rename from libs/deal-ticket/src/deal-ticket-container.tsx rename to libs/deal-ticket/src/components/deal-ticket-container.tsx index f6575e476..4f3c0f6e1 100644 --- a/libs/deal-ticket/src/deal-ticket-container.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-container.tsx @@ -4,7 +4,7 @@ import { DealTicketManager } from './deal-ticket-manager'; import type { DealTicketQuery, DealTicketQuery_market, -} from './__generated__/DealTicketQuery'; +} from '../__generated__/DealTicketQuery'; import { t } from '@vegaprotocol/react-helpers'; const DEAL_TICKET_QUERY = gql` @@ -12,6 +12,7 @@ const DEAL_TICKET_QUERY = gql` market(id: $marketId) { id decimalPlaces + positionDecimalPlaces state tradingMode tradableInstrument { diff --git a/libs/deal-ticket/src/deal-ticket-limit-form.tsx b/libs/deal-ticket/src/components/deal-ticket-limit-amount.tsx similarity index 51% rename from libs/deal-ticket/src/deal-ticket-limit-form.tsx rename to libs/deal-ticket/src/components/deal-ticket-limit-amount.tsx index 52a1ee3c1..98c262246 100644 --- a/libs/deal-ticket/src/deal-ticket-limit-form.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-limit-amount.tsx @@ -1,30 +1,32 @@ import { FormGroup, Input } from '@vegaprotocol/ui-toolkit'; +import { validateSize } from '../utils/validate-size'; +import type { DealTicketAmountProps } from './deal-ticket-amount'; -export interface DealTicketLimitFormProps { - quoteName: string; - price?: string; - size: string; - onSizeChange: (size: string) => void; - onPriceChange: (price: string) => void; -} +export type DealTicketLimitAmountProps = Omit< + DealTicketAmountProps, + 'orderType' +>; -export const DealTicketLimitForm = ({ - size, - price, - onSizeChange, - onPriceChange, +export const DealTicketLimitAmount = ({ + register, + step, quoteName, -}: DealTicketLimitFormProps) => { +}: DealTicketLimitAmountProps) => { return (
onSizeChange(e.target.value)} className="w-full" type="number" + step={step} + min={step} data-testid="order-size" + {...register('size', { + required: true, + min: step, + validate: validateSize(step), + })} />
@@ -32,11 +34,12 @@ export const DealTicketLimitForm = ({
onPriceChange(e.target.value)} className="w-full" type="number" + step={step} + defaultValue={0} data-testid="order-price" + {...register('price', { required: true, min: 0 })} />
diff --git a/libs/deal-ticket/src/deal-ticket-manager.tsx b/libs/deal-ticket/src/components/deal-ticket-manager.tsx similarity index 93% rename from libs/deal-ticket/src/deal-ticket-manager.tsx rename to libs/deal-ticket/src/components/deal-ticket-manager.tsx index f0d46eec8..9796acd54 100644 --- a/libs/deal-ticket/src/deal-ticket-manager.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-manager.tsx @@ -4,9 +4,9 @@ import { Dialog, Intent } from '@vegaprotocol/ui-toolkit'; import { OrderStatus } from '@vegaprotocol/types'; import { VegaTxStatus } from '@vegaprotocol/wallet'; import { DealTicket } from './deal-ticket'; -import { useOrderSubmit } from './use-order-submit'; import { OrderDialog } from './order-dialog'; -import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; +import { useOrderSubmit } from '../hooks/use-order-submit'; +import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; export interface DealTicketManagerProps { market: DealTicketQuery_market; diff --git a/libs/deal-ticket/src/deal-ticket-market-form.tsx b/libs/deal-ticket/src/components/deal-ticket-market-amount.tsx similarity index 55% rename from libs/deal-ticket/src/deal-ticket-market-form.tsx rename to libs/deal-ticket/src/components/deal-ticket-market-amount.tsx index 1e06a1903..763dc6d03 100644 --- a/libs/deal-ticket/src/deal-ticket-market-form.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-market-amount.tsx @@ -1,28 +1,33 @@ import { FormGroup, Input } from '@vegaprotocol/ui-toolkit'; +import { validateSize } from '../utils/validate-size'; +import type { DealTicketAmountProps } from './deal-ticket-amount'; -export interface DealTicketMarketFormProps { - quoteName?: string; - price?: string; - size: string; - onSizeChange: (size: string) => void; -} +export type DealTicketMarketAmountProps = Omit< + DealTicketAmountProps, + 'orderType' +>; -export const DealTicketMarketForm = ({ - size, - onSizeChange, +export const DealTicketMarketAmount = ({ + register, price, + step, quoteName, -}: DealTicketMarketFormProps) => { +}: DealTicketMarketAmountProps) => { return (
onSizeChange(e.target.value)} className="w-full" type="number" + step={step} + min={step} data-testid="order-size" + {...register('size', { + required: true, + min: step, + validate: validateSize(step), + })} />
diff --git a/libs/deal-ticket/src/deal-ticket.spec.tsx b/libs/deal-ticket/src/components/deal-ticket.spec.tsx similarity index 80% rename from libs/deal-ticket/src/deal-ticket.spec.tsx rename to libs/deal-ticket/src/components/deal-ticket.spec.tsx index e49a50383..4691d5adf 100644 --- a/libs/deal-ticket/src/deal-ticket.spec.tsx +++ b/libs/deal-ticket/src/components/deal-ticket.spec.tsx @@ -4,22 +4,17 @@ import { OrderType, } from '@vegaprotocol/wallet'; import { addDecimal } from '@vegaprotocol/react-helpers'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, act } from '@testing-library/react'; import { DealTicket } from './deal-ticket'; -import type { Order } from './use-order-state'; -import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; +import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; +import type { Order } from '../utils/get-default-order'; import { MarketState, MarketTradingMode } from '@vegaprotocol/types'; -const order: Order = { - type: OrderType.Market, - size: '100', - timeInForce: OrderTimeInForce.FOK, - side: null, -}; const market: DealTicketQuery_market = { __typename: 'Market', id: 'market-id', decimalPlaces: 2, + positionDecimalPlaces: 1, tradingMode: MarketTradingMode.Continuous, state: MarketState.Active, tradableInstrument: { @@ -43,7 +38,7 @@ const market: DealTicketQuery_market = { const submit = jest.fn(); const transactionStatus = 'default'; -function generateJsx() { +function generateJsx(order?: Order) { return ( // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -57,21 +52,23 @@ function generateJsx() { ); } -it('Deal ticket defaults', () => { +it('Displays ticket defaults', () => { render(generateJsx()); // Assert defaults are used expect( - screen.getByTestId(`order-type-${order.type}-selected`) + screen.getByTestId(`order-type-${OrderType.Market}-selected`) ).toBeInTheDocument(); expect( screen.queryByTestId('order-side-SIDE_BUY-selected') - ).not.toBeInTheDocument(); + ).toBeInTheDocument(); expect( screen.queryByTestId('order-side-SIDE_SELL-selected') ).not.toBeInTheDocument(); - expect(screen.getByTestId('order-size')).toHaveDisplayValue(order.size); - expect(screen.getByTestId('order-tif')).toHaveValue(order.timeInForce); + expect(screen.getByTestId('order-size')).toHaveDisplayValue( + String(1 / Math.pow(10, market.positionDecimalPlaces)) + ); + expect(screen.getByTestId('order-tif')).toHaveValue(OrderTimeInForce.IOC); // Assert last price is shown expect(screen.getByTestId('last-price')).toHaveTextContent( @@ -82,18 +79,18 @@ it('Deal ticket defaults', () => { ); }); -it('Can edit deal ticket', () => { +it('Can edit deal ticket', async () => { render(generateJsx()); - // Asssert changing values - fireEvent.click(screen.getByTestId('order-side-SIDE_BUY')); - expect( - screen.getByTestId('order-side-SIDE_BUY-selected') - ).toBeInTheDocument(); + // BUY is selected by default + screen.getByTestId('order-side-SIDE_BUY-selected'); - fireEvent.change(screen.getByTestId('order-size'), { - target: { value: '200' }, + await act(async () => { + fireEvent.change(screen.getByTestId('order-size'), { + target: { value: '200' }, + }); }); + expect(screen.getByTestId('order-size')).toHaveDisplayValue('200'); fireEvent.change(screen.getByTestId('order-tif'), { diff --git a/libs/deal-ticket/src/components/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket.tsx new file mode 100644 index 000000000..df5d2f4c7 --- /dev/null +++ b/libs/deal-ticket/src/components/deal-ticket.tsx @@ -0,0 +1,126 @@ +import { useCallback } from 'react'; +import { useForm, Controller } from 'react-hook-form'; +import { OrderType, OrderTimeInForce } from '@vegaprotocol/wallet'; +import { t, addDecimal, toDecimal } from '@vegaprotocol/react-helpers'; +import { Button, InputError } from '@vegaprotocol/ui-toolkit'; +import { TypeSelector } from './type-selector'; +import { SideSelector } from './side-selector'; +import { DealTicketAmount } from './deal-ticket-amount'; +import { TimeInForceSelector } from './time-in-force-selector'; +import { ExpirySelector } from './expiry-selector'; +import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; +import type { Order } from '../utils/get-default-order'; +import { getDefaultOrder } from '../utils/get-default-order'; +import { useOrderValidation } from '../hooks/use-order-validation'; + +export type TransactionStatus = 'default' | 'pending'; + +export interface DealTicketProps { + market: DealTicketQuery_market; + submit: (order: Order) => void; + transactionStatus: TransactionStatus; + defaultOrder?: Order; +} + +export const DealTicket = ({ + market, + submit, + transactionStatus, +}: DealTicketProps) => { + const { + register, + control, + handleSubmit, + watch, + formState: { errors }, + } = useForm({ + mode: 'onChange', + defaultValues: getDefaultOrder(market), + }); + + const step = toDecimal(market.positionDecimalPlaces); + const orderType = watch('type'); + const orderTimeInForce = watch('timeInForce'); + const invalidText = useOrderValidation({ + step, + market, + orderType, + orderTimeInForce, + fieldErrors: errors, + }); + const isDisabled = transactionStatus === 'pending' || Boolean(invalidText); + + const onSubmit = useCallback( + (order: Order) => { + if (!isDisabled && !invalidText) { + submit(order); + } + }, + [isDisabled, invalidText, submit] + ); + + return ( +
+ ( + + )} + /> + ( + + )} + /> + + ( + + )} + /> + {orderType === OrderType.Limit && + orderTimeInForce === OrderTimeInForce.GTT && ( + ( + + )} + /> + )} + + {invalidText && ( + + {invalidText} + + )} + + ); +}; diff --git a/libs/deal-ticket/src/expiry-selector.tsx b/libs/deal-ticket/src/components/expiry-selector.tsx similarity index 76% rename from libs/deal-ticket/src/expiry-selector.tsx rename to libs/deal-ticket/src/components/expiry-selector.tsx index dd64fa8a1..1015c3507 100644 --- a/libs/deal-ticket/src/expiry-selector.tsx +++ b/libs/deal-ticket/src/components/expiry-selector.tsx @@ -1,14 +1,13 @@ import { FormGroup, Input } from '@vegaprotocol/ui-toolkit'; -import type { Order } from './use-order-state'; import { formatForInput } from '@vegaprotocol/react-helpers'; interface ExpirySelectorProps { - order: Order; + value?: Date; onSelect: (expiration: Date | null) => void; } -export const ExpirySelector = ({ order, onSelect }: ExpirySelectorProps) => { - const date = order.expiration ? new Date(order.expiration) : new Date(); +export const ExpirySelector = ({ value, onSelect }: ExpirySelectorProps) => { + const date = value ? new Date(value) : new Date(); const dateFormatted = formatForInput(date); const minDate = formatForInput(date); return ( diff --git a/libs/deal-ticket/src/order-dialog.tsx b/libs/deal-ticket/src/components/order-dialog.tsx similarity index 97% rename from libs/deal-ticket/src/order-dialog.tsx rename to libs/deal-ticket/src/components/order-dialog.tsx index d3bbe4926..17498ec8f 100644 --- a/libs/deal-ticket/src/order-dialog.tsx +++ b/libs/deal-ticket/src/components/order-dialog.tsx @@ -1,6 +1,6 @@ import { Icon, Loader } from '@vegaprotocol/ui-toolkit'; import type { ReactNode } from 'react'; -import type { OrderEvent_busEvents_event_Order } from './__generated__/OrderEvent'; +import type { OrderEvent_busEvents_event_Order } from '../__generated__/OrderEvent'; import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; import type { VegaTxState } from '@vegaprotocol/wallet'; import { VegaTxStatus } from '@vegaprotocol/wallet'; diff --git a/libs/deal-ticket/src/side-selector.tsx b/libs/deal-ticket/src/components/side-selector.tsx similarity index 77% rename from libs/deal-ticket/src/side-selector.tsx rename to libs/deal-ticket/src/components/side-selector.tsx index 764d18995..ea3999cf3 100644 --- a/libs/deal-ticket/src/side-selector.tsx +++ b/libs/deal-ticket/src/components/side-selector.tsx @@ -1,14 +1,13 @@ import { FormGroup } from '@vegaprotocol/ui-toolkit'; import { OrderSide } from '@vegaprotocol/wallet'; import { Toggle } from '@vegaprotocol/ui-toolkit'; -import type { Order } from './use-order-state'; interface SideSelectorProps { - order: Order; + value: OrderSide; onSelect: (side: OrderSide) => void; } -export const SideSelector = ({ order, onSelect }: SideSelectorProps) => { +export const SideSelector = ({ value, onSelect }: SideSelectorProps) => { const toggles = Object.entries(OrderSide).map(([label, value]) => ({ label, value, @@ -19,7 +18,7 @@ export const SideSelector = ({ order, onSelect }: SideSelectorProps) => { onSelect(e.target.value as OrderSide)} /> diff --git a/libs/deal-ticket/src/time-in-force-selector.tsx b/libs/deal-ticket/src/components/time-in-force-selector.tsx similarity index 76% rename from libs/deal-ticket/src/time-in-force-selector.tsx rename to libs/deal-ticket/src/components/time-in-force-selector.tsx index a9fe72786..6af307daa 100644 --- a/libs/deal-ticket/src/time-in-force-selector.tsx +++ b/libs/deal-ticket/src/components/time-in-force-selector.tsx @@ -1,28 +1,30 @@ import { FormGroup, Select } from '@vegaprotocol/ui-toolkit'; import { OrderTimeInForce, OrderType } from '@vegaprotocol/wallet'; -import type { Order } from './use-order-state'; interface TimeInForceSelectorProps { - order: Order; + value: OrderTimeInForce; + orderType: OrderType; onSelect: (tif: OrderTimeInForce) => void; } export const TimeInForceSelector = ({ - order, + value, + orderType, onSelect, }: TimeInForceSelectorProps) => { const options = - order.type === OrderType.Limit + orderType === OrderType.Limit ? Object.entries(OrderTimeInForce) : Object.entries(OrderTimeInForce).filter( - ([_, value]) => - value === OrderTimeInForce.FOK || value === OrderTimeInForce.IOC + ([_, timeInForce]) => + timeInForce === OrderTimeInForce.FOK || + timeInForce === OrderTimeInForce.IOC ); return (