import 'allotment/dist/style.css'; import { DealTicketContainer, MarketInfoContainer, } from '@vegaprotocol/deal-ticket'; import { OrderbookContainer } from '@vegaprotocol/market-depth'; import { SelectMarketPopover } from '@vegaprotocol/market-list'; import { OrderListContainer } from '@vegaprotocol/orders'; import { FillsContainer } from '@vegaprotocol/fills'; import { PositionsContainer } from '@vegaprotocol/positions'; import { addDecimalsFormatNumber, getDateFormat, t, } from '@vegaprotocol/react-helpers'; import { TradesContainer } from '@vegaprotocol/trades'; import { AuctionTrigger, AuctionTriggerMapping, MarketTradingMode, MarketTradingModeMapping, } from '@vegaprotocol/types'; import { LayoutPriority } from 'allotment'; import classNames from 'classnames'; import AutoSizer from 'react-virtualized-auto-sizer'; import { useState } from 'react'; import type { ReactNode } from 'react'; import type { Market_market } from './__generated__/Market'; import type { CandleClose } from '@vegaprotocol/types'; import { useGlobalStore } from '../../stores'; import { AccountsContainer } from '@vegaprotocol/accounts'; import { DepthChartContainer } from '@vegaprotocol/market-depth'; import { CandlesChartContainer } from '@vegaprotocol/candles-chart'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useEnvironment } from '@vegaprotocol/environment'; import { Tab, Tabs, PriceCellChange, Link, Tooltip, ResizableGrid, ButtonLink, ResizableGridPanel, } from '@vegaprotocol/ui-toolkit'; import { TradingModeTooltip } from '../../components/trading-mode-tooltip'; const TradingViews = { Candles: CandlesChartContainer, Depth: DepthChartContainer, Ticket: DealTicketContainer, Info: MarketInfoContainer, Orderbook: OrderbookContainer, Trades: TradesContainer, Positions: PositionsContainer, Orders: OrderListContainer, Collateral: AccountsContainer, Fills: FillsContainer, }; type TradingView = keyof typeof TradingViews; type ExpiryLabelProps = { market: Market_market; }; const ExpiryLabel = ({ market }: ExpiryLabelProps) => { if (market.marketTimestamps.close === null) { return <>{t('Not time-based')}; } const closeDate = new Date(market.marketTimestamps.close); const isExpired = Date.now() - closeDate.valueOf() > 0; const expiryDate = getDateFormat().format(closeDate); return <>{`${isExpired ? `${t('Expired')} ` : ''} ${expiryDate}`}; }; type ExpiryTooltipContentProps = { market: Market_market; explorerUrl?: string; }; const ExpiryTooltipContent = ({ market, explorerUrl, }: ExpiryTooltipContentProps) => { if (market.marketTimestamps.close === null) { const oracleId = market.tradableInstrument.instrument.product .oracleSpecForTradingTermination?.id; return ( <>

{t( 'This market expires when triggered by its oracle, not on a set date.' )}

{explorerUrl && oracleId && ( {t('View oracle specification')} )} ); } return null; }; interface TradeMarketHeaderProps { market: Market_market; } export const TradeMarketHeader = ({ market }: TradeMarketHeaderProps) => { const { VEGA_EXPLORER_URL } = useEnvironment(); const { setAssetDetailsDialogOpen, setAssetDetailsDialogSymbol } = useAssetDetailsDialogStore(); const { update } = useGlobalStore((store) => ({ update: store.update, })); const onSelect = (marketId: string) => { if (marketId && marketId !== marketId) { update({ marketId }); } }; const candlesClose: string[] = (market?.candles || []) .map((candle) => candle?.close) .filter((c): c is CandleClose => c !== null); const hasExpiry = market.marketTimestamps.close !== null; const symbol = market.tradableInstrument.instrument.product?.settlementAsset?.symbol; const itemClass = 'min-w-min w-[120px] whitespace-nowrap pb-3 px-4 border-l border-neutral-300 dark:border-neutral-700'; const itemHeading = 'text-neutral-400'; return (
{t('Expiry')}
} >
{t('Change (24h)')}
{t('Volume')}
{market.data && market.data.indicativeVolume !== '0' ? addDecimalsFormatNumber( market.data.indicativeVolume, market.positionDecimalPlaces ) : '-'}
{t('Trading mode')}
} >
{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]}
{t('Price')}
{market.data && market.data.markPrice !== '0' ? addDecimalsFormatNumber( market.data.markPrice, market.decimalPlaces ) : '-'}
{symbol && (
{t('Settlement asset')}
{ setAssetDetailsDialogOpen(true); setAssetDetailsDialogSymbol(symbol); }} > {symbol}
)}
); }; interface TradeGridProps { market: Market_market; } export const TradeGrid = ({ market }: TradeGridProps) => { return (
); }; interface TradeGridChildProps { children: ReactNode; } const TradeGridChild = ({ children }: TradeGridChildProps) => { return (
{({ width, height }) => (
{children}
)}
); }; interface TradePanelsProps { market: Market_market; } export const TradePanels = ({ market }: TradePanelsProps) => { const [view, setView] = useState('Candles'); const renderView = () => { const Component = TradingViews[view]; if (!Component) { throw new Error(`No component for view: ${view}`); } return ; }; return (
{({ width, height }) => (
{renderView()}
)}
{Object.keys(TradingViews).map((key) => { const isActive = view === key; const className = classNames('p-4 min-w-[100px] capitalize', { 'text-black dark:text-vega-yellow': isActive, 'bg-neutral-200 dark:bg-neutral-800': isActive, }); return ( ); })}
); };