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

View File

@ -136,7 +136,7 @@ export const OrderList = forwardRef<AgGridReact, OrderListProps>(
order={editOrder}
onSubmit={(fields) => {
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"
headerName=""
field="status"
minWidth={150}
cellRenderer={({ data, node }: VegaICellRendererParams<Order>) => {
if (node?.rowPinned) {
return (

View File

@ -124,7 +124,7 @@ function setup(order: Order, context?: Partial<VegaWalletContextShape>) {
}
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 pubKeyObj = { publicKey: '0x123', name: 'test key 1' };
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', () => {
const order = generateOrder();
const { result } = setup(order);

View File

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