From ed78261aad8bf0a339fda6c8c5b4714cd2ad9ff2 Mon Sep 17 00:00:00 2001 From: "m.ray" <16125548+MadalinaRaicu@users.noreply.github.com> Date: Fri, 7 Apr 2023 13:01:12 -0400 Subject: [PATCH] fix(trading): order tx toasts title and intent should be set by status (#3368) --- .../lib/hooks/use-vega-transaction-toasts.tsx | 29 ++- libs/orders/src/lib/order-hooks/index.ts | 3 - .../lib/order-hooks/use-order-cancel.spec.tsx | 138 ------------ .../src/lib/order-hooks/use-order-cancel.tsx | 83 ------- .../lib/order-hooks/use-order-edit.spec.tsx | 179 --------------- .../src/lib/order-hooks/use-order-edit.tsx | 82 ------- .../lib/order-hooks/use-order-submit.spec.tsx | 205 ------------------ .../src/lib/order-hooks/use-order-submit.tsx | 142 ------------ libs/orders/src/lib/utils.ts | 53 +++++ 9 files changed, 66 insertions(+), 848 deletions(-) delete mode 100644 libs/orders/src/lib/order-hooks/use-order-cancel.spec.tsx delete mode 100644 libs/orders/src/lib/order-hooks/use-order-cancel.tsx delete mode 100644 libs/orders/src/lib/order-hooks/use-order-edit.spec.tsx delete mode 100644 libs/orders/src/lib/order-hooks/use-order-edit.tsx delete mode 100644 libs/orders/src/lib/order-hooks/use-order-submit.spec.tsx delete mode 100644 libs/orders/src/lib/order-hooks/use-order-submit.tsx diff --git a/apps/trading/lib/hooks/use-vega-transaction-toasts.tsx b/apps/trading/lib/hooks/use-vega-transaction-toasts.tsx index 2b394c5f5..c0591a94e 100644 --- a/apps/trading/lib/hooks/use-vega-transaction-toasts.tsx +++ b/apps/trading/lib/hooks/use-vega-transaction-toasts.tsx @@ -39,10 +39,14 @@ import { t } from '@vegaprotocol/i18n'; import { useAssetsDataProvider } from '@vegaprotocol/assets'; import { useEthWithdrawApprovalsStore } from '@vegaprotocol/web3'; import { DApp, EXPLORER_TX, useLinks } from '@vegaprotocol/environment'; -import { getRejectionReason, useOrderByIdQuery } from '@vegaprotocol/orders'; +import { + getOrderToastIntent, + getOrderToastTitle, + getRejectionReason, + useOrderByIdQuery, +} from '@vegaprotocol/orders'; import { useMarketList } from '@vegaprotocol/market-list'; import type { Side } from '@vegaprotocol/types'; -import { OrderStatus } from '@vegaprotocol/types'; import { OrderStatusMapping } from '@vegaprotocol/types'; import { Size } from '@vegaprotocol/react-helpers'; @@ -478,12 +482,10 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => { getRejectionReason(tx.order) || tx.order.rejectionReason || ''; return ( <> - {t('Order rejected')} - {rejectionReason || tx.order.rejectionReason ? ( + {getOrderToastTitle(tx.order.status)} + {rejectionReason ? (

- {t('Your order has been rejected because: %s', [ - rejectionReason || tx.order.rejectionReason, - ])} + {t('Your order has been rejected because: %s', [rejectionReason])}

) : (

{t('Your order has been rejected.')}

@@ -506,7 +508,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => { if (isOrderSubmissionTransaction(tx.body) && tx.order?.rejectionReason) { return (
-

{t('Order rejected')}

+

{getOrderToastTitle(tx.order.status)}

{t('Your order was rejected.')}

{tx.txHash && (

@@ -580,7 +582,7 @@ const VegaTxErrorToastContent = ({ tx }: VegaTxToastContentProps) => { tx.error instanceof WalletError && walletNoConnectionCodes.includes(tx.error.code); if (orderRejection) { - label = t('Order rejected'); + label = getOrderToastTitle(tx.order?.status) || t('Order rejected'); errorMessage = t('Your order has been rejected because: %s', [ orderRejection || tx.order?.rejectionReason || ' ', ]); @@ -649,13 +651,8 @@ export const useVegaTransactionToasts = () => { // Transaction can be successful but the order can be rejected by the network const intent = - (tx.order && - [OrderStatus.STATUS_REJECTED, OrderStatus.STATUS_STOPPED].includes( - tx.order.status - )) || - tx.order?.rejectionReason - ? Intent.Danger - : intentMap[tx.status]; + (tx.order && getOrderToastIntent(tx.order.status)) || + intentMap[tx.status]; return { id: `vega-${tx.id}`, diff --git a/libs/orders/src/lib/order-hooks/index.ts b/libs/orders/src/lib/order-hooks/index.ts index 80d733efb..e0a27c835 100644 --- a/libs/orders/src/lib/order-hooks/index.ts +++ b/libs/orders/src/lib/order-hooks/index.ts @@ -1,8 +1,5 @@ export * from './__generated__/OrdersSubscription'; export * from './use-has-active-order'; -export * from './use-order-cancel'; -export * from './use-order-edit'; -export * from './use-order-submit'; export * from './use-order-update'; export * from './use-pending-orders-volume'; export * from './use-order-store'; diff --git a/libs/orders/src/lib/order-hooks/use-order-cancel.spec.tsx b/libs/orders/src/lib/order-hooks/use-order-cancel.spec.tsx deleted file mode 100644 index 9740c474c..000000000 --- a/libs/orders/src/lib/order-hooks/use-order-cancel.spec.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import type { MockedResponse } from '@apollo/client/testing'; -import { MockedProvider } from '@apollo/client/testing'; -import { act, renderHook } from '@testing-library/react'; -import type { ReactNode } from 'react'; -import { VegaTxStatus, VegaWalletContext } from '@vegaprotocol/wallet'; -import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; -import { useOrderCancel } from './use-order-cancel'; -import type { OrderSubSubscription } from './'; -import { OrderSubDocument } from './'; -import * as Schema from '@vegaprotocol/types'; - -const defaultWalletContext = { - pubKey: null, - pubKeys: [], - isReadOnly: false, - sendTx: jest.fn().mockReturnValue(Promise.resolve(null)), - connect: jest.fn(), - disconnect: jest.fn(), - selectPubKey: jest.fn(), - connector: null, -}; - -function setup(context?: Partial) { - const mocks: MockedResponse = { - request: { - query: OrderSubDocument, - variables: { - partyId: context?.pubKey || '', - }, - }, - result: { - data: { - orders: [ - { - type: Schema.OrderType.TYPE_LIMIT, - id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62', - status: Schema.OrderStatus.STATUS_ACTIVE, - rejectionReason: null, - createdAt: '2022-07-05T14:25:47.815283706Z', - expiresAt: '2022-07-05T14:25:47.815283706Z', - size: '10', - price: '300000', - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, - side: Schema.Side.SIDE_BUY, - marketId: 'market-id', - __typename: 'OrderUpdate', - }, - ], - }, - }, - }; - const filterMocks: MockedResponse = { - request: { - query: OrderSubDocument, - variables: { - partyId: context?.pubKey || '', - }, - }, - result: { - data: { - orders: [ - { - type: Schema.OrderType.TYPE_LIMIT, - id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62', - status: Schema.OrderStatus.STATUS_ACTIVE, - rejectionReason: null, - createdAt: '2022-07-05T14:25:47.815283706Z', - expiresAt: '2022-07-05T14:25:47.815283706Z', - size: '10', - price: '300000', - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, - side: Schema.Side.SIDE_BUY, - marketId: 'market-id', - __typename: 'OrderUpdate', - }, - ], - }, - }, - }; - - const wrapper = ({ children }: { children: ReactNode }) => ( - - - {children} - - - ); - - return renderHook(() => useOrderCancel(), { wrapper }); -} - -describe('useOrderCancel', () => { - it('has the correct default state', () => { - const { result } = setup(); - expect(typeof result.current.cancel).toEqual('function'); - expect(typeof result.current.reset).toEqual('function'); - expect(result.current.transaction.status).toEqual(VegaTxStatus.Default); - expect(result.current.transaction.txHash).toEqual(null); - expect(result.current.transaction.error).toEqual(null); - }); - - it('should not sendTx if no keypair', () => { - const mockSendTx = jest.fn(); - const { result } = setup({ - sendTx: mockSendTx, - pubKeys: [], - pubKey: null, - }); - act(() => { - result.current.cancel({ orderId: 'order-id', marketId: 'market-id' }); - }); - expect(mockSendTx).not.toHaveBeenCalled(); - }); - - it('should cancel a correctly formatted order', async () => { - const mockSendTx = jest.fn().mockReturnValue(Promise.resolve({})); - const pubKeyObj = { publicKey: '0x123', name: 'test key 1' }; - const { result } = setup({ - sendTx: mockSendTx, - pubKeys: [pubKeyObj], - pubKey: pubKeyObj.publicKey, - }); - - const args = { - orderId: 'order-id', - marketId: 'market-id', - }; - act(() => { - result.current.cancel(args); - }); - - expect(mockSendTx).toHaveBeenCalledWith(pubKeyObj.publicKey, { - orderCancellation: args, - }); - }); -}); diff --git a/libs/orders/src/lib/order-hooks/use-order-cancel.tsx b/libs/orders/src/lib/order-hooks/use-order-cancel.tsx deleted file mode 100644 index 038ca1533..000000000 --- a/libs/orders/src/lib/order-hooks/use-order-cancel.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { useCallback, useState } from 'react'; -import { - useVegaWallet, - useVegaTransaction, - useTransactionResult, -} from '@vegaprotocol/wallet'; -import type { - OrderCancellationBody, - TransactionResult, -} from '@vegaprotocol/wallet'; -import type { OrderSubFieldsFragment } from './'; -import * as Sentry from '@sentry/react'; -import { useOrderUpdate } from './use-order-update'; - -export const useOrderCancel = () => { - const { pubKey } = useVegaWallet(); - - const [cancelledOrder, setCancelledOrder] = - useState(null); - const [transactionResult, setTransactionResult] = - useState(); - - const { - send, - transaction, - reset: resetTransaction, - setComplete, - Dialog, - } = useVegaTransaction(); - - const waitForOrderUpdate = useOrderUpdate(transaction); - const waitForTransactionResult = useTransactionResult(); - - const reset = useCallback(() => { - resetTransaction(); - setCancelledOrder(null); - }, [resetTransaction]); - - const cancel = useCallback( - async (orderCancellation: OrderCancellationBody['orderCancellation']) => { - if (!pubKey) { - return; - } - - setCancelledOrder(null); - - try { - const res = await send(pubKey, { - orderCancellation, - }); - if (orderCancellation.orderId) { - const cancelledOrder = await waitForOrderUpdate( - orderCancellation.orderId, - pubKey - ); - setCancelledOrder(cancelledOrder); - setComplete(); - } else if (res) { - const txResult = await waitForTransactionResult( - res.transactionHash, - pubKey - ); - setTransactionResult(txResult); - setComplete(); - } - return res; - } catch (e) { - Sentry.captureException(e); - return; - } - }, - [pubKey, send, setComplete, waitForOrderUpdate, waitForTransactionResult] - ); - - return { - transaction, - transactionResult, - cancelledOrder, - Dialog, - cancel, - reset, - }; -}; diff --git a/libs/orders/src/lib/order-hooks/use-order-edit.spec.tsx b/libs/orders/src/lib/order-hooks/use-order-edit.spec.tsx deleted file mode 100644 index 292acc93c..000000000 --- a/libs/orders/src/lib/order-hooks/use-order-edit.spec.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import { act, renderHook } from '@testing-library/react'; -import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; -import { VegaTxStatus, VegaWalletContext } from '@vegaprotocol/wallet'; -import type { ReactNode } from 'react'; -import { useOrderEdit } from './use-order-edit'; -import type { OrderSubSubscription } from './__generated__/OrdersSubscription'; -import { OrderSubDocument } from './__generated__/OrdersSubscription'; -import type { MockedResponse } from '@apollo/client/testing'; -import { MockedProvider } from '@apollo/client/testing'; -import type { Order } from '../components'; -import { generateOrder } from '../components'; -import * as Schema from '@vegaprotocol/types'; - -const defaultWalletContext = { - pubKey: null, - pubKeys: [], - isReadOnly: false, - sendTx: jest.fn().mockReturnValue(Promise.resolve(null)), - connect: jest.fn(), - disconnect: jest.fn(), - selectPubKey: jest.fn(), - connector: null, -}; - -function setup(order: Order, context?: Partial) { - const mocks: MockedResponse = { - request: { - query: OrderSubDocument, - variables: { - partyId: context?.pubKey || '', - }, - }, - result: { - data: { - orders: [ - { - type: Schema.OrderType.TYPE_LIMIT, - id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62', - status: Schema.OrderStatus.STATUS_ACTIVE, - rejectionReason: null, - createdAt: '2022-07-05T14:25:47.815283706Z', - expiresAt: '2022-07-05T14:25:47.815283706Z', - size: '10', - price: '300000', - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, - side: Schema.Side.SIDE_BUY, - marketId: 'market-id', - __typename: 'OrderUpdate', - }, - ], - }, - }, - }; - const filterMocks: MockedResponse = { - request: { - query: OrderSubDocument, - variables: { - partyId: context?.pubKey || '', - }, - }, - result: { - data: { - orders: [ - { - type: Schema.OrderType.TYPE_LIMIT, - id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62', - status: Schema.OrderStatus.STATUS_ACTIVE, - rejectionReason: null, - createdAt: '2022-07-05T14:25:47.815283706Z', - expiresAt: '2022-07-05T14:25:47.815283706Z', - size: '10', - price: '300000', - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, - side: Schema.Side.SIDE_BUY, - marketId: 'market-id', - __typename: 'OrderUpdate', - }, - ], - }, - }, - }; - - const wrapper = ({ children }: { children: ReactNode }) => ( - - - {children} - - - ); - return renderHook(() => useOrderEdit(order), { wrapper }); -} - -describe('useOrderEdit', () => { - 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({ - price: '123456789', - market: { decimalPlaces: 2 }, - }); - const { result } = setup(order, { - sendTx: mockSendTx, - pubKeys: [pubKeyObj], - pubKey: pubKeyObj.publicKey, - }); - - act(() => { - result.current.edit({ price: '1234567.89' }); - }); - - 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: 0, - expiresAt: undefined, - }, - }); - }); - - 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); - expect(typeof result.current.edit).toEqual('function'); - expect(typeof result.current.reset).toEqual('function'); - expect(result.current.transaction.status).toEqual(VegaTxStatus.Default); - expect(result.current.transaction.txHash).toEqual(null); - expect(result.current.transaction.error).toEqual(null); - }); - - it('should not sendTx if no keypair', async () => { - const order = generateOrder(); - const mockSendTx = jest.fn(); - const { result } = setup(order, { - sendTx: mockSendTx, - pubKeys: [], - pubKey: null, - }); - await act(async () => { - result.current.edit(order); - }); - expect(mockSendTx).not.toHaveBeenCalled(); - }); -}); diff --git a/libs/orders/src/lib/order-hooks/use-order-edit.tsx b/libs/orders/src/lib/order-hooks/use-order-edit.tsx deleted file mode 100644 index 9069e50fa..000000000 --- a/libs/orders/src/lib/order-hooks/use-order-edit.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { removeDecimal, toNanoSeconds } from '@vegaprotocol/utils'; -import { useState, useCallback } from 'react'; -import { useVegaTransaction, useVegaWallet } from '@vegaprotocol/wallet'; -import type { OrderSubFieldsFragment } from './'; -import * as Sentry from '@sentry/react'; -import type { Order } from '../components'; -import { useOrderUpdate } from './use-order-update'; -import BigNumber from 'bignumber.js'; - -export interface EditOrderArgs { - price: string; - size?: string; -} - -export const useOrderEdit = (order: Order | null) => { - const { pubKey } = useVegaWallet(); - - const [updatedOrder, setUpdatedOrder] = - useState(null); - - const { - send, - transaction, - reset: resetTransaction, - setComplete, - Dialog, - } = useVegaTransaction(); - - const waitForOrderUpdate = useOrderUpdate(transaction); - - const reset = useCallback(() => { - resetTransaction(); - setUpdatedOrder(null); - }, [resetTransaction]); - - const edit = useCallback( - async (args: EditOrderArgs) => { - if (!pubKey || !order || !order.market) { - return; - } - - setUpdatedOrder(null); - - try { - await send(pubKey, { - orderAmendment: { - orderId: order.id, - marketId: order.market.id, - price: removeDecimal(args.price, order.market.decimalPlaces), - timeInForce: order.timeInForce, - 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, - }, - }); - - const updatedOrder = await waitForOrderUpdate(order.id, pubKey); - setUpdatedOrder(updatedOrder); - setComplete(); - } catch (e) { - Sentry.captureException(e); - return; - } - }, - [pubKey, send, order, setComplete, waitForOrderUpdate] - ); - - return { - transaction, - updatedOrder, - Dialog, - edit, - reset, - }; -}; diff --git a/libs/orders/src/lib/order-hooks/use-order-submit.spec.tsx b/libs/orders/src/lib/order-hooks/use-order-submit.spec.tsx deleted file mode 100644 index 4af7b5c94..000000000 --- a/libs/orders/src/lib/order-hooks/use-order-submit.spec.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import { act, renderHook } from '@testing-library/react'; -import type { PubKey, VegaWalletContextShape } from '@vegaprotocol/wallet'; -import { VegaTxStatus, VegaWalletContext } from '@vegaprotocol/wallet'; -import * as Schema from '@vegaprotocol/types'; -import type { ReactNode } from 'react'; -import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; -import { useOrderSubmit } from './use-order-submit'; -import type { OrderSubSubscription } from './'; -import { OrderSubDocument } from './'; -import type { MockedResponse } from '@apollo/client/testing'; -import { MockedProvider } from '@apollo/client/testing'; - -const marketId = 'market-id'; - -const defaultWalletContext = { - pubKey: null, - pubKeys: [], - isReadOnly: false, - sendTx: jest.fn().mockReturnValue(Promise.resolve(null)), - connect: jest.fn(), - disconnect: jest.fn(), - selectPubKey: jest.fn(), - connector: null, -}; - -function setup(context?: Partial) { - const mocks: MockedResponse = { - request: { - query: OrderSubDocument, - variables: { - partyId: context?.pubKey || '', - }, - }, - result: { - data: { - orders: [ - { - type: Schema.OrderType.TYPE_LIMIT, - id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62', - status: Schema.OrderStatus.STATUS_ACTIVE, - rejectionReason: null, - createdAt: '2022-07-05T14:25:47.815283706Z', - expiresAt: '2022-07-05T14:25:47.815283706Z', - size: '10', - price: '300000', - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, - side: Schema.Side.SIDE_BUY, - marketId: 'market-id', - }, - ], - }, - }, - }; - const filterMocks: MockedResponse = { - request: { - query: OrderSubDocument, - variables: { - partyId: context?.pubKey || '', - }, - }, - result: { - data: { - orders: [ - { - type: Schema.OrderType.TYPE_LIMIT, - id: '9c70716f6c3698ac7bbcddc97176025b985a6bb9a0c4507ec09c9960b3216b62', - status: Schema.OrderStatus.STATUS_ACTIVE, - rejectionReason: null, - createdAt: '2022-07-05T14:25:47.815283706Z', - expiresAt: '2022-07-05T14:25:47.815283706Z', - size: '10', - price: '300000', - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, - side: Schema.Side.SIDE_BUY, - marketId: 'market-id', - __typename: 'OrderUpdate', - }, - ], - }, - }, - }; - - const wrapper = ({ children }: { children: ReactNode }) => ( - - - {children} - - - ); - return renderHook(() => useOrderSubmit(), { wrapper }); -} - -describe('useOrderSubmit', () => { - it('should submit a correctly formatted order on GTT', async () => { - const mockSendTx = jest.fn().mockReturnValue(Promise.resolve({})); - const pubKey = '0x123'; - const { result } = setup({ - sendTx: mockSendTx, - pubKeys: [{ publicKey: pubKey, name: 'test key 1' }], - pubKey, - }); - - const order = { - type: Schema.OrderType.TYPE_LIMIT, - size: '10', - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT, - side: Schema.Side.SIDE_BUY, - price: '123456789', - expiresAt: new Date('2022-01-01').toISOString(), - }; - await act(async () => { - result.current.submit({ ...order, marketId }); - }); - - expect(mockSendTx).toHaveBeenCalledWith(pubKey, { - orderSubmission: { - type: Schema.OrderType.TYPE_LIMIT, - marketId, - size: '10', - side: Schema.Side.SIDE_BUY, - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT, - price: '123456789', - expiresAt: new Date('2022-01-01').toISOString(), - }, - }); - }); - - it('should submit a correctly formatted order on GTC', async () => { - const mockSendTx = jest.fn().mockReturnValue(Promise.resolve({})); - const publicKeyObj: PubKey = { - publicKey: '0x123', - name: 'test key 1', - }; - const { result } = setup({ - sendTx: mockSendTx, - pubKeys: [publicKeyObj], - pubKey: publicKeyObj.publicKey, - }); - - const order = { - type: Schema.OrderType.TYPE_LIMIT, - size: '10', - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, - side: Schema.Side.SIDE_BUY, - price: '123456789', - expiresAt: new Date('2022-01-01').toISOString(), - }; - await act(async () => { - result.current.submit({ ...order, marketId }); - }); - - expect(mockSendTx).toHaveBeenCalledWith(publicKeyObj.publicKey, { - orderSubmission: { - type: Schema.OrderType.TYPE_LIMIT, - marketId, - size: '10', - side: Schema.Side.SIDE_BUY, - timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTC, - price: '123456789', - expiresAt: new Date('2022-01-01').toISOString(), - }, - }); - }); - - it('has the correct default state', () => { - const { result } = setup(); - expect(typeof result.current.submit).toEqual('function'); - expect(typeof result.current.reset).toEqual('function'); - expect(result.current.transaction.status).toEqual(VegaTxStatus.Default); - expect(result.current.transaction.txHash).toEqual(null); - expect(result.current.transaction.error).toEqual(null); - }); - - it('should not sendTx if no keypair', async () => { - const mockSendTx = jest.fn(); - const { result } = setup({ - sendTx: mockSendTx, - pubKeys: [], - pubKey: null, - }); - await act(async () => { - result.current.submit({} as OrderSubmissionBody['orderSubmission']); - }); - expect(mockSendTx).not.toHaveBeenCalled(); - }); - - it('should not sendTx side is not specified', async () => { - const mockSendTx = jest.fn(); - const publicKeyObj: PubKey = { - publicKey: '0x123', - name: 'test key 1', - }; - const { result } = setup({ - sendTx: mockSendTx, - pubKeys: [publicKeyObj], - pubKey: publicKeyObj.publicKey, - }); - await act(async () => { - result.current.submit({} as OrderSubmissionBody['orderSubmission']); - }); - expect(mockSendTx).not.toHaveBeenCalled(); - }); -}); diff --git a/libs/orders/src/lib/order-hooks/use-order-submit.tsx b/libs/orders/src/lib/order-hooks/use-order-submit.tsx deleted file mode 100644 index 4be232443..000000000 --- a/libs/orders/src/lib/order-hooks/use-order-submit.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { useCallback, useState } from 'react'; -import type { ReactNode } from 'react'; -import type { OrderSubFieldsFragment } from './__generated__/OrdersSubscription'; -import { - useVegaWallet, - useVegaTransaction, - determineId, -} from '@vegaprotocol/wallet'; -import * as Sentry from '@sentry/react'; -import { useOrderUpdate } from './use-order-update'; -import * as Schema from '@vegaprotocol/types'; -import { Icon, Intent } from '@vegaprotocol/ui-toolkit'; -import { t } from '@vegaprotocol/i18n'; -import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; - -export const getOrderDialogTitle = ( - status?: Schema.OrderStatus -): string | undefined => { - if (!status) { - return; - } - - switch (status) { - case Schema.OrderStatus.STATUS_ACTIVE: - return t('Order submitted'); - case Schema.OrderStatus.STATUS_FILLED: - return t('Order filled'); - case Schema.OrderStatus.STATUS_PARTIALLY_FILLED: - return t('Order partially filled'); - case Schema.OrderStatus.STATUS_PARKED: - return t('Order parked'); - case Schema.OrderStatus.STATUS_STOPPED: - return t('Order stopped'); - case Schema.OrderStatus.STATUS_CANCELLED: - return t('Order cancelled'); - case Schema.OrderStatus.STATUS_EXPIRED: - return t('Order expired'); - case Schema.OrderStatus.STATUS_REJECTED: - return t('Order rejected'); - default: - return t('Submission failed'); - } -}; - -export const getOrderDialogIntent = ( - status?: Schema.OrderStatus -): Intent | undefined => { - if (!status) { - return; - } - switch (status) { - case Schema.OrderStatus.STATUS_PARKED: - case Schema.OrderStatus.STATUS_EXPIRED: - case Schema.OrderStatus.STATUS_PARTIALLY_FILLED: - return Intent.Warning; - case Schema.OrderStatus.STATUS_REJECTED: - case Schema.OrderStatus.STATUS_STOPPED: - case Schema.OrderStatus.STATUS_CANCELLED: - return Intent.Danger; - case Schema.OrderStatus.STATUS_FILLED: - case Schema.OrderStatus.STATUS_ACTIVE: - return Intent.Success; - default: - return; - } -}; - -export const getOrderDialogIcon = ( - status?: Schema.OrderStatus -): ReactNode | undefined => { - if (!status) { - return; - } - - switch (status) { - case Schema.OrderStatus.STATUS_PARKED: - case Schema.OrderStatus.STATUS_EXPIRED: - return ; - case Schema.OrderStatus.STATUS_REJECTED: - case Schema.OrderStatus.STATUS_STOPPED: - case Schema.OrderStatus.STATUS_CANCELLED: - return ; - default: - return; - } -}; - -export const useOrderSubmit = () => { - const { pubKey } = useVegaWallet(); - - const { - send, - transaction, - reset: resetTransaction, - setComplete, - Dialog, - } = useVegaTransaction(); - - const waitForOrderUpdate = useOrderUpdate(transaction); - - const [finalizedOrder, setFinalizedOrder] = - useState(null); - - const reset = useCallback(() => { - resetTransaction(); - setFinalizedOrder(null); - }, [resetTransaction]); - - const submit = useCallback( - async (orderSubmission: OrderSubmissionBody['orderSubmission']) => { - if (!pubKey || !orderSubmission.side) { - return; - } - - setFinalizedOrder(null); - - try { - const res = await send(pubKey, { orderSubmission }); - - if (res) { - const orderId = determineId(res.signature); - if (orderId) { - const order = await waitForOrderUpdate(orderId, pubKey); - setFinalizedOrder(order); - setComplete(); - } - } - } catch (e) { - Sentry.captureException(e); - } - }, - [pubKey, send, setComplete, waitForOrderUpdate] - ); - - return { - transaction, - finalizedOrder, - Dialog, - submit, - reset, - }; -}; diff --git a/libs/orders/src/lib/utils.ts b/libs/orders/src/lib/utils.ts index b9e4060ed..2acac6fcb 100644 --- a/libs/orders/src/lib/utils.ts +++ b/libs/orders/src/lib/utils.ts @@ -1,6 +1,7 @@ import { t } from '@vegaprotocol/i18n'; import * as Schema from '@vegaprotocol/types'; import type { OrderSubFieldsFragment } from './order-hooks'; +import { Intent } from '@vegaprotocol/ui-toolkit'; // More detail in https://docs.vega.xyz/mainnet/graphql/enums/order-time-in-force export const timeInForceLabel = (tif: string) => { @@ -38,3 +39,55 @@ export const getRejectionReason = ( : null; } }; + +export const getOrderToastTitle = ( + status?: Schema.OrderStatus +): string | undefined => { + if (!status) { + return; + } + + switch (status) { + case Schema.OrderStatus.STATUS_ACTIVE: + return t('Order submitted'); + case Schema.OrderStatus.STATUS_FILLED: + return t('Order filled'); + case Schema.OrderStatus.STATUS_PARTIALLY_FILLED: + return t('Order partially filled'); + case Schema.OrderStatus.STATUS_PARKED: + return t('Order parked'); + case Schema.OrderStatus.STATUS_STOPPED: + return t('Order stopped'); + case Schema.OrderStatus.STATUS_CANCELLED: + return t('Order cancelled'); + case Schema.OrderStatus.STATUS_EXPIRED: + return t('Order expired'); + case Schema.OrderStatus.STATUS_REJECTED: + return t('Order rejected'); + default: + return t('Submission failed'); + } +}; + +export const getOrderToastIntent = ( + status?: Schema.OrderStatus +): Intent | undefined => { + if (!status) { + return; + } + switch (status) { + case Schema.OrderStatus.STATUS_PARKED: + case Schema.OrderStatus.STATUS_EXPIRED: + case Schema.OrderStatus.STATUS_PARTIALLY_FILLED: + return Intent.Warning; + case Schema.OrderStatus.STATUS_REJECTED: + case Schema.OrderStatus.STATUS_STOPPED: + case Schema.OrderStatus.STATUS_CANCELLED: + return Intent.Danger; + case Schema.OrderStatus.STATUS_FILLED: + case Schema.OrderStatus.STATUS_ACTIVE: + return Intent.Success; + default: + return; + } +};