Compare commits

..
Author SHA1 Message Date
Bartłomiej Głownia 79bd15e004 fix(trading): throttle deal ticket submit 2023-03-27 12:58:18 +02:00
6 changed files with 63 additions and 22 deletions
@@ -164,6 +164,7 @@ export type OnCellClickHandler = (
export const columns = (
market: MarketMaybeWithDataAndCandles,
onSelect: (id: string) => void,
onCellClick: OnCellClickHandler,
inViewRoot?: RefObject<HTMLElement>
) => {
@@ -173,6 +174,14 @@ export const columns = (
const candleLow = market.candles && calcCandleLow(market.candles);
const candleHigh = market.candles && calcCandleHigh(market.candles);
const candleVolume = market.candles && calcCandleVolume(market.candles);
const handleKeyPress = (
event: React.KeyboardEvent<HTMLAnchorElement>,
id: string
) => {
if (event.key === 'Enter' && onSelect) {
return onSelect(id);
}
};
const selectMarketColumns: Column[] = [
{
kind: ColumnKind.Market,
@@ -180,7 +189,11 @@ export const columns = (
<Link
to={Links[Routes.MARKET](market.id)}
data-testid={`market-link-${market.id}`}
className="stretched-link"
onKeyPress={(event) => handleKeyPress(event, market.id)}
onClick={(e) => {
e.preventDefault();
onSelect(market.id);
}}
>
<UILink>{market.tradableInstrument.instrument.code}</UILink>
</Link>
@@ -239,7 +252,7 @@ export const columns = (
value: (
<button
data-dialog-trigger
className="inline underline relative z-[1]"
className="inline underline"
onClick={(e) => {
e.stopPropagation();
onCellClick(
@@ -339,6 +352,7 @@ export const columns = (
export const columnsPositionMarkets = (
market: MarketMaybeWithDataAndCandles,
onSelect: (id: string) => void,
inViewRoot?: RefObject<HTMLElement>,
openVolume?: string,
onCellClick?: OnCellClickHandler
@@ -348,6 +362,14 @@ export const columnsPositionMarkets = (
.filter((c: string | undefined): c is CandleClose => !isNil(c));
const candleLow = market.candles && calcCandleLow(market.candles);
const candleHigh = market.candles && calcCandleHigh(market.candles);
const handleKeyPress = (
event: React.KeyboardEvent<HTMLSpanElement>,
id: string
) => {
if (event.key === 'Enter' && onSelect) {
return onSelect(id);
}
};
const candleVolume = market.candles && calcCandleVolume(market.candles);
const selectMarketColumns: Column[] = [
{
@@ -356,7 +378,11 @@ export const columnsPositionMarkets = (
<Link
to={Links[Routes.MARKET](market.id)}
data-testid={`market-link-${market.id}`}
className="stretched-link"
onKeyPress={(event) => handleKeyPress(event, market.id)}
onClick={(e) => {
e.preventDefault();
onSelect(market.id);
}}
>
<UILink>{market.tradableInstrument.instrument.code}</UILink>
</Link>
@@ -415,7 +441,7 @@ export const columnsPositionMarkets = (
value: (
<button
data-dialog-trigger
className="inline underline relative"
className="inline underline"
onClick={(e) => {
e.stopPropagation();
if (!onCellClick) return;
@@ -32,15 +32,20 @@ export const SelectMarketTableHeader = ({
export const SelectMarketTableRow = ({
detailed = false,
columns,
onSelect,
marketId,
}: {
detailed?: boolean;
columns: Column[];
onSelect: (id: string) => void;
marketId: string;
}) => {
return (
<tr
className={`hover:bg-neutral-200 dark:hover:bg-neutral-700 cursor-pointer relative h-[34px]`}
onClick={() => {
onSelect(marketId);
}}
data-testid={`market-link-${marketId}`}
>
{columns.map(({ kind, value, className, dataTestId, onlyOnDetailed }) => {
@@ -162,12 +162,14 @@ describe('SelectMarket', () => {
const table = document.createElement('table');
it('should render the SelectAllMarketsTableBody', () => {
const onSelect = jest.fn();
const onCellClick = jest.fn();
const { container } = render(
<MemoryRouter>
<SelectAllMarketsTableBody
markets={[MARKET_A as Market, MARKET_B as Market]}
onCellClick={onCellClick}
onSelect={onSelect}
/>
</MemoryRouter>,
{ wrapper: MockedProvider, container: document.body.appendChild(table) }
@@ -175,5 +177,7 @@ describe('SelectMarket', () => {
expect(screen.getByText('ABCDEF')).toBeTruthy(); // name
expect(screen.getByText('25.00%')).toBeTruthy(); // price change
expect(container).toHaveTextContent(/1,000/); // volume
fireEvent.click(screen.getAllByTestId(`market-link-1`)[0]);
expect(onSelect).toHaveBeenCalledWith('1');
});
});
@@ -1,6 +1,5 @@
import { useEffect, useMemo, useState, useRef } from 'react';
import { useCallback, useEffect, useMemo, useState, useRef } from 'react';
import type { RefObject } from 'react';
import { useLocation } from 'react-router-dom';
import { useMarketList } from '@vegaprotocol/market-list';
import { positionsDataProvider } from '@vegaprotocol/positions';
import { t } from '@vegaprotocol/i18n';
@@ -32,14 +31,16 @@ import { HeaderTitle } from '../header';
export const SelectAllMarketsTableBody = ({
markets,
positions,
onSelect,
onCellClick,
inViewRoot,
headers = columnHeaders,
tableColumns = (market) => columns(market, onCellClick, inViewRoot),
tableColumns = (market) => columns(market, onSelect, onCellClick, inViewRoot),
}: {
markets?: MarketMaybeWithDataAndCandles[] | null;
positions?: PositionFieldsFragment[];
title?: string;
onSelect: (id: string) => void;
onCellClick: OnCellClickHandler;
headers?: Column[];
tableColumns?: (
@@ -64,6 +65,7 @@ export const SelectAllMarketsTableBody = ({
marketId={market.id}
key={i}
detailed
onSelect={onSelect}
columns={tableColumns(
market,
inViewRoot,
@@ -88,6 +90,7 @@ export const SelectAllMarketsTableBody = ({
export const SelectMarketPopover = ({
marketCode,
marketName,
onSelect,
onCellClick,
}: {
marketCode: string;
@@ -112,10 +115,13 @@ export const SelectMarketPopover = ({
variables: { partyId: pubKey || '' },
skip: !pubKey,
});
const location = useLocation();
useEffect(() => {
setOpen(false);
}, [location]);
const onSelectMarket = useCallback(
(marketId: string) => {
onSelect(marketId);
setOpen(false);
},
[onSelect]
);
const iconClass = open ? 'rotate-180' : '';
const markets = useMemo(
@@ -166,11 +172,13 @@ export const SelectMarketPopover = ({
inViewRoot={inViewRoot}
markets={markets}
positions={positions || undefined}
onSelect={onSelectMarket}
onCellClick={onCellClick}
headers={columnHeadersPositionMarkets}
tableColumns={(market, inViewRoot, openVolume) =>
columnsPositionMarkets(
market,
onSelectMarket,
inViewRoot,
openVolume,
onCellClick
@@ -183,6 +191,7 @@ export const SelectMarketPopover = ({
<SelectAllMarketsTableBody
inViewRoot={inViewRoot}
markets={data}
onSelect={onSelectMarket}
onCellClick={onCellClick}
/>
</table>
-10
View File
@@ -56,13 +56,3 @@ html [data-theme='light'] {
--pennant-color-depth-sell-fill: theme('colors.vega.pink.400');
--pennant-color-depth-sell-stroke: theme('colors.vega.pink.550');
}
.stretched-link::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
content: '';
}
@@ -1,6 +1,6 @@
import { t } from '@vegaprotocol/i18n';
import * as Schema from '@vegaprotocol/types';
import { memo, useCallback, useEffect, useState } from 'react';
import { memo, useCallback, useEffect, useState, useRef } from 'react';
import { Controller } from 'react-hook-form';
import { DealTicketAmount } from './deal-ticket-amount';
import { DealTicketButton } from './deal-ticket-button';
@@ -75,6 +75,8 @@ export const DealTicket = ({
handleSubmit,
} = useOrderForm(market.id);
const lastSubmitTime = useRef(0);
const asset = market.tradableInstrument.instrument.product.settlementAsset;
const { accountBalance: marginAccountBalance } = useMarketAccountBalance(
@@ -146,6 +148,10 @@ export const DealTicket = ({
const onSubmit = useCallback(
(order: OrderSubmission) => {
const now = new Date().getTime();
if (lastSubmitTime.current && now - lastSubmitTime.current < 1000) {
return;
}
submit(
normalizeOrderSubmission(
order,
@@ -153,6 +159,7 @@ export const DealTicket = ({
market.positionDecimalPlaces
)
);
lastSubmitTime.current = now;
},
[submit, market.decimalPlaces, market.positionDecimalPlaces]
);