feat: 24h volume + market links in orders table (#1836)

* feat: #1659 add link to market in orders table

* feat: #1794 use volume 24h instead of indicative volume

* fix: remove total fees that was defined but not used in select columns

* fix: fix cypress test for volume (24h) header

* fix: add volume 24h tooltip

* fix: trading mode and volume order
This commit is contained in:
m.ray 2022-10-24 13:16:09 +01:00 committed by GitHub
parent 2d9fdbf98c
commit ee3b9a56c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 181 additions and 63 deletions

View File

@ -67,7 +67,7 @@ describe('Market trading page', () => {
it('must see market volume', () => {
cy.getByTestId(marketSummaryBlock).within(() => {
cy.getByTestId(marketVolume).within(() => {
cy.getByTestId(itemHeader).should('have.text', 'Volume');
cy.getByTestId(itemHeader).should('have.text', 'Volume (24h)');
cy.getByTestId(itemValue).should('not.be.empty');
});
});

View File

@ -0,0 +1 @@
export * from './last-24h-volume';

View File

@ -0,0 +1,90 @@
import {
calcCandleVolume,
marketCandlesProvider,
marketProvider,
} from '@vegaprotocol/market-list';
import {
addDecimalsFormatNumber,
t,
useDataProvider,
useYesterday,
} from '@vegaprotocol/react-helpers';
import { Interval } from '@vegaprotocol/types';
import throttle from 'lodash/throttle';
import { useCallback, useMemo, useRef, useState } from 'react';
import * as constants from '../constants';
import { HeaderStat } from '../header';
import type {
SingleMarketFieldsFragment,
Candle,
} from '@vegaprotocol/market-list';
export const Last24hVolume = ({ marketId }: { marketId: string }) => {
const [candleVolume, setCandleVolume] = useState<string>();
const yesterday = useYesterday();
// Cache timestamp for yesterday to prevent full unmount of market page when
// a rerender occurs
const yTimestamp = useMemo(() => {
return new Date(yesterday).toISOString();
}, [yesterday]);
const marketVariables = useMemo(
() => ({
marketId: marketId,
}),
[marketId]
);
const variables = useMemo(
() => ({
marketId: marketId,
interval: Interval.INTERVAL_I1H,
since: yTimestamp,
}),
[marketId, yTimestamp]
);
const { data, error } = useDataProvider<SingleMarketFieldsFragment, never>({
dataProvider: marketProvider,
variables: marketVariables,
skip: !marketId,
});
const throttledSetCandles = useRef(
throttle((data: Candle[]) => {
setCandleVolume(calcCandleVolume(data));
}, constants.DEBOUNCE_UPDATE_TIME)
).current;
const update = useCallback(
({ data }: { data: Candle[] }) => {
throttledSetCandles(data);
return true;
},
[throttledSetCandles]
);
useDataProvider<Candle[], Candle>({
dataProvider: marketCandlesProvider,
update,
variables,
skip: !marketId || !data,
updateOnInit: true,
});
return (
<HeaderStat
heading={t('Volume (24h)')}
testId="market-volume"
description={
error && candleVolume && data?.positionDecimalPlaces
? t('The total amount of assets traded in the last 24 hours.')
: null
}
>
{!error && candleVolume && data?.positionDecimalPlaces
? addDecimalsFormatNumber(candleVolume, data.positionDecimalPlaces)
: '-'}
</HeaderStat>
);
};

View File

@ -1,4 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { FeesCell } from '@vegaprotocol/market-info';
import {
calcCandleHigh,
calcCandleLow,
calcCandleVolume,
} from '@vegaprotocol/market-list';
import {
addDecimalsFormatNumber,
PriceCell,
@ -12,16 +18,14 @@ import {
MarketTradingModeMapping,
} from '@vegaprotocol/types';
import { PriceCellChange, Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit';
import isNil from 'lodash/isNil';
import Link from 'next/link';
import { calcCandleHigh, calcCandleLow } from '@vegaprotocol/market-list';
import type { CandleClose } from '@vegaprotocol/types';
import type {
MarketWithData,
MarketWithCandles,
} from '@vegaprotocol/market-list';
import isNil from 'lodash/isNil';
import { FeesCell } from '@vegaprotocol/market-info';
type Market = MarketWithData & MarketWithCandles;
export const cellClassNames = 'py-1 first:text-left text-right';
@ -103,28 +107,28 @@ const headers: Column[] = [
},
{
kind: ColumnKind.High24,
value: t('24h high'),
value: t('24h High'),
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Low24,
value: t('24h low'),
value: t('24h Low'),
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Volume,
value: t('24h Volume'),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.TradingMode,
value: t('Trading mode'),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Volume,
value: t('Volume'),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Fee,
value: <FeesInfo />,
@ -169,6 +173,7 @@ export const columns = (
.filter((c: string | undefined): c is CandleClose => !isNil(c));
const candleLow = market.candles && calcCandleLow(market.candles);
const candleHigh = market.candles && calcCandleHigh(market.candles);
const candleVolume = market.candles && calcCandleVolume(market.candles);
const selectMarketColumns: Column[] = [
{
kind: ColumnKind.Market,
@ -273,6 +278,19 @@ export const columns = (
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Volume,
value: candleVolume
? addDecimalsFormatNumber(
candleVolume.toString(),
market.positionDecimalPlaces,
2
)
: '-',
className: `${cellClassNames} hidden lg:table-cell font-mono`,
onlyOnDetailed: true,
dataTestId: 'market-volume',
},
{
kind: ColumnKind.TradingMode,
value:
@ -287,19 +305,6 @@ export const columns = (
onlyOnDetailed: true,
dataTestId: 'trading-mode-col',
},
{
kind: ColumnKind.Volume,
value:
market.data?.indicativeVolume && market.data.indicativeVolume !== '0'
? addDecimalsFormatNumber(
market.data.indicativeVolume,
market.positionDecimalPlaces
)
: '-',
className: `${cellClassNames} hidden lg:table-cell font-mono`,
onlyOnDetailed: true,
dataTestId: 'market-volume',
},
{
kind: ColumnKind.Fee,
value: <FeesCell feeFactors={market.fees.factors} />,
@ -337,6 +342,7 @@ export const columnsPositionMarkets = (
return onSelect(id);
}
};
const candleVolume = market.candles && calcCandleVolume(market.candles);
const selectMarketColumns: Column[] = [
{
kind: ColumnKind.Market,
@ -454,6 +460,19 @@ export const columnsPositionMarkets = (
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Volume,
value: candleVolume
? addDecimalsFormatNumber(
candleVolume.toString(),
market.positionDecimalPlaces,
2
)
: '-',
className: `${cellClassNames} hidden lg:table-cell font-mono`,
onlyOnDetailed: true,
dataTestId: 'market-volume',
},
{
kind: ColumnKind.TradingMode,
value:
@ -468,18 +487,6 @@ export const columnsPositionMarkets = (
onlyOnDetailed: true,
dataTestId: 'trading-mode-col',
},
{
kind: ColumnKind.Volume,
value:
market.data && market.data.indicativeVolume !== '0'
? addDecimalsFormatNumber(
market.data.indicativeVolume,
market.positionDecimalPlaces
)
: '-',
className: `${cellClassNames} hidden lg:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Fee,
value: <FeesCell feeFactors={market.fees.factors} />,

View File

@ -33,8 +33,8 @@ import type { OnCellClickHandler } from '../../components/select-market';
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
import { Last24hPriceChange } from '../../components/last-24h-price-change';
import { MarketMarkPrice } from '../../components/market-mark-price';
import { MarketVolume } from '../../components/market-volume';
import { MarketTradingModeComponent } from '../../components/market-trading-mode';
import { Last24hVolume } from '../../components/last-24h-volume';
const TradingViews = {
Candles: CandlesChartContainer,
@ -138,7 +138,7 @@ export const TradeMarketHeader = ({
</HeaderStat>
<MarketMarkPrice marketId={market.id} />
<Last24hPriceChange marketId={market.id} />
<MarketVolume marketId={market.id} />
<Last24hVolume marketId={market.id} />
<MarketTradingModeComponent marketId={market.id} onSelect={onSelect} />
{symbol ? (
<HeaderStat

View File

@ -1,9 +1,9 @@
import type { Market } from '@vegaprotocol/market-list';
import { totalFeesPercentage } from '@vegaprotocol/market-list';
import { t, formatNumberPercentage } from '@vegaprotocol/react-helpers';
import { formatNumberPercentage, t } from '@vegaprotocol/react-helpers';
import { Tooltip } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js';
import type { Market } from '@vegaprotocol/market-list';
export const FeesCell = ({
feeFactors,
}: {

View File

@ -69,3 +69,7 @@ export const calcCandleHigh = (candles: Candle[]): string | undefined => {
}, new BigNumber(0))
.toString();
};
export const calcCandleVolume = (candles: Candle[]): string | undefined =>
candles &&
candles.reduce((acc, c) => new BigNumber(acc).plus(c.volume).toString(), '0');

View File

@ -1,41 +1,42 @@
import {
OrderTimeInForce,
OrderStatus,
Side,
OrderType,
OrderTypeMapping,
OrderStatusMapping,
OrderTimeInForceMapping,
OrderRejectionReasonMapping,
} from '@vegaprotocol/types';
import {
addDecimal,
getDateTimeFormat,
t,
positiveClassNames,
negativeClassNames,
isNumeric,
negativeClassNames,
positiveClassNames,
t,
} from '@vegaprotocol/react-helpers';
import type {
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/ui-toolkit';
import {
OrderRejectionReasonMapping,
OrderStatus,
OrderStatusMapping,
OrderTimeInForce,
OrderTimeInForceMapping,
OrderType,
OrderTypeMapping,
Side,
} from '@vegaprotocol/types';
import {
AgGridDynamic as AgGrid,
Button,
Intent,
Link,
} from '@vegaprotocol/ui-toolkit';
import type { AgGridReact, AgGridReactProps } from 'ag-grid-react';
import { AgGridColumn } from 'ag-grid-react';
import { forwardRef, useState } from 'react';
import BigNumber from 'bignumber.js';
import { forwardRef, useState } from 'react';
import { useOrderCancel } from '../../order-hooks/use-order-cancel';
import { useOrderEdit } from '../../order-hooks/use-order-edit';
import { OrderEditDialog } from './order-edit-dialog';
import type { Order } from '../';
import { OrderFeedback } from '../order-feedback';
import { OrderEditDialog } from './order-edit-dialog';
import type {
VegaICellRendererParams,
VegaValueFormatterParams,
} from '@vegaprotocol/ui-toolkit';
import type { AgGridReact, AgGridReactProps } from 'ag-grid-react';
import type { Order } from '../';
type OrderListProps = AgGridReactProps;
export const OrderList = forwardRef<AgGridReact, OrderListProps>(
@ -113,6 +114,21 @@ export const OrderListTable = forwardRef<AgGridReact, OrderListTableProps>(
<AgGridColumn
headerName={t('Market')}
field="market.tradableInstrument.instrument.code"
cellRenderer={({
value,
data,
}: VegaICellRendererParams<
Order,
'market.tradableInstrument.instrument.code'
>) =>
data?.market?.id ? (
<Link href={`/markets/${data?.market?.id}`} target="_blank">
{value}
</Link>
) : (
value
)
}
/>
<AgGridColumn
headerName={t('Size')}