diff --git a/apps/trading-e2e/src/integration/markets.cy.ts b/apps/trading-e2e/src/integration/markets.cy.ts index 4906328bd..e8e847808 100644 --- a/apps/trading-e2e/src/integration/markets.cy.ts +++ b/apps/trading-e2e/src/integration/markets.cy.ts @@ -1,4 +1,7 @@ import * as Schema from '@vegaprotocol/types'; +import { aliasGQLQuery } from '@vegaprotocol/cypress'; +import { marketQuery } from '@vegaprotocol/mock'; +import { getDateTimeFormat } from '@vegaprotocol/react-helpers'; describe('markets table', { tags: '@smoke' }, () => { beforeEach(() => { @@ -111,6 +114,53 @@ describe('markets table', { tags: '@smoke' }, () => { `${Cypress.env('VEGA_TOKEN_URL')}/proposals/propose/new-market` ); }); + + it('opening auction subsets should be properly displayed', () => { + cy.mockTradingPage( + Schema.MarketState.STATE_ACTIVE, + Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION + ); + cy.mockGQL((req) => { + const override = { + market: { + tradableInstrument: { + instrument: { + name: `opening auction MARKET`, + }, + }, + state: Schema.MarketState.STATE_ACTIVE, + tradingMode: Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION, + }, + }; + const market = marketQuery(override); + aliasGQLQuery(req, 'Market', market); + aliasGQLQuery(req, 'ProposalOfMarket', { + proposal: { terms: { enactmentDatetime: '2023-01-31 12:00:01' } }, + }); + }); + cy.visit('/'); + cy.visit('#/markets/market-0'); + cy.getByTestId('item-value').contains('Opening auction').realHover(); + cy.getByTestId('opening-auction-sub-status').should( + 'contain.text', + 'Opening auction: Not enough liquidity to open' + ); + + const now = new Date(Date.parse('2023-01-30 12:00:01')).getTime(); + cy.clock(now, ['Date']); // Set "now" to BEFORE reservation + cy.visit('/'); + cy.visit('#/markets/market-0'); + cy.getByTestId('item-value').contains('Opening auction').realHover(); + cy.getByTestId('opening-auction-sub-status').should( + 'contain.text', + `Opening auction: Closing on ${getDateTimeFormat().format( + new Date('2023-01-31 12:00:01') + )}` + ); + cy.clock().then((clock) => { + clock.restore(); + }); + }); }); function openMarketDropDown() { diff --git a/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx b/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx index a6a4042f1..b34eb88c2 100644 --- a/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx +++ b/libs/deal-ticket/src/components/trading-mode-tooltip/trading-mode-tooltip.tsx @@ -1,6 +1,9 @@ +import { useMemo } from 'react'; +import { parseISO, isValid, isAfter } from 'date-fns'; import classNames from 'classnames'; +import { useProposalOfMarketQuery } from '@vegaprotocol/governance'; import { useEnvironment } from '@vegaprotocol/environment'; -import { DataGrid, t } from '@vegaprotocol/react-helpers'; +import { DataGrid, getDateTimeFormat, t } from '@vegaprotocol/react-helpers'; import * as Schema from '@vegaprotocol/types'; import { ExternalLink } from '@vegaprotocol/ui-toolkit'; import { createDocsLinks } from '@vegaprotocol/react-helpers'; @@ -21,14 +24,24 @@ export const TradingModeTooltip = ({ const { VEGA_DOCS_URL } = useEnvironment(); const market = useMarket(marketId); const marketData = useStaticMarketData(marketId, skip); + const { marketTradingMode: tradingMode, trigger } = marketData || {}; + const variables = useMemo(() => ({ marketId: marketId || '' }), [marketId]); + const { data: proposalData } = useProposalOfMarketQuery({ + variables, + skip: + !tradingMode || + Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION !== tradingMode, + }); if (!market || !marketData) { return null; } + const enactmentDate = parseISO( + proposalData?.proposal?.terms.enactmentDatetime + ); const compiledGrid = onSelect && compileGridData(market, marketData, onSelect); - const { marketTradingMode: tradingMode, trigger } = marketData; switch (tradingMode) { case Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS: { @@ -43,12 +56,47 @@ export const TradingModeTooltip = ({ case Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION: { return (
-

- - {t( - 'This new market is in an opening auction to determine a fair mid-price before starting continuous trading.' - )} - {' '} +

+ {isValid(enactmentDate) && isAfter(new Date(), enactmentDate) ? ( + <> + + {`${Schema.MarketTradingModeMapping[tradingMode]}: ${t( + 'Not enough liquidity to open' + )}`} + + + {t( + 'This market is in opening auction until it has reached enough liquidity to move into continuous trading.' + )} + + + ) : ( + <> + {isValid(enactmentDate) && ( + + {`${Schema.MarketTradingModeMapping[tradingMode]}: ${t( + 'Closing on %s', + getDateTimeFormat().format(enactmentDate) + )}`} + + )} + + {t( + 'This is a new market in an opening auction to determine a fair mid-price before starting continuous trading.' + )} + + + )} {VEGA_DOCS_URL && ( | null }; +export type ProposalOfMarketQueryVariables = Types.Exact<{ + marketId: Types.Scalars['ID']; +}>; + + +export type ProposalOfMarketQuery = { __typename?: 'Query', proposal?: { __typename?: 'Proposal', id?: string | null, terms: { __typename?: 'ProposalTerms', enactmentDatetime?: any | null } } | null }; + export const ProposalEventFieldsFragmentDoc = gql` fragment ProposalEventFields on Proposal { id @@ -113,4 +120,42 @@ export function useOnUpdateNetworkParametersSubscription(baseOptions?: Apollo.Su return Apollo.useSubscription(OnUpdateNetworkParametersDocument, options); } export type OnUpdateNetworkParametersSubscriptionHookResult = ReturnType; -export type OnUpdateNetworkParametersSubscriptionResult = Apollo.SubscriptionResult; \ No newline at end of file +export type OnUpdateNetworkParametersSubscriptionResult = Apollo.SubscriptionResult; +export const ProposalOfMarketDocument = gql` + query ProposalOfMarket($marketId: ID!) { + proposal(id: $marketId) { + id + terms { + enactmentDatetime + } + } +} + `; + +/** + * __useProposalOfMarketQuery__ + * + * To run a query within a React component, call `useProposalOfMarketQuery` and pass it any options that fit your needs. + * When your component renders, `useProposalOfMarketQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useProposalOfMarketQuery({ + * variables: { + * marketId: // value for 'marketId' + * }, + * }); + */ +export function useProposalOfMarketQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(ProposalOfMarketDocument, options); + } +export function useProposalOfMarketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(ProposalOfMarketDocument, options); + } +export type ProposalOfMarketQueryHookResult = ReturnType; +export type ProposalOfMarketLazyQueryHookResult = ReturnType; +export type ProposalOfMarketQueryResult = Apollo.QueryResult; \ No newline at end of file