feat: 1661 add market expiry date from metadata tags to market info and market header (#1739)
This commit is contained in:
parent
d674162e38
commit
fe472acfe9
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
@ -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>
|
||||||
|
@ -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,
|
||||||
|
@ -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>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
export * from './market-expires';
|
||||||
export * from './market-info';
|
export * from './market-info';
|
||||||
|
1
libs/market-info/src/components/market-expires/index.ts
Normal file
1
libs/market-info/src/components/market-expires/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './market-expires';
|
@ -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();
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -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;
|
||||||
|
};
|
@ -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(':');
|
||||||
|
Loading…
Reference in New Issue
Block a user