import { DealTicketContainer } from '@vegaprotocol/deal-ticket'; import { MarketInfoContainer, getExpiryDate } from '@vegaprotocol/market-info'; import { OrderbookContainer } from '@vegaprotocol/market-depth'; import { OrderListContainer } from '@vegaprotocol/orders'; import { FillsContainer } from '@vegaprotocol/fills'; import { PositionsContainer } from '@vegaprotocol/positions'; import { TradesContainer } from '@vegaprotocol/trades'; import { LayoutPriority } from 'allotment'; import classNames from 'classnames'; import AutoSizer from 'react-virtualized-auto-sizer'; import { memo, useState } from 'react'; import type { ReactNode, ComponentProps } from 'react'; import { DepthChartContainer } from '@vegaprotocol/market-depth'; import { CandlesChartContainer } from '@vegaprotocol/candles-chart'; import { Tab, Tabs, ResizableGrid, ResizableGridPanel, ButtonLink, Link, Splash, } from '@vegaprotocol/ui-toolkit'; import { t } from '@vegaprotocol/react-helpers'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useEnvironment } from '@vegaprotocol/environment'; import { Header, HeaderStat } from '../../components/header'; import { AccountsContainer } from '../../components/accounts-container'; import { ColumnKind, SelectMarketPopover, } from '../../components/select-market'; 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 { MarketTradingModeComponent } from '../../components/market-trading-mode'; import { Last24hVolume } from '../../components/last-24h-volume'; import { MarketProposalNotification } from '@vegaprotocol/governance'; import { VegaWalletContainer } from '../../components/vega-wallet-container'; const NO_MARKET = t('No market'); type MarketDependantView = | typeof CandlesChartContainer | typeof DepthChartContainer | typeof DealTicketContainer | typeof MarketInfoContainer | typeof OrderbookContainer | typeof TradesContainer; type MarketDependantViewProps = ComponentProps; const requiresMarket = (View: MarketDependantView) => { const WrappedComponent = (props: MarketDependantViewProps) => props.marketId ? : {NO_MARKET}; WrappedComponent.displayName = `RequiresMarket(${View.name})`; return WrappedComponent; }; const TradingViews = { Candles: requiresMarket(CandlesChartContainer), Depth: requiresMarket(DepthChartContainer), Ticket: requiresMarket(DealTicketContainer), Info: requiresMarket(MarketInfoContainer), Orderbook: requiresMarket(OrderbookContainer), Trades: requiresMarket(TradesContainer), Positions: PositionsContainer, Orders: OrderListContainer, Collateral: AccountsContainer, Fills: FillsContainer, }; type TradingView = keyof typeof TradingViews; type ExpiryLabelProps = { market: SingleMarketFieldsFragment | null; }; const ExpiryLabel = ({ market }: ExpiryLabelProps) => { const content = market ? getExpiryDate(market) : '-'; return
{content}
; }; type ExpiryTooltipContentProps = { market: SingleMarketFieldsFragment; explorerUrl?: string; }; const ExpiryTooltipContent = ({ market, explorerUrl, }: ExpiryTooltipContentProps) => { if (market?.marketTimestamps.close === null) { const oracleId = market.tradableInstrument.instrument.product .dataSourceSpecForTradingTermination?.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: SingleMarketFieldsFragment | null; onSelect: (marketId: string) => void; } export const TradeMarketHeader = ({ market, onSelect, }: TradeMarketHeaderProps) => { const { VEGA_EXPLORER_URL } = useEnvironment(); const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore(); const asset = market?.tradableInstrument.instrument.product?.settlementAsset; const onCellClick: OnCellClickHandler = (e, kind, value) => { if (value && kind === ColumnKind.Asset) { openAssetDetailsDialog(value, e.target as HTMLElement); } }; return (
} > ) } testId="market-expiry" > {asset ? (
{ openAssetDetailsDialog(asset.id, e.target as HTMLElement); }} > {asset.symbol}
) : null}
); }; interface TradeGridProps { market: SingleMarketFieldsFragment | null; onSelect: (marketId: string) => void; } const MainGrid = ({ marketId, onSelect, }: { marketId: string; onSelect?: (marketId: string) => void; }) => ( { onSelect?.(id); }} /> ); const MainGridWrapped = memo(MainGrid); export const TradeGrid = ({ market, onSelect }: TradeGridProps) => { return (
); }; interface TradeGridChildProps { children: ReactNode; } const TradeGridChild = ({ children }: TradeGridChildProps) => { return (
{({ width, height }) =>
{children}
}
); }; interface TradePanelsProps { market: SingleMarketFieldsFragment | null; onSelect: (marketId: string) => void; } export const TradePanels = ({ market, onSelect }: TradePanelsProps) => { const [view, setView] = useState('Candles'); const renderView = () => { const Component = memo<{ marketId: string; onSelect: (marketId: string) => void; }>(TradingViews[view]); if (!Component) { throw new Error(`No component for view: ${view}`); } if (!market) return {NO_MARKET}; 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 ( ); })}
); };