2022-12-02 00:33:30 +00:00
|
|
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
|
|
|
import { useEnvironment } from '@vegaprotocol/environment';
|
|
|
|
import { ButtonLink, Link } from '@vegaprotocol/ui-toolkit';
|
2023-02-28 18:56:29 +00:00
|
|
|
import { MarketProposalNotification } from '@vegaprotocol/proposals';
|
2023-05-18 11:22:54 +00:00
|
|
|
import type { Market } from '@vegaprotocol/markets';
|
2023-02-28 18:56:29 +00:00
|
|
|
import { getExpiryDate, getMarketExpiryDate } from '@vegaprotocol/utils';
|
|
|
|
import { t } from '@vegaprotocol/i18n';
|
2023-07-24 08:37:18 +00:00
|
|
|
import { Last24hPriceChange, Last24hVolume } from '@vegaprotocol/markets';
|
|
|
|
import { MarketState as State } from '@vegaprotocol/types';
|
2023-05-16 16:57:36 +00:00
|
|
|
import { HeaderStat } from '../../components/header';
|
2022-12-02 00:33:30 +00:00
|
|
|
import { MarketMarkPrice } from '../../components/market-mark-price';
|
2023-01-16 17:51:30 +00:00
|
|
|
import { HeaderStatMarketTradingMode } from '../../components/market-trading-mode';
|
2023-07-24 08:37:18 +00:00
|
|
|
import { MarketState } from '../../components/market-state';
|
2022-12-28 17:37:19 +00:00
|
|
|
import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
|
2022-12-02 00:33:30 +00:00
|
|
|
|
2023-07-24 08:37:18 +00:00
|
|
|
interface MarketHeaderStatsProps {
|
2023-02-09 14:20:31 +00:00
|
|
|
market: Market | null;
|
2022-12-02 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
2023-07-24 08:37:18 +00:00
|
|
|
export const MarketHeaderStats = ({ market }: MarketHeaderStatsProps) => {
|
2022-12-02 00:33:30 +00:00
|
|
|
const { VEGA_EXPLORER_URL } = useEnvironment();
|
|
|
|
const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore();
|
|
|
|
|
|
|
|
const asset = market?.tradableInstrument.instrument.product?.settlementAsset;
|
|
|
|
|
|
|
|
return (
|
2023-07-24 08:37:18 +00:00
|
|
|
<>
|
|
|
|
<HeaderStat
|
|
|
|
heading={t('Expiry')}
|
|
|
|
description={
|
|
|
|
market && (
|
|
|
|
<ExpiryTooltipContent
|
|
|
|
market={market}
|
|
|
|
explorerUrl={VEGA_EXPLORER_URL}
|
2023-05-16 16:57:36 +00:00
|
|
|
/>
|
2023-07-24 08:37:18 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
testId="market-expiry"
|
|
|
|
>
|
|
|
|
<ExpiryLabel market={market} />
|
|
|
|
</HeaderStat>
|
|
|
|
<HeaderStat heading={t('Price')} testId="market-price">
|
|
|
|
<MarketMarkPrice
|
|
|
|
marketId={market?.id}
|
|
|
|
decimalPlaces={market?.decimalPlaces}
|
|
|
|
/>
|
|
|
|
</HeaderStat>
|
|
|
|
<HeaderStat heading={t('Change (24h)')} testId="market-change">
|
|
|
|
<Last24hPriceChange
|
|
|
|
marketId={market?.id}
|
|
|
|
decimalPlaces={market?.decimalPlaces}
|
|
|
|
/>
|
|
|
|
</HeaderStat>
|
|
|
|
<HeaderStat heading={t('Volume (24h)')} testId="market-volume">
|
|
|
|
<Last24hVolume
|
|
|
|
marketId={market?.id}
|
|
|
|
positionDecimalPlaces={market?.positionDecimalPlaces}
|
|
|
|
/>
|
|
|
|
</HeaderStat>
|
|
|
|
<HeaderStatMarketTradingMode
|
|
|
|
marketId={market?.id}
|
|
|
|
initialTradingMode={market?.tradingMode}
|
|
|
|
/>
|
|
|
|
<MarketState market={market} />
|
|
|
|
{asset ? (
|
|
|
|
<HeaderStat
|
|
|
|
heading={t('Settlement asset')}
|
|
|
|
testId="market-settlement-asset"
|
|
|
|
>
|
|
|
|
<div>
|
|
|
|
<ButtonLink
|
|
|
|
onClick={(e) => {
|
|
|
|
openAssetDetailsDialog(asset.id, e.target as HTMLElement);
|
|
|
|
}}
|
2022-12-02 00:33:30 +00:00
|
|
|
>
|
2023-07-24 08:37:18 +00:00
|
|
|
{asset.symbol}
|
|
|
|
</ButtonLink>
|
|
|
|
</div>
|
|
|
|
</HeaderStat>
|
|
|
|
) : null}
|
|
|
|
<MarketLiquiditySupplied
|
|
|
|
marketId={market?.id}
|
|
|
|
assetDecimals={asset?.decimals || 0}
|
|
|
|
/>
|
|
|
|
<MarketProposalNotification marketId={market?.id} />
|
|
|
|
</>
|
2022-12-02 00:33:30 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
type ExpiryLabelProps = {
|
2023-02-09 14:20:31 +00:00
|
|
|
market: Market | null;
|
2022-12-02 00:33:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
|
2023-01-26 09:58:39 +00:00
|
|
|
const content =
|
|
|
|
market && market.tradableInstrument.instrument.metadata.tags
|
|
|
|
? getExpiryDate(
|
|
|
|
market.tradableInstrument.instrument.metadata.tags,
|
|
|
|
market.marketTimestamps.close,
|
|
|
|
market.state
|
|
|
|
)
|
|
|
|
: '-';
|
2022-12-02 00:33:30 +00:00
|
|
|
return <div data-testid="trading-expiry">{content}</div>;
|
|
|
|
};
|
|
|
|
|
|
|
|
type ExpiryTooltipContentProps = {
|
2023-02-09 14:20:31 +00:00
|
|
|
market: Market;
|
2022-12-02 00:33:30 +00:00
|
|
|
explorerUrl?: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
const ExpiryTooltipContent = ({
|
|
|
|
market,
|
|
|
|
explorerUrl,
|
|
|
|
}: ExpiryTooltipContentProps) => {
|
|
|
|
if (market?.marketTimestamps.close === null) {
|
|
|
|
const oracleId =
|
|
|
|
market.tradableInstrument.instrument.product
|
|
|
|
.dataSourceSpecForTradingTermination?.id;
|
|
|
|
|
2023-01-16 17:36:06 +00:00
|
|
|
const metadataExpiryDate = getMarketExpiryDate(
|
|
|
|
market.tradableInstrument.instrument.metadata.tags
|
|
|
|
);
|
|
|
|
|
|
|
|
const isExpired =
|
|
|
|
metadataExpiryDate &&
|
|
|
|
Date.now() - metadataExpiryDate.valueOf() > 0 &&
|
|
|
|
(market.state === State.STATE_TRADING_TERMINATED ||
|
|
|
|
market.state === State.STATE_SETTLED);
|
|
|
|
|
2022-12-02 00:33:30 +00:00
|
|
|
return (
|
2023-01-16 17:36:06 +00:00
|
|
|
<section data-testid="expiry-tooltip">
|
2022-12-02 00:33:30 +00:00
|
|
|
<p className="mb-2">
|
|
|
|
{t(
|
|
|
|
'This market expires when triggered by its oracle, not on a set date.'
|
|
|
|
)}
|
|
|
|
</p>
|
2023-01-16 17:36:06 +00:00
|
|
|
{metadataExpiryDate && !isExpired && (
|
|
|
|
<p className="mb-2">
|
|
|
|
{t(
|
|
|
|
'This timestamp is user curated metadata and does not drive any on-chain functionality.'
|
|
|
|
)}
|
|
|
|
</p>
|
|
|
|
)}
|
2022-12-02 00:33:30 +00:00
|
|
|
{explorerUrl && oracleId && (
|
|
|
|
<Link href={`${explorerUrl}/oracles#${oracleId}`} target="_blank">
|
|
|
|
{t('View oracle specification')}
|
|
|
|
</Link>
|
|
|
|
)}
|
|
|
|
</section>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
};
|