feat(trading): show successor banner if market is settled or successor market exists (#5056)

Co-authored-by: bwallacee <ben@vega.xyz>
This commit is contained in:
Bartłomiej Głownia 2023-10-18 14:48:52 +02:00 committed by GitHub
parent abf84b9d45
commit 236e35a92b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 84 additions and 59 deletions

View File

@ -21,6 +21,7 @@ const market = {
} as unknown as Market;
let mockDataSuccessorMarket: PartialDeep<Market> | null = null;
let mockDataMarketState: Market['state'] | null = null;
jest.mock('@vegaprotocol/data-provider', () => ({
...jest.requireActual('@vegaprotocol/data-provider'),
useDataProvider: jest.fn().mockImplementation((args) => {
@ -43,6 +44,12 @@ jest.mock('@vegaprotocol/utils', () => ({
let mockCandles = {};
jest.mock('@vegaprotocol/markets', () => ({
...jest.requireActual('@vegaprotocol/markets'),
useMarketState: (marketId: string) =>
marketId
? {
data: mockDataMarketState,
}
: { data: undefined },
useSuccessorMarket: (marketId: string) =>
marketId
? {
@ -81,30 +88,6 @@ describe('MarketSuccessorBanner', () => {
});
expect(container).toBeEmptyDOMElement();
});
it('successor market not in continuous mode', () => {
mockDataSuccessorMarket = {
...mockDataSuccessorMarket,
tradingMode: Types.MarketTradingMode.TRADING_MODE_NO_TRADING,
};
const { container } = render(<MarketSuccessorBanner market={market} />, {
wrapper: MockedProvider,
});
expect(container).toBeEmptyDOMElement();
expect(allUtils.getMarketExpiryDate).toHaveBeenCalled();
});
it('successor market is not active', () => {
mockDataSuccessorMarket = {
...mockDataSuccessorMarket,
state: Types.MarketState.STATE_PENDING,
};
const { container } = render(<MarketSuccessorBanner market={market} />, {
wrapper: MockedProvider,
});
expect(container).toBeEmptyDOMElement();
expect(allUtils.getMarketExpiryDate).toHaveBeenCalled();
});
});
describe('should be displayed', () => {
@ -120,6 +103,17 @@ describe('MarketSuccessorBanner', () => {
).toHaveAttribute('href', '/#/markets/successorMarketID');
});
it('no successor market data, market settled', () => {
mockDataSuccessorMarket = null;
mockDataMarketState = Types.MarketState.STATE_SETTLED;
render(<MarketSuccessorBanner market={market} />, {
wrapper: MockedProvider,
});
expect(
screen.getByText('This market has been settled')
).toBeInTheDocument();
});
it('should display optionally successor volume', () => {
mockDataSuccessorMarket = {
...mockDataSuccessorMarket,
@ -137,7 +131,9 @@ describe('MarketSuccessorBanner', () => {
render(<MarketSuccessorBanner market={market} />, {
wrapper: MockedProvider,
});
expect(screen.getByText('has 101.367 24h vol.')).toBeInTheDocument();
expect(
screen.getByText('has a 24h trading volume of 101.367')
).toBeInTheDocument();
});
it('should display optionally duration', () => {

View File

@ -4,6 +4,7 @@ import type { Market } from '@vegaprotocol/markets';
import {
calcCandleVolume,
useCandles,
useMarketState,
useSuccessorMarket,
} from '@vegaprotocol/markets';
import {
@ -29,7 +30,9 @@ export const MarketSuccessorBanner = ({
}: {
market: Market | null;
}) => {
const { data: successorData } = useSuccessorMarket(market?.id);
const { data: marketState } = useMarketState(market?.id);
const isSettled = marketState === Types.MarketState.STATE_SETTLED;
const { data: successorData, loading } = useSuccessorMarket(market?.id);
const [visible, setVisible] = useState(true);
@ -45,11 +48,6 @@ export const MarketSuccessorBanner = ({
? intervalToDuration({ start: new Date(), end: expiry })
: null;
const isInContinuesMode =
successorData?.state === Types.MarketState.STATE_ACTIVE &&
successorData?.tradingMode ===
Types.MarketTradingMode.TRADING_MODE_CONTINUOUS;
const { oneDayCandles } = useCandles({
marketId: successorData?.id,
});
@ -66,7 +64,7 @@ export const MarketSuccessorBanner = ({
)
: null;
if (isInContinuesMode && visible) {
if (!loading && (isSettled || successorData) && visible) {
return (
<NotificationBanner
intent={Intent.Primary}
@ -74,34 +72,47 @@ export const MarketSuccessorBanner = ({
setVisible(false);
}}
>
<div className="uppercase mb-1">
{t('This market has been succeeded')}
</div>
<div>
{duration && (
<span>
{t('This market expires in %s.', [
formatDuration(duration, {
format: [
'years',
'months',
'weeks',
'days',
'hours',
'minutes',
],
}),
])}
</span>
)}{' '}
{t('The successor market')}{' '}
<ExternalLink href={`/#/markets/${successorData?.id}`}>
{successorData?.tradableInstrument.instrument.name}
</ExternalLink>
{successorVolume && (
<span> {t('has %s 24h vol.', [successorVolume])}</span>
)}
<div className="uppercase">
{successorData
? t('This market has been succeeded')
: t('This market has been settled')}
</div>
{(duration || successorData) && (
<div className="mt-1">
{duration && (
<span>
{t('This market expires in %s.', [
formatDuration(duration, {
format: [
'years',
'months',
'weeks',
'days',
'hours',
'minutes',
],
}),
])}
</span>
)}
{successorData && (
<>
{' '}
{t('The successor market')}
{!successorVolume ? ' is ' : ' '}
<ExternalLink href={`/#/markets/${successorData?.id}`}>
{successorData?.tradableInstrument.instrument.name}
</ExternalLink>
{successorVolume && (
<span>
{' '}
{t('has a 24h trading volume of %s', [successorVolume])}
</span>
)}
</>
)}
</div>
)}
</NotificationBanner>
);
}

View File

@ -126,6 +126,16 @@ export const marketTradingModeProvider = makeDerivedDataProvider<
(parts[0] as ReturnType<typeof getData>)?.marketTradingMode
);
export const marketStateProvider = makeDerivedDataProvider<
MarketDataFieldsFragment['marketState'] | undefined,
never,
MarketDataQueryVariables
>(
[marketDataProvider],
(parts, variables, prevData) =>
(parts[0] as ReturnType<typeof getData>)?.marketState
);
export const fundingRateProvider = makeDerivedDataProvider<
string,
never,
@ -176,3 +186,11 @@ export const useMarketTradingMode = (marketId?: string, skip?: boolean) => {
skip: skip || !marketId,
});
};
export const useMarketState = (marketId?: string, skip?: boolean) => {
return useDataProvider({
dataProvider: marketStateProvider,
variables: { marketId: marketId || '' },
skip: skip || !marketId,
});
};