feat: 1661 add market expiry date from metadata tags to market info and market header (#1739)

This commit is contained in:
m.ray 2022-10-14 08:09:11 +01:00 committed by GitHub
parent d674162e38
commit fe472acfe9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 92 additions and 56 deletions

View File

@ -9,7 +9,6 @@ import classNames from 'classnames';
import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket'; import type { DealTicketMarketFragment } from '@vegaprotocol/deal-ticket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet'; import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { SIDE_NAMES } from './side-selector'; import { SIDE_NAMES } from './side-selector';
import SimpleMarketExpires from '../simple-market-list/simple-market-expires';
import { gql, useQuery } from '@apollo/client'; import { gql, useQuery } from '@apollo/client';
import type { import type {
MarketTags, MarketTags,
@ -17,6 +16,7 @@ import type {
} from './__generated__/MarketTags'; } from './__generated__/MarketTags';
import { DealTicketEstimates } from './deal-ticket-estimates'; import { DealTicketEstimates } from './deal-ticket-estimates';
import { Side } from '@vegaprotocol/types'; import { Side } from '@vegaprotocol/types';
import { MarketExpires } from '@vegaprotocol/market-info';
export const MARKET_TAGS_QUERY = gql` export const MARKET_TAGS_QUERY = gql`
query MarketTags($marketId: ID!) { query MarketTags($marketId: ID!) {
@ -86,7 +86,7 @@ export default ({
<div> <div>
{tagsData?.market?.tradableInstrument.instrument.metadata {tagsData?.market?.tradableInstrument.instrument.metadata
.tags && ( .tags && (
<SimpleMarketExpires <MarketExpires
tags={ tags={
tagsData?.market.tradableInstrument.instrument.metadata.tags tagsData?.market.tradableInstrument.instrument.metadata.tags
} }

View File

@ -1,34 +0,0 @@
import React from 'react';
import { format, isValid, parseISO } from 'date-fns';
import { EXPIRE_DATE_FORMAT } from '../../constants';
const SimpleMarketExpires = ({
tags,
}: {
tags?: ReadonlyArray<string> | null;
}) => {
if (tags) {
const dateFound = tags.reduce<Date | null>((agg, tag) => {
const parsed = parseISO(
(tag.match(/^settlement.*:/) &&
tag
.split(':')
.filter((item, i) => i)
.join(':')) as string
);
if (isValid(parsed)) {
agg = parsed;
}
return agg;
}, null);
return dateFound ? (
<div className="p-2 text-ui-small border border-pink text-pink inline-block">{`${format(
dateFound as Date,
EXPIRE_DATE_FORMAT
)}`}</div>
) : null;
}
return null;
};
export default SimpleMarketExpires;

View File

@ -1,6 +1,6 @@
import classNames from 'classnames'; import classNames from 'classnames';
import SimpleMarketExpires from './simple-market-expires';
import type { Market } from '@vegaprotocol/market-list'; import type { Market } from '@vegaprotocol/market-list';
import { MarketExpires } from '@vegaprotocol/market-info';
interface Props { interface Props {
market: Market; market: Market;
@ -19,7 +19,7 @@ const MarketNameRenderer = ({ market, isMobile }: Props) => {
{isMobile {isMobile
? market.tradableInstrument.instrument.code ? market.tradableInstrument.instrument.code
: market.tradableInstrument.instrument.name}{' '} : market.tradableInstrument.instrument.name}{' '}
<SimpleMarketExpires <MarketExpires
tags={market.tradableInstrument.instrument.metadata.tags} tags={market.tradableInstrument.instrument.metadata.tags}
/> />
</div> </div>

View File

@ -3,7 +3,6 @@ import { t } from '@vegaprotocol/react-helpers';
import type { Market } from '@vegaprotocol/market-list'; import type { Market } from '@vegaprotocol/market-list';
export const DATE_FORMAT = 'dd MMMM yyyy HH:mm'; export const DATE_FORMAT = 'dd MMMM yyyy HH:mm';
export const EXPIRE_DATE_FORMAT = 'MMM dd';
export const TRADABLE_STATES = { export const TRADABLE_STATES = {
[MarketState.STATE_ACTIVE]: true, [MarketState.STATE_ACTIVE]: true,

View File

@ -1,5 +1,5 @@
import { DealTicketContainer } from '@vegaprotocol/deal-ticket'; import { DealTicketContainer } from '@vegaprotocol/deal-ticket';
import { MarketInfoContainer } from '@vegaprotocol/market-info'; import { MarketInfoContainer, getExpiryDate } from '@vegaprotocol/market-info';
import { OrderbookContainer } from '@vegaprotocol/market-depth'; import { OrderbookContainer } from '@vegaprotocol/market-depth';
import { OrderListContainer } from '@vegaprotocol/orders'; import { OrderListContainer } from '@vegaprotocol/orders';
import { FillsContainer } from '@vegaprotocol/fills'; import { FillsContainer } from '@vegaprotocol/fills';
@ -20,7 +20,7 @@ import {
ButtonLink, ButtonLink,
Link, Link,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import { getDateFormat, t } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/react-helpers';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import { useEnvironment } from '@vegaprotocol/environment'; import { useEnvironment } from '@vegaprotocol/environment';
import { Header, HeaderStat } from '../../components/header'; import { Header, HeaderStat } from '../../components/header';
@ -56,15 +56,7 @@ type ExpiryLabelProps = {
}; };
const ExpiryLabel = ({ market }: ExpiryLabelProps) => { const ExpiryLabel = ({ market }: ExpiryLabelProps) => {
let content = null; const content = getExpiryDate(market);
if (market.marketTimestamps.close === null) {
content = t('Not time-based');
} else {
const closeDate = new Date(market.marketTimestamps.close as string);
const isExpired = Date.now() - closeDate.valueOf() > 0;
const expiryDate = getDateFormat().format(closeDate);
content = `${isExpired ? `${t('Expired')} ` : ''} ${expiryDate}`;
}
return <div data-testid="trading-expiry">{content}</div>; return <div data-testid="trading-expiry">{content}</div>;
}; };

View File

@ -1 +1,2 @@
export * from './market-expires';
export * from './market-info'; export * from './market-info';

View File

@ -0,0 +1 @@
export * from './market-expires';

View File

@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import SimpleMarketExpires from './simple-market-expires'; import { MarketExpires } from './market-expires';
describe('SimpleMarketExpires', () => { describe('MarketExpires', () => {
describe('should properly parse different tags', () => { describe('should properly parse different tags', () => {
it('settlement:date', () => { it('settlement:date', () => {
const tags = [ const tags = [
@ -12,7 +12,7 @@ describe('SimpleMarketExpires', () => {
'settlement:notadate', 'settlement:notadate',
'settlement:20220525T1200', 'settlement:20220525T1200',
]; ];
render(<SimpleMarketExpires tags={tags} />); render(<MarketExpires tags={tags} />);
expect(screen.getByText('May 25')).toBeInTheDocument(); expect(screen.getByText('May 25')).toBeInTheDocument();
}); });
@ -22,7 +22,7 @@ describe('SimpleMarketExpires', () => {
'settlement:20220525T1200', 'settlement:20220525T1200',
'settlement-date:2022-04-25T1200', 'settlement-date:2022-04-25T1200',
]; ];
render(<SimpleMarketExpires tags={tags} />); render(<MarketExpires tags={tags} />);
expect(screen.getByText('Apr 25')).toBeInTheDocument(); expect(screen.getByText('Apr 25')).toBeInTheDocument();
}); });
@ -32,7 +32,7 @@ describe('SimpleMarketExpires', () => {
'settlement-date:20220525T1200', 'settlement-date:20220525T1200',
'settlement-expiry-date:2022-03-25T12:00:00', 'settlement-expiry-date:2022-03-25T12:00:00',
]; ];
render(<SimpleMarketExpires tags={tags} />); render(<MarketExpires tags={tags} />);
expect(screen.getByText('Mar 25')).toBeInTheDocument(); expect(screen.getByText('Mar 25')).toBeInTheDocument();
}); });
@ -42,7 +42,7 @@ describe('SimpleMarketExpires', () => {
'settlemenz:20220525T1200', 'settlemenz:20220525T1200',
'settlemenx-date:20220425T1200', 'settlemenx-date:20220425T1200',
]; ];
const { container } = render(<SimpleMarketExpires tags={tags} />); const { container } = render(<MarketExpires tags={tags} />);
expect(container.firstChild).toBeNull(); expect(container.firstChild).toBeNull();
}); });
}); });

View File

@ -0,0 +1,73 @@
import type { SingleMarketFieldsFragment } from '@vegaprotocol/market-list';
import { getDateFormat, t } from '@vegaprotocol/react-helpers';
import { format, isValid, parseISO } from 'date-fns';
export const EXPIRE_DATE_FORMAT = 'MMM dd';
export const getMarketExpiryDate = (
tags?: ReadonlyArray<string> | null
): Date | null => {
if (tags) {
const dateFound = tags.reduce<Date | null>((agg, tag) => {
const parsed = parseISO(
(tag.match(/^settlement.*:/) &&
tag
.split(':')
.filter((item, i) => i)
.join(':')) as string
);
if (isValid(parsed)) {
agg = parsed;
}
return agg;
}, null);
return dateFound;
}
return null;
};
export const getMarketExpiryDateFormatted = (
tags?: ReadonlyArray<string> | null
): string | null => {
if (tags) {
const dateFound = getMarketExpiryDate(tags);
return dateFound ? format(dateFound, EXPIRE_DATE_FORMAT) : null;
}
return null;
};
export const getExpiryDate = (market: SingleMarketFieldsFragment): string => {
const closeDate = getMarketExpiryDate(
market.tradableInstrument.instrument.metadata.tags
);
const closedMarketDate =
market.marketTimestamps.close && new Date(market.marketTimestamps.close);
let content = null;
if (!closeDate) {
content = closedMarketDate
? `Expired on ${getDateFormat().format(closedMarketDate)}`
: t('Not time-based');
} else {
const isExpired = Date.now() - closeDate.valueOf() > 0;
const expiryDate = getDateFormat().format(closeDate);
if (isExpired) {
content = closedMarketDate
? `Expired on ${getDateFormat().format(closedMarketDate)}`
: t('Expired');
} else {
content = expiryDate;
}
}
return content;
};
export const MarketExpires = ({
tags,
}: {
tags?: ReadonlyArray<string> | null;
}) => {
const date = getMarketExpiryDateFormatted(tags);
return date ? (
<div className="p-2 text-ui-small border border-pink text-pink inline-block">{`${date}`}</div>
) : null;
};

View File

@ -24,6 +24,7 @@ import { useEnvironment } from '@vegaprotocol/environment';
import { Link as UiToolkitLink } from '@vegaprotocol/ui-toolkit'; import { Link as UiToolkitLink } from '@vegaprotocol/ui-toolkit';
import Link from 'next/link'; import Link from 'next/link';
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets'; import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
import { getMarketExpiryDateFormatted } from '../market-expires';
const Links = { const Links = {
PROPOSAL_PAGE: ':tokenUrl/governance/:proposalId', PROPOSAL_PAGE: ':tokenUrl/governance/:proposalId',
@ -224,6 +225,9 @@ export const Info = ({ market, onSelect }: InfoProps) => {
content: ( content: (
<MarketInfoTable <MarketInfoTable
data={{ data={{
expiryDate: getMarketExpiryDateFormatted(
market.tradableInstrument.instrument.metadata.tags
),
...market.tradableInstrument.instrument.metadata.tags ...market.tradableInstrument.instrument.metadata.tags
?.map((tag) => { ?.map((tag) => {
const [key, value] = tag.split(':'); const [key, value] = tag.split(':');