vega-frontend-monorepo/apps/trading/client-pages/market/market.tsx

184 lines
4.6 KiB
TypeScript

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import debounce from 'lodash/debounce';
import { addDecimalsFormatNumber, titlefy } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import {
useDataProvider,
useThrottledDataProvider,
} from '@vegaprotocol/react-helpers';
import { AsyncRenderer, ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
import type {
MarketData,
MarketDataUpdateFieldsFragment,
} from '@vegaprotocol/market-list';
import { marketProvider, marketDataProvider } from '@vegaprotocol/market-list';
import { useGlobalStore, usePageTitleStore } from '../../stores';
import { TradeGrid, TradePanels } from './trade-grid';
import { useNavigate, useParams } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
const calculatePrice = (markPrice?: string, decimalPlaces?: number) => {
return markPrice && decimalPlaces
? addDecimalsFormatNumber(markPrice, decimalPlaces)
: '-';
};
const TitleUpdater = ({
marketId,
marketName,
decimalPlaces,
}: {
marketId?: string;
marketName?: string;
decimalPlaces?: number;
}) => {
const pageTitle = usePageTitleStore((store) => store.pageTitle);
const updateTitle = usePageTitleStore((store) => store.updateTitle);
const { data: marketData } = useThrottledDataProvider<
MarketData,
MarketDataUpdateFieldsFragment
>(
{
dataProvider: marketDataProvider,
variables: useMemo(() => ({ marketId }), [marketId]),
skip: !marketId,
},
1000
);
useEffect(() => {
const marketPrice = calculatePrice(marketData?.markPrice, decimalPlaces);
if (marketName) {
const newPageTitle = titlefy([marketName, marketPrice]);
if (pageTitle !== newPageTitle) {
updateTitle(newPageTitle);
}
}
}, [
decimalPlaces,
marketName,
marketData?.markPrice,
pageTitle,
updateTitle,
]);
return null;
};
export const MarketPage = () => {
const { marketId } = useParams();
const navigate = useNavigate();
const { w } = useWindowSize();
const update = useGlobalStore((store) => store.update);
const lastMarketId = useGlobalStore((store) => store.marketId);
const onSelect = useCallback(
(id: string) => {
if (id && id !== marketId) {
navigate(Links[Routes.MARKET](id));
}
},
[marketId, navigate]
);
const { data, error, loading } = useDataProvider({
dataProvider: marketProvider,
variables: { marketId: marketId || '' },
skip: !marketId,
});
useEffect(() => {
if (data?.id && data.id !== lastMarketId) {
update({ marketId: data.id });
}
}, [update, lastMarketId, data?.id]);
const tradeView = useMemo(() => {
if (w > 960) {
return (
<TradeGrid
market={data}
onSelect={onSelect}
pinnedAsset={
data?.tradableInstrument.instrument.product.settlementAsset
}
/>
);
}
return (
<TradePanels
market={data}
onSelect={onSelect}
onClickCollateral={() => navigate('/portfolio')}
/>
);
}, [w, data, onSelect, navigate]);
if (!data && marketId) {
return (
<Splash>
<span className="flex flex-col items-center gap-2">
<p className="text-sm justify-center">
{t('This market URL is not available any more.')}
</p>
<p className="text-sm justify-center">
{t(`Please choose another market from the`)}{' '}
<ExternalLink onClick={() => navigate(Links[Routes.MARKETS]())}>
market list
</ExternalLink>
</p>
</span>
</Splash>
);
}
return (
<AsyncRenderer
loading={loading}
error={error}
data={data || undefined}
noDataCondition={(data) => false}
>
<TitleUpdater
marketId={data?.id}
marketName={data?.tradableInstrument.instrument.name}
decimalPlaces={data?.decimalPlaces}
/>
{tradeView}
</AsyncRenderer>
);
};
const useWindowSize = () => {
const [windowSize, setWindowSize] = useState(() => {
if (typeof window !== 'undefined') {
return {
w: window.innerWidth,
h: window.innerHeight,
};
}
// Something sensible for server rendered page
return {
w: 1200,
h: 900,
};
});
useEffect(() => {
const handleResize = debounce(({ target }) => {
setWindowSize({
w: target.innerWidth,
h: target.innerHeight,
});
}, 300);
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return windowSize;
};