From 8b2ec489d827cd89aefbbf58c62319c1b8b44431 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 19 Jul 2022 01:37:07 +0100 Subject: [PATCH] feat: improve types for order transactions and dialogs --- .../src/components/deal-ticket-amount.tsx | 4 +- .../src/components/deal-ticket-manager.tsx | 151 ++++++-- .../src/components/deal-ticket.tsx | 10 +- .../order-list/order-edit-dialog.tsx | 24 +- .../order-list/order-list.stories.tsx | 26 +- .../lib/components/order-list/order-list.tsx | 153 +++++---- libs/orders/src/lib/index.ts | 1 - libs/orders/src/lib/market.ts | 13 - .../src/lib/order-hooks/use-order-cancel.tsx | 37 +- .../src/lib/order-hooks/use-order-edit.tsx | 30 +- .../src/lib/order-hooks/use-order-submit.ts | 56 +-- .../lib/order-hooks/use-order-validation.tsx | 17 +- .../orders/src/lib/utils/get-default-order.ts | 33 +- libs/wallet/src/use-vega-transaction.ts | 9 +- .../vega-transaction-dialog.tsx | 321 ++++++------------ libs/wallet/src/wallet-types.ts | 13 - libs/withdraws/src/lib/withdraw-dialog.tsx | 6 + 17 files changed, 438 insertions(+), 466 deletions(-) delete mode 100644 libs/orders/src/lib/market.ts diff --git a/libs/deal-ticket/src/components/deal-ticket-amount.tsx b/libs/deal-ticket/src/components/deal-ticket-amount.tsx index 000153aea..b86bb3a96 100644 --- a/libs/deal-ticket/src/components/deal-ticket-amount.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-amount.tsx @@ -1,13 +1,13 @@ import type { UseFormRegister } from 'react-hook-form'; import { VegaWalletOrderType } from '@vegaprotocol/wallet'; -import type { Order } from '@vegaprotocol/orders'; import { DealTicketMarketAmount } from './deal-ticket-market-amount'; import { DealTicketLimitAmount } from './deal-ticket-limit-amount'; +import type { OrderSubmitInput } from '@vegaprotocol/orders'; export interface DealTicketAmountProps { orderType: VegaWalletOrderType; step: number; - register: UseFormRegister; + register: UseFormRegister; quoteName: string; price?: string; } diff --git a/libs/deal-ticket/src/components/deal-ticket-manager.tsx b/libs/deal-ticket/src/components/deal-ticket-manager.tsx index b202f6c6f..8497ce4d5 100644 --- a/libs/deal-ticket/src/components/deal-ticket-manager.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-manager.tsx @@ -1,10 +1,16 @@ import type { ReactNode } from 'react'; +import { useEffect } from 'react'; import { useState } from 'react'; +import type { VegaTxState } from '@vegaprotocol/wallet'; import { VegaTransactionDialog, VegaTxStatus } from '@vegaprotocol/wallet'; import { DealTicket } from './deal-ticket'; import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; +import type { OrderEvent_busEvents_event_Order } from '@vegaprotocol/orders'; import { useOrderSubmit } from '@vegaprotocol/orders'; -import { OrderStatus } from '@vegaprotocol/types'; +import { OrderStatus, OrderType } from '@vegaprotocol/types'; +import { Icon, Intent } from '@vegaprotocol/ui-toolkit'; +import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; +import { useEnvironment } from '@vegaprotocol/environment'; export interface DealTicketManagerProps { market: DealTicketQuery_market; @@ -17,26 +23,41 @@ export const DealTicketManager = ({ }: DealTicketManagerProps) => { const [orderDialogOpen, setOrderDialogOpen] = useState(false); const { submit, transaction, finalizedOrder, reset } = useOrderSubmit(market); - const getDialogTitle = (status?: string) => { - switch (status) { - case OrderStatus.Active: - return 'Order submitted'; - case OrderStatus.Filled: - return 'Order filled'; - case OrderStatus.PartiallyFilled: - return 'Order partially filled'; - case OrderStatus.Parked: - return 'Order parked'; - default: - return 'Submission failed'; + + let title; + let intent; + let icon; + let dialogContent; + + if (finalizedOrder) { + title = getDialogTitle(finalizedOrder); + + if (finalizedOrder.status === OrderStatus.Rejected) { + icon = ; + intent = Intent.Danger; + dialogContent = ( +

+ {t(`Reason: ${finalizedOrder.rejectionReason}`)} +

+ ); } - }; + + icon = ; + intent = Intent.Success; + dialogContent = ( + + ); + } + return ( <> {children || ( { + setOrderDialogOpen(true); + submit(order); + }} transactionStatus={ transaction.status === VegaTxStatus.Requested || transaction.status === VegaTxStatus.Pending @@ -45,15 +66,101 @@ export const DealTicketManager = ({ } /> )} + { + setOrderDialogOpen(isOpen); + if (!isOpen) { + reset(); + } + }} transaction={transaction} - reset={reset} - title={getDialogTitle(finalizedOrder?.status)} - /> + intent={intent} + title={title} + icon={icon} + > + {dialogContent} + + + ); +}; + +const getDialogTitle = (finalizedOrder: OrderEvent_busEvents_event_Order) => { + switch (finalizedOrder.status) { + case OrderStatus.Active: + return 'Order submitted'; + case OrderStatus.Filled: + return 'Order filled'; + case OrderStatus.PartiallyFilled: + return 'Order partially filled'; + case OrderStatus.Parked: + return 'Order parked'; + default: + return undefined; + } +}; + +interface OrderSuccessContentProps { + order: OrderEvent_busEvents_event_Order; + transaction: VegaTxState; +} + +const OrderSuccessContent = ({ + order, + transaction, +}: OrderSuccessContentProps) => { + const headerClassName = 'text-h5 font-bold text-black dark:text-white'; + const { VEGA_EXPLORER_URL } = useEnvironment(); + return ( + <> +
+ {order.market && ( +
+

{t(`Market`)}

+

{t(`${order.market.name}`)}

+
+ )} +
+

{t(`Status`)}

+

{t(`${order.status}`)}

+
+ {order.type === OrderType.Limit && order.market && ( +
+

{t(`Price`)}

+

+ {addDecimalsFormatNumber(order.price, order.market.decimalPlaces)} +

+
+ )} +
+

{t(`Amount`)}

+

+ {`${order.side === 'Buy' ? '+' : '-'} ${order.size} + `} +

+
+
+
+ {transaction.txHash && ( +
+

{t(`Transaction`)}

+ + {transaction.txHash} + +
+ )} +
); }; diff --git a/libs/deal-ticket/src/components/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket.tsx index 4e3d3d4ee..b3324b509 100644 --- a/libs/deal-ticket/src/components/deal-ticket.tsx +++ b/libs/deal-ticket/src/components/deal-ticket.tsx @@ -16,16 +16,16 @@ import { DealTicketAmount } from './deal-ticket-amount'; import { TimeInForceSelector } from './time-in-force-selector'; import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; import { ExpirySelector } from './expiry-selector'; -import type { Order } from '@vegaprotocol/orders'; +import type { OrderSubmitInput } from '@vegaprotocol/orders'; import { getDefaultOrder, useOrderValidation } from '@vegaprotocol/orders'; export type TransactionStatus = 'default' | 'pending'; export interface DealTicketProps { market: DealTicketQuery_market; - submit: (order: Order) => void; + submit: (order: OrderSubmitInput) => void; transactionStatus: TransactionStatus; - defaultOrder?: Order; + defaultOrder?: OrderSubmitInput; } export const DealTicket = ({ @@ -39,7 +39,7 @@ export const DealTicket = ({ handleSubmit, watch, formState: { errors }, - } = useForm({ + } = useForm({ mode: 'onChange', defaultValues: getDefaultOrder(market), }); @@ -57,7 +57,7 @@ export const DealTicket = ({ const isDisabled = transactionStatus === 'pending' || disabled; const onSubmit = useCallback( - (order: Order) => { + (order: OrderSubmitInput) => { if (!isDisabled) { submit(order); } diff --git a/libs/orders/src/lib/components/order-list/order-edit-dialog.tsx b/libs/orders/src/lib/components/order-list/order-edit-dialog.tsx index 94bf5fd76..0a7c1d6a2 100644 --- a/libs/orders/src/lib/components/order-list/order-edit-dialog.tsx +++ b/libs/orders/src/lib/components/order-list/order-edit-dialog.tsx @@ -6,25 +6,18 @@ import { import { OrderType } from '@vegaprotocol/types'; import { FormGroup, Input, InputError, Button } from '@vegaprotocol/ui-toolkit'; import { useForm } from 'react-hook-form'; -import Icon from 'react-syntax-highlighter'; -import { OrderDialogWrapper } from '@vegaprotocol/wallet'; -import type { Order } from '@vegaprotocol/wallet'; +import type { Orders_party_orders } from '../__generated__'; interface OrderEditDialogProps { - title: string; - order: Order | null; - edit: (body: Order) => Promise; + order: Orders_party_orders; + onSubmit: (order: Orders_party_orders) => void; } interface FormFields { entryPrice: string; } -export const OrderEditDialog = ({ - order, - title, - edit, -}: OrderEditDialogProps) => { +export const OrderEditDialog = ({ order, onSubmit }: OrderEditDialogProps) => { const headerClassName = 'text-h5 font-bold text-black dark:text-white'; const { register, @@ -39,7 +32,7 @@ export const OrderEditDialog = ({ }); if (!order) return null; return ( - }> +
{order.market && (
@@ -69,11 +62,10 @@ export const OrderEditDialog = ({

-
{ - await edit({ + onSubmit={handleSubmit((data) => { + onSubmit({ ...order, price: data.entryPrice, }); @@ -97,6 +89,6 @@ export const OrderEditDialog = ({
- +
); }; diff --git a/libs/orders/src/lib/components/order-list/order-list.stories.tsx b/libs/orders/src/lib/components/order-list/order-list.stories.tsx index 8fbc6ad10..0cd9cecaa 100644 --- a/libs/orders/src/lib/components/order-list/order-list.stories.tsx +++ b/libs/orders/src/lib/components/order-list/order-list.stories.tsx @@ -1,8 +1,7 @@ import type { Story, Meta } from '@storybook/react'; -import { OrderType, OrderStatus, OrderTimeInForce } from '@vegaprotocol/types'; import { OrderList, OrderListTable } from './order-list'; import { useState } from 'react'; -import type { Order, VegaTxState } from '@vegaprotocol/wallet'; +import type { VegaTxState } from '@vegaprotocol/wallet'; import { VegaTransactionDialog, VegaTxStatus } from '@vegaprotocol/wallet'; import { generateOrdersArray } from '../mocks'; @@ -18,9 +17,6 @@ const Template: Story = (args) => { { - return; - }} setEditOrder={() => { return; }} @@ -41,36 +37,22 @@ const Template2: Story = (args) => { txHash: null, signature: null, }; - const finalizedOrder: Order = { - status: OrderStatus.Cancelled, - rejectionReason: null, - size: '10', - price: '1000', - market: { name: 'ETH/DAI (30 Jun 2022)', decimalPlaces: 5 }, - type: OrderType.Limit, - timeInForce: OrderTimeInForce.GTC, - }; - const reset = () => null; + return ( <>
{ - return; - }} setEditOrder={() => { return; }} />
diff --git a/libs/orders/src/lib/components/order-list/order-list.tsx b/libs/orders/src/lib/components/order-list/order-list.tsx index 2593872ec..e8fd87be6 100644 --- a/libs/orders/src/lib/components/order-list/order-list.tsx +++ b/libs/orders/src/lib/components/order-list/order-list.tsx @@ -5,99 +5,98 @@ import { getDateTimeFormat, t, } from '@vegaprotocol/react-helpers'; -import { AgGridDynamic as AgGrid, Button } from '@vegaprotocol/ui-toolkit'; +import { + AgGridDynamic as AgGrid, + Button, + Dialog, +} from '@vegaprotocol/ui-toolkit'; import type { ICellRendererParams, ValueFormatterParams, } from 'ag-grid-community'; -import type { - AgGridReact, - AgGridReactProps, - AgReactUiProps, -} from 'ag-grid-react'; +import type { AgGridReact } from 'ag-grid-react'; import { AgGridColumn } from 'ag-grid-react'; import { forwardRef, useState } from 'react'; import type { Orders_party_ordersConnection_edges_node } from '../'; import BigNumber from 'bignumber.js'; - +import type { OrderCancelInput } from '../../order-hooks/use-order-cancel'; import { useOrderCancel } from '../../order-hooks/use-order-cancel'; import { VegaTransactionDialog } from '@vegaprotocol/wallet'; import { useOrderEdit } from '../../order-hooks/use-order-edit'; import { OrderEditDialog } from './order-edit-dialog'; -type OrderListProps = AgGridReactProps | AgReactUiProps; +interface OrderListProps { + data: Orders_party_ordersConnection_edges_node[] | null; +} export const OrderList = forwardRef( - (props, ref) => { + ({ data }, ref) => { + // Cancel transaction dialog const [cancelOrderDialogOpen, setCancelOrderDialogOpen] = useState(false); + // Edit order transaction dialog const [editOrderDialogOpen, setEditOrderDialogOpen] = useState(false); + // Order for edit order dialog const [editOrder, setEditOrder] = useState(null); - - const { transaction, updatedOrder, reset, cancel } = useOrderCancel(); + const { transaction, reset, cancel } = useOrderCancel(); const { transaction: editTransaction, - updatedOrder: editedOrder, reset: resetEdit, edit, } = useOrderEdit(); - const getCancelDialogTitle = (status?: string) => { - switch (status) { - case OrderStatus.Cancelled: - return 'Order cancelled'; - case OrderStatus.Rejected: - return 'Order rejected'; - case OrderStatus.Expired: - return 'Order expired'; - default: - return 'Cancellation failed'; - } - }; - const getEditDialogTitle = () => - editedOrder - ? t( - `Order ${ - editOrder?.market?.tradableInstrument.instrument.code ?? '' - } updated` - ) - : t( - `Edit ${ - editOrder?.market?.tradableInstrument.instrument.code ?? '' - } order` - ); + // const getEditDialogTitle = () => + // editedOrder + // ? t( + // `Order ${ + // editOrder?.market?.tradableInstrument.instrument.code ?? '' + // } updated` + // ) + // : t( + // `Edit ${ + // editOrder?.market?.tradableInstrument.instrument.code ?? '' + // } order` + // ); return ( <> { + setCancelOrderDialogOpen(true); + cancel(order); + }} ref={ref} - setEditOrderDialogOpen={setEditOrderDialogOpen} setEditOrder={setEditOrder} /> { + setCancelOrderDialogOpen(isOpen); + if (!isOpen) { + reset(); + } + }} transaction={transaction} - reset={reset} - title={getCancelDialogTitle(updatedOrder?.status)} - finalizedOrder={updatedOrder} /> { + setEditOrderDialogOpen(isOpen); + if (!isOpen) { + resetEdit(); + } + }} transaction={editTransaction} - reset={resetEdit} - title={getEditDialogTitle()} - finalizedOrder={editedOrder} - > - - + /> + { + setEditOrder(null); + setEditOrderDialogOpen(true); + // @ts-ignore fix me, market is null + edit(order); + }} + /> ); } @@ -109,17 +108,16 @@ type OrderListTableValueFormatterParams = Omit< > & { data: Orders_party_ordersConnection_edges_node | null; }; - -type OrderListTableProps = (AgGridReactProps | AgReactUiProps) & { - cancel: (body?: unknown) => Promise; - setEditOrderDialogOpen: (value: boolean) => void; +interface OrderListTableProps { + data: Orders_party_ordersConnection_edges_node[] | null; + cancel: (order: OrderCancelInput) => void; setEditOrder: ( order: Orders_party_ordersConnection_edges_node | null ) => void; -}; +} export const OrderListTable = forwardRef( - ({ cancel, setEditOrderDialogOpen, setEditOrder, ...props }, ref) => { + ({ data, cancel, setEditOrder }, ref) => { return ( ( style={{ width: '100%', height: '100%' }} getRowId={({ data }) => data.id} rowHeight={40} - {...props} > ( data-testid="edit" variant="secondary" onClick={() => { - setEditOrderDialogOpen(true); setEditOrder(data); }} > @@ -301,7 +297,10 @@ export const OrderListTable = forwardRef(