4f8d6bd876
Co-authored-by: Art <artur@vegaprotocol.io> Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
184 lines
5.2 KiB
TypeScript
184 lines
5.2 KiB
TypeScript
import { type ReactNode } from 'react';
|
|
import sortBy from 'lodash/sortBy';
|
|
import { format, formatDuration, intervalToDuration } from 'date-fns';
|
|
import { type ProposalFragment } from '@vegaprotocol/proposals';
|
|
import { MarketUpdateType, ProposalState } from '@vegaprotocol/types';
|
|
import {
|
|
DApp,
|
|
TOKEN_PROPOSAL,
|
|
TOKEN_PROPOSALS,
|
|
useLinks,
|
|
} from '@vegaprotocol/environment';
|
|
import { getQuoteName, type Market } from '@vegaprotocol/markets';
|
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
|
import { useT } from '../../lib/use-t';
|
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
|
|
|
export const MarketUpdateStateBanner = ({
|
|
market,
|
|
proposals,
|
|
}: {
|
|
market: Market;
|
|
proposals: ProposalFragment[];
|
|
}) => {
|
|
const t = useT();
|
|
const governanceLink = useLinks(DApp.Governance);
|
|
|
|
const openTradingProposals = sortBy(
|
|
proposals.filter(
|
|
(p) =>
|
|
p.terms &&
|
|
p.terms.change.__typename === 'UpdateMarketState' &&
|
|
p.terms.change.updateType ===
|
|
MarketUpdateType.MARKET_STATE_UPDATE_TYPE_RESUME
|
|
),
|
|
(p) => p.terms?.enactmentDatetime
|
|
);
|
|
|
|
const openProposals = sortBy(
|
|
proposals.filter((p) => p.state === ProposalState.STATE_OPEN),
|
|
(p) => p.terms?.enactmentDatetime
|
|
);
|
|
const passedProposals = sortBy(
|
|
proposals.filter((p) => p.state === ProposalState.STATE_PASSED),
|
|
(p) => p.terms?.enactmentDatetime
|
|
);
|
|
|
|
if (!passedProposals.length && !openProposals.length) {
|
|
return null;
|
|
}
|
|
|
|
const name = market.tradableInstrument.instrument.code;
|
|
const assetSymbol = getQuoteName(market);
|
|
|
|
const proposalLink =
|
|
!passedProposals.length && openProposals[0]?.id
|
|
? governanceLink(TOKEN_PROPOSAL.replace(':id', openProposals[0]?.id))
|
|
: undefined;
|
|
|
|
const openTradingProposalsLink =
|
|
openTradingProposals[0]?.__typename === 'Proposal' &&
|
|
openTradingProposals[0]?.id
|
|
? governanceLink(
|
|
TOKEN_PROPOSAL.replace(':id', openTradingProposals[0].id)
|
|
)
|
|
: openTradingProposals[0]?.__typename === 'ProposalDetail' &&
|
|
openTradingProposals[0]?.batchId
|
|
? governanceLink(
|
|
TOKEN_PROPOSAL.replace(':id', openTradingProposals[0].batchId)
|
|
)
|
|
: undefined;
|
|
|
|
const proposalsLink =
|
|
openProposals.length > 1 ? governanceLink(TOKEN_PROPOSALS) : undefined;
|
|
|
|
let content: ReactNode;
|
|
|
|
if (openTradingProposals.length >= 1) {
|
|
content = (
|
|
<>
|
|
<p className="mb-1">
|
|
{t(
|
|
'Trading on market {{name}} was suspended by governance. There are open proposals to resume trading on this market.',
|
|
{ name }
|
|
)}
|
|
</p>
|
|
<p>
|
|
<ExternalLink href={openTradingProposalsLink}>
|
|
{t('View proposals')}
|
|
</ExternalLink>
|
|
</p>
|
|
</>
|
|
);
|
|
} else if (passedProposals.length) {
|
|
const { date, duration, price } = getMessageVariables(passedProposals[0]);
|
|
content = (
|
|
<>
|
|
<p className="uppercase mb-1">
|
|
{t('Trading on market {{name}} will stop on {{date}}', {
|
|
name,
|
|
date,
|
|
})}
|
|
</p>
|
|
<p>
|
|
{t(
|
|
'You will no longer be able to hold a position on this market when it closes in {{duration}}.',
|
|
{ duration }
|
|
)}{' '}
|
|
{price &&
|
|
assetSymbol &&
|
|
t('The final price will be {{price}} {{assetSymbol}}.', {
|
|
price: addDecimalsFormatNumber(price, market.decimalPlaces),
|
|
assetSymbol,
|
|
})}
|
|
</p>
|
|
</>
|
|
);
|
|
} else if (openProposals.length > 1) {
|
|
content = (
|
|
<>
|
|
<p className="uppercase mb-1">
|
|
{t(
|
|
'Trading on market {{name}} may stop. There are open proposals to close this market',
|
|
{ name }
|
|
)}
|
|
</p>
|
|
<p>
|
|
<ExternalLink href={proposalsLink}>
|
|
{t('View proposals')}
|
|
</ExternalLink>
|
|
</p>
|
|
</>
|
|
);
|
|
} else {
|
|
const { date, price } = getMessageVariables(openProposals[0]);
|
|
content = (
|
|
<>
|
|
<p className="mb-1">
|
|
{t(
|
|
'Trading on market {{name}} may stop on {{date}}. There is an open proposal to close this market.',
|
|
{ name, date }
|
|
)}
|
|
</p>
|
|
<p>
|
|
{price &&
|
|
assetSymbol &&
|
|
t('Proposed final price is {{price}} {{assetSymbol}}.', {
|
|
price: addDecimalsFormatNumber(price, market.decimalPlaces),
|
|
assetSymbol,
|
|
})}{' '}
|
|
<ExternalLink href={proposalLink}>{t('View proposal')}</ExternalLink>
|
|
</p>
|
|
</>
|
|
);
|
|
}
|
|
|
|
return <div data-testid={`update-state-banner-${market.id}`}>{content}</div>;
|
|
};
|
|
|
|
const getMessageVariables = (proposal: ProposalFragment) => {
|
|
const enactmentDatetime =
|
|
proposal.terms && new Date(proposal.terms.enactmentDatetime);
|
|
const date = enactmentDatetime && format(enactmentDatetime, 'dd MMMM');
|
|
const duration =
|
|
enactmentDatetime &&
|
|
formatDuration(
|
|
intervalToDuration({
|
|
start: new Date(),
|
|
end: enactmentDatetime,
|
|
}),
|
|
{
|
|
format: ['days', 'hours'],
|
|
}
|
|
);
|
|
const price =
|
|
proposal.terms?.change.__typename === 'UpdateMarketState'
|
|
? proposal.terms.change.price
|
|
: '';
|
|
return {
|
|
date,
|
|
duration,
|
|
price,
|
|
};
|
|
};
|