fix(trading): order tx toasts title and intent should be set by status (#3368)

This commit is contained in:
m.ray 2023-04-07 13:01:12 -04:00 committed by GitHub
parent 363ca9c6e1
commit ed78261aad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 848 deletions

View File

@ -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 (
<>
<ToastHeading>{t('Order rejected')}</ToastHeading>
{rejectionReason || tx.order.rejectionReason ? (
<ToastHeading>{getOrderToastTitle(tx.order.status)}</ToastHeading>
{rejectionReason ? (
<p>
{t('Your order has been rejected because: %s', [
rejectionReason || tx.order.rejectionReason,
])}
{t('Your order has been rejected because: %s', [rejectionReason])}
</p>
) : (
<p>{t('Your order has been rejected.')}</p>
@ -506,7 +508,7 @@ const VegaTxCompleteToastsContent = ({ tx }: VegaTxToastContentProps) => {
if (isOrderSubmissionTransaction(tx.body) && tx.order?.rejectionReason) {
return (
<div>
<h3 className="font-bold">{t('Order rejected')}</h3>
<h3 className="font-bold">{getOrderToastTitle(tx.order.status)}</h3>
<p>{t('Your order was rejected.')}</p>
{tx.txHash && (
<p className="break-all">
@ -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}`,

View File

@ -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';

View File

@ -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<VegaWalletContextShape>) {
const mocks: MockedResponse<OrderSubSubscription> = {
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<OrderSubSubscription> = {
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 }) => (
<MockedProvider mocks={[mocks, filterMocks]}>
<VegaWalletContext.Provider
value={{ ...defaultWalletContext, ...context }}
>
{children}
</VegaWalletContext.Provider>
</MockedProvider>
);
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,
});
});
});

View File

@ -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<OrderSubFieldsFragment | null>(null);
const [transactionResult, setTransactionResult] =
useState<TransactionResult>();
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,
};
};

View File

@ -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<VegaWalletContextShape>) {
const mocks: MockedResponse<OrderSubSubscription> = {
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<OrderSubSubscription> = {
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 }) => (
<MockedProvider mocks={[mocks, filterMocks]}>
<VegaWalletContext.Provider
value={{ ...defaultWalletContext, ...context }}
>
{children}
</VegaWalletContext.Provider>
</MockedProvider>
);
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();
});
});

View File

@ -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<OrderSubFieldsFragment | null>(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,
};
};

View File

@ -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<VegaWalletContextShape>) {
const mocks: MockedResponse<OrderSubSubscription> = {
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<OrderSubSubscription> = {
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 }) => (
<MockedProvider mocks={[mocks, filterMocks]}>
<VegaWalletContext.Provider
value={{ ...defaultWalletContext, ...context }}
>
{children}
</VegaWalletContext.Provider>
</MockedProvider>
);
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();
});
});

View File

@ -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 <Icon name="warning-sign" size={16} />;
case Schema.OrderStatus.STATUS_REJECTED:
case Schema.OrderStatus.STATUS_STOPPED:
case Schema.OrderStatus.STATUS_CANCELLED:
return <Icon name="error" size={16} />;
default:
return;
}
};
export const useOrderSubmit = () => {
const { pubKey } = useVegaWallet();
const {
send,
transaction,
reset: resetTransaction,
setComplete,
Dialog,
} = useVegaTransaction();
const waitForOrderUpdate = useOrderUpdate(transaction);
const [finalizedOrder, setFinalizedOrder] =
useState<OrderSubFieldsFragment | null>(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,
};
};

View File

@ -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;
}
};