/* eslint-disable @typescript-eslint/no-explicit-any */
import {
addDecimalsFormatNumber,
formatNumberPercentage,
PriceCell,
signedNumberCssClass,
t,
} from '@vegaprotocol/react-helpers';
import {
AuctionTrigger,
AuctionTriggerMapping,
MarketTradingMode,
MarketTradingModeMapping,
} from '@vegaprotocol/types';
import { PriceCellChange, Sparkline, Tooltip } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js';
import Link from 'next/link';
import {
calcCandleHigh,
calcCandleLow,
totalFees,
} from '@vegaprotocol/market-list';
import type { CandleClose } from '@vegaprotocol/types';
import type {
MarketWithData,
MarketWithCandles,
} from '@vegaprotocol/market-list';
import isNil from 'lodash/isNil';
type Market = MarketWithData & MarketWithCandles;
export const cellClassNames = 'py-1 first:text-left text-right';
const FeesInfo = () => {
return (
{t(
'Fees are paid by market takers on aggressive orders only. The fee displayed is made up of:'
)}
- {t('An infrastructure fee')}
- {t('A liquidity provision fee')}
- {t('A maker fee')}
}
>
{t('Taker fee')}
);
};
export enum ColumnKind {
Market,
LastPrice,
Change24,
Asset,
Sparkline,
High24,
Low24,
TradingMode,
Volume,
Fee,
Position,
FullName,
}
export interface Column {
kind: ColumnKind;
value: string | React.ReactNode;
className: string;
onlyOnDetailed: boolean;
dataTestId?: string;
}
const headers: Column[] = [
{
kind: ColumnKind.Market,
value: t('Market'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.LastPrice,
value: t('Last price'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Change24,
value: t('Change (24h)'),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Sparkline,
value: t(''),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Asset,
value: t('Settlement asset'),
className: `${cellClassNames} hidden sm:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.High24,
value: t('24h high'),
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Low24,
value: t('24h low'),
className: `${cellClassNames} hidden xl: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: ,
className: `${cellClassNames} hidden xl:table-cell`,
onlyOnDetailed: true,
},
];
export const columnHeadersPositionMarkets: Column[] = [
...headers,
{
kind: ColumnKind.Position,
value: t('Position'),
className: `${cellClassNames} hidden xxl:table-cell`,
onlyOnDetailed: true,
},
];
export const columnHeaders: Column[] = [
...headers,
{
kind: ColumnKind.FullName,
value: t('Full name'),
className: `${cellClassNames} hidden xxl:block`,
onlyOnDetailed: true,
},
];
export type OnCellClickHandler = (
e: React.MouseEvent,
kind: ColumnKind,
value: string
) => void;
export const columns = (
market: Market,
onSelect: (id: string) => void,
onCellClick: OnCellClickHandler
) => {
const candlesClose = market.candles
?.map((candle) => candle?.close)
.filter((c: string | undefined): c is CandleClose => !isNil(c));
const candleLow = market.candles && calcCandleLow(market.candles);
const candleHigh = market.candles && calcCandleHigh(market.candles);
const selectMarketColumns: Column[] = [
{
kind: ColumnKind.Market,
value: market.tradableInstrument.instrument.code,
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.LastPrice,
value: market.data?.markPrice ? (
) : (
'-'
),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Change24,
value: candlesClose && (
),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Sparkline,
value: market.candles && (
Number(c)) || []}
/>
),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: false && candlesClose,
},
{
kind: ColumnKind.Asset,
value: (
),
dataTestId: 'settlement-asset',
className: `${cellClassNames} hidden sm:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.High24,
value: candleHigh ? (
) : (
'-'
),
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Low24,
value: candleLow ? (
) : (
'-'
),
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.TradingMode,
value:
market.tradingMode ===
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data?.trigger &&
market.data.trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED
? `${MarketTradingModeMapping[market.tradingMode]}
- ${AuctionTriggerMapping[market.data.trigger]}`
: MarketTradingModeMapping[market.tradingMode],
className: `${cellClassNames} hidden lg:table-cell`,
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: ,
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
dataTestId: 'taker-fee',
},
{
kind: ColumnKind.FullName,
value: market.tradableInstrument.instrument.name,
className: `${cellClassNames} hidden xxl:block`,
onlyOnDetailed: true,
dataTestId: 'market-name',
},
];
return selectMarketColumns;
};
export const columnsPositionMarkets = (
market: Market,
onSelect: (id: string) => void,
openVolume?: string,
onCellClick?: OnCellClickHandler
) => {
const candlesClose = market.candles
?.map((candle) => candle?.close)
.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,
id: string
) => {
if (event.key === 'Enter' && onSelect) {
return onSelect(id);
}
};
const selectMarketColumns: Column[] = [
{
kind: ColumnKind.Market,
value: (
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid,jsx-a11y/no-static-element-interactions */}
handleKeyPress(event, market.id)}
onClick={() => {
onSelect(market.id);
}}
data-testid={`market-link-${market.id}`}
>
{market.tradableInstrument.instrument.code}
),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.LastPrice,
value: market.data?.markPrice ? (
) : (
'-'
),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Change24,
value: candlesClose && (
),
className: cellClassNames,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Sparkline,
value: candlesClose && (
Number(c))}
/>
),
className: `${cellClassNames} hidden lg:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.Asset,
value: (
),
className: `${cellClassNames} hidden sm:table-cell`,
onlyOnDetailed: false,
},
{
kind: ColumnKind.High24,
value: candleHigh ? (
) : (
'-'
),
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Low24,
value: candleLow ? (
) : (
'-'
),
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.TradingMode,
value:
market.tradingMode ===
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data?.trigger &&
market.data.trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED
? `${MarketTradingModeMapping[market.tradingMode]}
- ${AuctionTriggerMapping[market.data.trigger]}`
: MarketTradingModeMapping[market.tradingMode],
className: `${cellClassNames} hidden lg:table-cell`,
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: ,
className: `${cellClassNames} hidden xl:table-cell font-mono`,
onlyOnDetailed: true,
},
{
kind: ColumnKind.Position,
value: (
{openVolume}
),
className: `${cellClassNames} hidden xxl:table-cell font-mono`,
onlyOnDetailed: true,
},
];
return selectMarketColumns;
};
const FeesCell = ({
feeFactors,
}: {
feeFactors: Market['fees']['factors'];
}) => (
}>
{totalFees(feeFactors) ?? '-'}
);
export const FeesBreakdown = ({
feeFactors,
}: {
feeFactors?: Market['fees']['factors'];
}) => {
if (!feeFactors) return null;
return (
- {t('Infrastructure fee')}
-
{formatNumberPercentage(
new BigNumber(feeFactors.infrastructureFee).times(100)
)}
- {t('Liquidity fee')}
-
{formatNumberPercentage(
new BigNumber(feeFactors.liquidityFee).times(100)
)}
- {t('Maker fee')}
-
{formatNumberPercentage(new BigNumber(feeFactors.makerFee).times(100))}
- {t('Total fees')}
- {totalFees(feeFactors)}
);
};