feat(#1552): order edit dialog supports size editing (#2053)

* feat(#1552): order edit dialog supports size editing

* feat(#1552): calculate size delta correctly

* feat(#1552): be able to edit order size

* feat(#1552): make sizeediting optional
This commit is contained in:
m.ray 2022-11-15 06:06:36 -05:00 committed by GitHub
parent 7ab1778830
commit 2eae066ea7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 27 deletions

View File

@ -4,6 +4,7 @@ import {
toDecimal, toDecimal,
Size, Size,
getDateTimeFormat, getDateTimeFormat,
addDecimal,
} from '@vegaprotocol/react-helpers'; } from '@vegaprotocol/react-helpers';
import { Schema } from '@vegaprotocol/types'; import { Schema } from '@vegaprotocol/types';
import { import {
@ -26,6 +27,7 @@ interface OrderEditDialogProps {
interface FormFields { interface FormFields {
limitPrice: string; limitPrice: string;
size: string;
} }
export const OrderEditDialog = ({ export const OrderEditDialog = ({
@ -41,15 +43,13 @@ export const OrderEditDialog = ({
handleSubmit, handleSubmit,
} = useForm<FormFields>({ } = useForm<FormFields>({
defaultValues: { defaultValues: {
limitPrice: addDecimalsFormatNumber( limitPrice: addDecimal(order.price, order.market?.decimalPlaces ?? 0),
order.price, size: addDecimal(order.size, order.market?.positionDecimalPlaces ?? 0),
order.market?.decimalPlaces ?? 0
),
}, },
}); });
const step = toDecimal(order.market?.decimalPlaces ?? 0); const step = toDecimal(order.market?.decimalPlaces ?? 0);
const stepSize = toDecimal(order.market?.positionDecimalPlaces ?? 0);
return ( return (
<Dialog <Dialog
open={isOpen} open={isOpen}
@ -96,9 +96,10 @@ export const OrderEditDialog = ({
<form <form
onSubmit={handleSubmit(onSubmit)} onSubmit={handleSubmit(onSubmit)}
data-testid="edit-order" data-testid="edit-order"
className="w-1/2 mt-4" className="w-full mt-4"
> >
<FormGroup label={t('Price')} labelFor="limitPrice"> <div className="flex flex-col md:flex-row gap-4">
<FormGroup label={t('Price')} labelFor="limitPrice" className="grow">
<Input <Input
type="number" type="number"
step={step} step={step}
@ -106,15 +107,37 @@ export const OrderEditDialog = ({
required: t('You need to provide a price'), required: t('You need to provide a price'),
validate: { validate: {
min: (value) => min: (value) =>
Number(value) > 0 ? true : t('The price cannot be negative'), Number(value) > 0
? true
: t('The price cannot be negative'),
}, },
})} })}
id="limitPrice" id="limitPrice"
/> />
{errors.limitPrice?.message && ( {errors.limitPrice?.message && (
<InputError intent="danger">{errors.limitPrice.message}</InputError> <InputError intent="danger">
{errors.limitPrice.message}
</InputError>
)} )}
</FormGroup> </FormGroup>
<FormGroup label={t('Size')} labelFor="size" className="grow">
<Input
type="number"
step={stepSize}
{...register('size', {
required: t('You need to provide a size'),
validate: {
min: (value) =>
Number(value) > 0 ? true : t('The size cannot be negative'),
},
})}
id="size"
/>
{errors.size?.message && (
<InputError intent="danger">{errors.size.message}</InputError>
)}
</FormGroup>
</div>
<Button variant="primary" size="md" type="submit"> <Button variant="primary" size="md" type="submit">
{t('Update')} {t('Update')}
</Button> </Button>

View File

@ -136,7 +136,7 @@ export const OrderList = forwardRef<AgGridReact, OrderListProps>(
order={editOrder} order={editOrder}
onSubmit={(fields) => { onSubmit={(fields) => {
setEditOrder(null); setEditOrder(null);
orderEdit.edit({ price: fields.limitPrice }); orderEdit.edit({ price: fields.limitPrice, size: fields.size });
}} }}
/> />
)} )}
@ -356,6 +356,7 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
colId="amend" colId="amend"
headerName="" headerName=""
field="status" field="status"
minWidth={150}
cellRenderer={({ data, node }: VegaICellRendererParams<Order>) => { cellRenderer={({ data, node }: VegaICellRendererParams<Order>) => {
if (node?.rowPinned) { if (node?.rowPinned) {
return ( return (

View File

@ -124,7 +124,7 @@ function setup(order: Order, context?: Partial<VegaWalletContextShape>) {
} }
describe('useOrderEdit', () => { describe('useOrderEdit', () => {
it('should edit a correctly formatted order', async () => { it('should edit a correctly formatted order if there is no size', async () => {
const mockSendTx = jest.fn().mockReturnValue(Promise.resolve({})); const mockSendTx = jest.fn().mockReturnValue(Promise.resolve({}));
const pubKeyObj = { publicKey: '0x123', name: 'test key 1' }; const pubKeyObj = { publicKey: '0x123', name: 'test key 1' };
const order = generateOrder({ const order = generateOrder({
@ -154,6 +154,36 @@ describe('useOrderEdit', () => {
}); });
}); });
it('should edit a correctly formatted order', async () => {
const mockSendTx = jest.fn().mockReturnValue(Promise.resolve({}));
const pubKeyObj = { publicKey: '0x123', name: 'test key 1' };
const order = generateOrder({
price: '123456789',
market: { decimalPlaces: 2 },
});
const { result } = setup(order, {
sendTx: mockSendTx,
pubKeys: [pubKeyObj],
pubKey: pubKeyObj.publicKey,
});
act(() => {
result.current.edit({ price: '1234567.89', size: '20' });
});
expect(mockSendTx).toHaveBeenCalledWith(pubKeyObj.publicKey, {
orderAmendment: {
orderId: order.id,
// eslint-disable-next-line
marketId: order.market!.id,
timeInForce: order.timeInForce,
price: '123456789', // Decimal removed
sizeDelta: 1990,
expiresAt: undefined,
},
});
});
it('has the correct default state', () => { it('has the correct default state', () => {
const order = generateOrder(); const order = generateOrder();
const { result } = setup(order); const { result } = setup(order);

View File

@ -5,10 +5,11 @@ import type { OrderEventFieldsFragment } from './';
import * as Sentry from '@sentry/react'; import * as Sentry from '@sentry/react';
import type { Order } from '../components'; import type { Order } from '../components';
import { useOrderEvent } from './use-order-event'; import { useOrderEvent } from './use-order-event';
import BigNumber from 'bignumber.js';
// Can only edit price for now
export interface EditOrderArgs { export interface EditOrderArgs {
price: string; price: string;
size?: string;
} }
export const useOrderEdit = (order: Order | null) => { export const useOrderEdit = (order: Order | null) => {
@ -47,7 +48,13 @@ export const useOrderEdit = (order: Order | null) => {
marketId: order.market.id, marketId: order.market.id,
price: removeDecimal(args.price, order.market.decimalPlaces), price: removeDecimal(args.price, order.market.decimalPlaces),
timeInForce: order.timeInForce, timeInForce: order.timeInForce,
sizeDelta: 0, sizeDelta: args.size
? new BigNumber(
removeDecimal(args.size, order.market.positionDecimalPlaces)
)
.minus(order.size)
.toNumber()
: 0,
expiresAt: order.expiresAt expiresAt: order.expiresAt
? toNanoSeconds(order.expiresAt) // Wallet expects timestamp in nanoseconds ? toNanoSeconds(order.expiresAt) // Wallet expects timestamp in nanoseconds
: undefined, : undefined,