feat: add market termination warning banner

This commit is contained in:
maciek
2023-09-27 17:18:32 +02:00
parent 77c0894501
commit 5d4da60f05
11 changed files with 456 additions and 4 deletions
@@ -18,6 +18,7 @@ import { TradingViews } from './trade-views';
import {
MarketSuccessorBanner,
MarketSuccessorProposalBanner,
MarketTerminationBanner,
} from '../../components/market-banner';
import { FLAGS } from '@vegaprotocol/environment';
@@ -169,6 +170,7 @@ export const TradeGrid = ({ market, pinnedAsset }: TradeGridProps) => {
<MarketSuccessorProposalBanner marketId={market?.id} />
</>
)}
<MarketTerminationBanner />
<OracleBanner marketId={market?.id || ''} />
</div>
<div className="min-h-0 p-0.5">
@@ -1,2 +1,3 @@
export * from './market-successor-banner';
export * from './market-successor-proposal-banner';
export * from './market-termination-banner';
@@ -0,0 +1,129 @@
import { render, screen, waitFor } from '@testing-library/react';
import type { MockedResponse } from '@apollo/client/testing';
import { MockedProvider } from '@apollo/client/testing';
import { MarketTerminationBanner } from './market-termination-banner';
import type { TerminateProposalsListQuery } from '@vegaprotocol/proposals';
import { TerminateProposalsListDocument } from '@vegaprotocol/proposals';
import type { PositionsQuery } from '@vegaprotocol/positions';
import { PositionsDocument } from '@vegaprotocol/positions';
const walletMock = {
pubKey: 'pubKey',
pubKeys: [{ publicKey: 'pubKey' }, { publicKey: 'secondPubKey' }],
};
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn(() => walletMock),
}));
const proposalMock: MockedResponse<TerminateProposalsListQuery> = {
request: {
query: TerminateProposalsListDocument,
variables: undefined,
},
result: {
data: {
proposalsConnection: {
edges: [
{
node: {
id: 'first-id',
terms: {
closingDatetime: '2023-09-27T11:48:18Z',
enactmentDatetime: '2023-09-30T11:48:18',
change: {
__typename: 'UpdateMarketState',
updateType: '',
price: '',
market: {
id: 'market-1',
tradableInstrument: {
instrument: {
name: 'Market one',
},
},
},
},
},
},
},
{
node: {
id: 'second-id',
terms: {
closingDatetime: '2023-09-27T11:48:18Z',
enactmentDatetime: '2023-10-01T11:48:18',
change: {
__typename: 'UpdateMarketState',
updateType: '',
price: '',
market: {
id: 'market-2',
tradableInstrument: {
instrument: {
name: 'Market two',
},
},
},
},
},
},
},
],
},
} as unknown as TerminateProposalsListQuery,
},
};
const positionsMock: MockedResponse<PositionsQuery> = {
request: {
query: PositionsDocument,
variables: { partyIds: ['pubKey', 'secondPubKey'] },
},
result: {
data: {
positions: {
edges: [
{
node: {
market: {
id: 'market-1',
},
party: {
id: 'pubKey',
},
},
},
{
node: {
market: {
id: 'market-2',
},
party: {
id: 'secondPubKey',
},
},
},
],
},
} as unknown as PositionsQuery,
},
};
const mocks: MockedResponse[] = [proposalMock, positionsMock];
describe('MarketTerminationBanner', () => {
it('should be properly rendered', async () => {
render(
<MockedProvider mocks={mocks}>
<MarketTerminationBanner />
</MockedProvider>
);
await waitFor(() => {
expect(
screen.getByTestId('termination-warning-banner-market-1')
).toBeInTheDocument();
});
expect(
screen.getByTestId('termination-warning-banner-market-2')
).toBeInTheDocument();
});
});
@@ -0,0 +1,96 @@
import {
ExternalLink,
Intent,
NotificationBanner,
} from '@vegaprotocol/ui-toolkit';
import { useState } from 'react';
import { useGetTerminationProposals } from '@vegaprotocol/proposals';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { positionsDataProvider } from '@vegaprotocol/positions';
import { formatDateWithLocalTimezone } from '@vegaprotocol/utils';
import { formatDuration, intervalToDuration } from 'date-fns';
export const MarketTerminationBanner = () => {
const [visible, setVisible] = useState(true);
const { pubKey, pubKeys } = useVegaWallet();
const partyIds = pubKeys?.map((item) => item.publicKey) || [];
const { data: positionsData } = useDataProvider({
dataProvider: positionsDataProvider,
variables: {
partyIds,
},
skip: !partyIds?.length,
});
const marketsId = (positionsData || []).map((item) => item.market.id);
const skip = !pubKey || !visible || !marketsId.length;
const proposalsData = useGetTerminationProposals({ skip });
const marketsMatched = (proposalsData || [])
.filter((item) =>
marketsId.some(
(marketId) =>
item.terms.change.__typename === 'UpdateMarketState' &&
item.terms.change.market.id === marketId
)
)
.map((item) => ({
enactmentDatetime: item.terms.enactmentDatetime,
name:
item.terms.change.__typename === 'UpdateMarketState'
? item.terms.change.market.tradableInstrument.instrument.name
: '',
id:
item.terms.change.__typename === 'UpdateMarketState'
? item.terms.change.market.id
: '',
}));
if (visible && marketsMatched.length) {
return marketsMatched.map((item) => {
const dayMonthDate = formatDateWithLocalTimezone(
new Date(item.enactmentDatetime),
'dd MMMM'
);
const duration = intervalToDuration({
start: new Date(),
end: new Date(item.enactmentDatetime),
});
const formattedDuration = formatDuration(duration, {
format: ['days', 'hours'],
});
return (
<>
<NotificationBanner
intent={Intent.Warning}
onClose={() => {
setVisible(false);
}}
data-testid={`termination-warning-banner-${item.id}`}
>
<div className="uppercase mb-1">
{t('Trading on Market %s will stop on %s', [
item.name,
dayMonthDate,
])}
</div>
<div>
{t('Market')}{' '}
<ExternalLink href={`/#/markets/${item.id}`}>
{item.name}
</ExternalLink>
{t(
'will close to trading in %s. You will not be able to hold a position on this market after %s.',
[formattedDuration, dayMonthDate]
)}
</div>
</NotificationBanner>
</>
);
});
}
return null;
};
@@ -261,4 +261,4 @@ export function useMarketInfoLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions
}
export type MarketInfoQueryHookResult = ReturnType<typeof useMarketInfoQuery>;
export type MarketInfoLazyQueryHookResult = ReturnType<typeof useMarketInfoLazyQuery>;
export type MarketInfoQueryResult = Apollo.QueryResult<MarketInfoQuery, MarketInfoQueryVariables>;
export type MarketInfoQueryResult = Apollo.QueryResult<MarketInfoQuery, MarketInfoQueryVariables>;
@@ -1,3 +1,16 @@
fragment UpdateMarketStateFields on UpdateMarketState {
market {
id
tradableInstrument {
instrument {
name
}
}
}
updateType
price
}
fragment NewMarketFields on NewMarket {
instrument {
name
@@ -428,3 +441,36 @@ query SuccessorProposalsList {
}
}
}
fragment TerminateProposalsListFields on Proposal {
id
state
datetime
rejectionReason
terms {
closingDatetime
enactmentDatetime
change {
__typename
... on UpdateMarketState {
...UpdateMarketStateFields
}
}
}
}
query TerminateProposalsList {
proposalsConnection(inState: STATE_PASSED) {
edges {
node {
...TerminateProposalsListFields
}
}
}
}
subscription TerminateLiveProposals {
proposals {
...TerminateProposalsListFields
}
}
@@ -3,6 +3,8 @@ import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type UpdateMarketStateFieldsFragment = { __typename?: 'UpdateMarketState', updateType: Types.MarketUpdateType, price?: string | null, market: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } };
export type NewMarketFieldsFragment = { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array<string> | null, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null }, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, successorConfiguration?: { __typename?: 'SuccessorConfiguration', parentMarketId: string } | null };
export type UpdateMarketFieldsFragment = { __typename?: 'UpdateMarket', marketId: string, updateMarketConfiguration: { __typename?: 'UpdateMarketConfiguration', metadata?: Array<string | null> | null, instrument: { __typename?: 'UpdateInstrumentConfiguration', code: string, product: { __typename?: 'UpdateFutureProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | { __typename?: 'UpdatePerpetualProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecPerpetualBinding', settlementDataProperty: string, settlementScheduleProperty: string } } }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, riskParameters: { __typename: 'UpdateMarketLogNormalRiskModel', logNormal?: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | null } | { __typename: 'UpdateMarketSimpleRiskModel', simple?: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } | null } } };
@@ -32,6 +34,18 @@ export type SuccessorProposalsListQueryVariables = Types.Exact<{ [key: string]:
export type SuccessorProposalsListQuery = { __typename?: 'Query', proposalsConnection?: { __typename?: 'ProposalsConnection', edges?: Array<{ __typename?: 'ProposalEdge', node: { __typename?: 'Proposal', id?: string | null, terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', name: string }, successorConfiguration?: { __typename?: 'SuccessorConfiguration', parentMarketId: string } | null } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } } } | null> | null } | null };
export type TerminateProposalsListFieldsFragment = { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename: 'CancelTransfer' } | { __typename: 'NewAsset' } | { __typename: 'NewFreeform' } | { __typename: 'NewMarket' } | { __typename: 'NewSpotMarket' } | { __typename: 'NewTransfer' } | { __typename: 'UpdateAsset' } | { __typename: 'UpdateMarket' } | { __typename: 'UpdateMarketState', updateType: Types.MarketUpdateType, price?: string | null, market: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } } | { __typename: 'UpdateNetworkParameter' } | { __typename: 'UpdateReferralProgram' } | { __typename: 'UpdateSpotMarket' } | { __typename: 'UpdateVolumeDiscountProgram' } } };
export type TerminateProposalsListQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type TerminateProposalsListQuery = { __typename?: 'Query', proposalsConnection?: { __typename?: 'ProposalsConnection', edges?: Array<{ __typename?: 'ProposalEdge', node: { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename: 'CancelTransfer' } | { __typename: 'NewAsset' } | { __typename: 'NewFreeform' } | { __typename: 'NewMarket' } | { __typename: 'NewSpotMarket' } | { __typename: 'NewTransfer' } | { __typename: 'UpdateAsset' } | { __typename: 'UpdateMarket' } | { __typename: 'UpdateMarketState', updateType: Types.MarketUpdateType, price?: string | null, market: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } } | { __typename: 'UpdateNetworkParameter' } | { __typename: 'UpdateReferralProgram' } | { __typename: 'UpdateSpotMarket' } | { __typename: 'UpdateVolumeDiscountProgram' } } } } | null> | null } | null };
export type TerminateLiveProposalsSubscriptionVariables = Types.Exact<{ [key: string]: never; }>;
export type TerminateLiveProposalsSubscription = { __typename?: 'Subscription', proposals: { __typename?: 'Proposal', id?: string | null, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename: 'CancelTransfer' } | { __typename: 'NewAsset' } | { __typename: 'NewFreeform' } | { __typename: 'NewMarket' } | { __typename: 'NewSpotMarket' } | { __typename: 'NewTransfer' } | { __typename: 'UpdateAsset' } | { __typename: 'UpdateMarket' } | { __typename: 'UpdateMarketState', updateType: Types.MarketUpdateType, price?: string | null, market: { __typename?: 'Market', id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string } } } } | { __typename: 'UpdateNetworkParameter' } | { __typename: 'UpdateReferralProgram' } | { __typename: 'UpdateSpotMarket' } | { __typename: 'UpdateVolumeDiscountProgram' } } } };
export const NewMarketFieldsFragmentDoc = gql`
fragment NewMarketFields on NewMarket {
instrument {
@@ -437,6 +451,38 @@ export const SuccessorProposalListFieldsFragmentDoc = gql`
}
}
${NewMarketSuccessorFieldsFragmentDoc}`;
export const UpdateMarketStateFieldsFragmentDoc = gql`
fragment UpdateMarketStateFields on UpdateMarketState {
market {
id
tradableInstrument {
instrument {
name
}
}
}
updateType
price
}
`;
export const TerminateProposalsListFieldsFragmentDoc = gql`
fragment TerminateProposalsListFields on Proposal {
id
state
datetime
rejectionReason
terms {
closingDatetime
enactmentDatetime
change {
__typename
... on UpdateMarketState {
...UpdateMarketStateFields
}
}
}
}
${UpdateMarketStateFieldsFragmentDoc}`;
export const ProposalsListDocument = gql`
query ProposalsList($proposalType: ProposalType, $inState: ProposalState) {
proposalsConnection(proposalType: $proposalType, inState: $inState) {
@@ -514,4 +560,71 @@ export function useSuccessorProposalsListLazyQuery(baseOptions?: Apollo.LazyQuer
}
export type SuccessorProposalsListQueryHookResult = ReturnType<typeof useSuccessorProposalsListQuery>;
export type SuccessorProposalsListLazyQueryHookResult = ReturnType<typeof useSuccessorProposalsListLazyQuery>;
export type SuccessorProposalsListQueryResult = Apollo.QueryResult<SuccessorProposalsListQuery, SuccessorProposalsListQueryVariables>;
export type SuccessorProposalsListQueryResult = Apollo.QueryResult<SuccessorProposalsListQuery, SuccessorProposalsListQueryVariables>;
export const TerminateProposalsListDocument = gql`
query TerminateProposalsList {
proposalsConnection(inState: STATE_PASSED) {
edges {
node {
...TerminateProposalsListFields
}
}
}
}
${TerminateProposalsListFieldsFragmentDoc}`;
/**
* __useTerminateProposalsListQuery__
*
* To run a query within a React component, call `useTerminateProposalsListQuery` and pass it any options that fit your needs.
* When your component renders, `useTerminateProposalsListQuery` 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 } = useTerminateProposalsListQuery({
* variables: {
* },
* });
*/
export function useTerminateProposalsListQuery(baseOptions?: Apollo.QueryHookOptions<TerminateProposalsListQuery, TerminateProposalsListQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<TerminateProposalsListQuery, TerminateProposalsListQueryVariables>(TerminateProposalsListDocument, options);
}
export function useTerminateProposalsListLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<TerminateProposalsListQuery, TerminateProposalsListQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<TerminateProposalsListQuery, TerminateProposalsListQueryVariables>(TerminateProposalsListDocument, options);
}
export type TerminateProposalsListQueryHookResult = ReturnType<typeof useTerminateProposalsListQuery>;
export type TerminateProposalsListLazyQueryHookResult = ReturnType<typeof useTerminateProposalsListLazyQuery>;
export type TerminateProposalsListQueryResult = Apollo.QueryResult<TerminateProposalsListQuery, TerminateProposalsListQueryVariables>;
export const TerminateLiveProposalsDocument = gql`
subscription TerminateLiveProposals {
proposals {
...TerminateProposalsListFields
}
}
${TerminateProposalsListFieldsFragmentDoc}`;
/**
* __useTerminateLiveProposalsSubscription__
*
* To run a query within a React component, call `useTerminateLiveProposalsSubscription` and pass it any options that fit your needs.
* When your component renders, `useTerminateLiveProposalsSubscription` 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 subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useTerminateLiveProposalsSubscription({
* variables: {
* },
* });
*/
export function useTerminateLiveProposalsSubscription(baseOptions?: Apollo.SubscriptionHookOptions<TerminateLiveProposalsSubscription, TerminateLiveProposalsSubscriptionVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSubscription<TerminateLiveProposalsSubscription, TerminateLiveProposalsSubscriptionVariables>(TerminateLiveProposalsDocument, options);
}
export type TerminateLiveProposalsSubscriptionHookResult = ReturnType<typeof useTerminateLiveProposalsSubscription>;
export type TerminateLiveProposalsSubscriptionResult = Apollo.SubscriptionResult<TerminateLiveProposalsSubscription>;
@@ -1,10 +1,19 @@
import { makeDataProvider } from '@vegaprotocol/data-provider';
import produce from 'immer';
import type {
ProposalsListQuery,
ProposalsListQueryVariables,
ProposalListFieldsFragment,
TerminateLiveProposalsSubscription,
TerminateProposalsListFieldsFragment,
TerminateProposalsListQuery,
} from './__generated__/Proposals';
import { ProposalsListDocument } from './__generated__/Proposals';
import {
ProposalsListDocument,
TerminateLiveProposalsDocument,
TerminateProposalsListDocument,
} from './__generated__/Proposals';
import { removePaginationWrapper } from '@vegaprotocol/utils';
const getData = (responseData: ProposalsListQuery | null) =>
responseData?.proposalsConnection?.edges
@@ -31,3 +40,41 @@ export const proposalsDataProvider = makeDataProvider<
errorPolicyGuard: (errors) =>
errors.every((e) => e.message.match(/failed to get asset for ID/)),
});
const update = (
data: TerminateProposalsListFieldsFragment[] | null,
delta: TerminateProposalsListFieldsFragment
) => {
const updateData = produce(data || [], (draft) => {
const { id } = delta;
const index = draft.findIndex((item) => item.id === id);
if (index === -1) {
draft.unshift(delta);
} else {
const currNode = draft[index];
draft[index] = {
...currNode,
...delta,
};
}
});
return updateData;
};
const getTerminateProposalsData = (
responseData: TerminateProposalsListQuery | null
) => removePaginationWrapper(responseData?.proposalsConnection?.edges) || [];
export const proposalTerminateDataProvider = makeDataProvider<
TerminateProposalsListQuery,
TerminateProposalsListFieldsFragment[],
TerminateLiveProposalsSubscription,
TerminateProposalsListFieldsFragment
>({
query: TerminateProposalsListDocument,
subscriptionQuery: TerminateLiveProposalsDocument,
update,
getDelta: (subscriptionData: TerminateLiveProposalsSubscription) =>
subscriptionData.proposals,
getData: getTerminateProposalsData,
});
@@ -4,3 +4,4 @@ export * from './use-proposal-submit';
export * from './use-update-proposal';
export * from './use-update-network-paramaters-toasts';
export * from './use-successor-market-proposal-details';
export * from './use-get-termination-proposals';
@@ -0,0 +1,17 @@
import { useDataProvider } from '@vegaprotocol/data-provider';
import { proposalTerminateDataProvider } from '../proposals-data-provider';
export const useGetTerminationProposals = ({
skip = false,
}: {
skip?: boolean;
}) => {
const { data } = useDataProvider({
dataProvider: proposalTerminateDataProvider,
skip,
variables: undefined,
});
return (data || []).filter(
(item) => item.terms.change.__typename === 'UpdateMarketState'
);
};
+1 -1
View File
@@ -4637,7 +4637,7 @@ export type ReferralSet = {
* Referral set statistics for the latest or specific epoch.
* If provided the results can be filtered for a specific referee
*/
stats: ReferralSetStats;
stats?: Maybe<ReferralSetStats>;
/** Timestamp as RFC3339Nano when the referral set was updated. */
updatedAt: Scalars['Timestamp'];
};