feat: extract market name for active reward cards
This commit is contained in:
@@ -196,3 +196,18 @@ query VestingDetails($partyId: ID!) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query MarketForRewards($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
name
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,13 @@ export type VestingDetailsQueryVariables = Types.Exact<{
|
||||
|
||||
export type VestingDetailsQuery = { __typename?: 'Query', party?: { __typename?: 'Party', vestingStats?: { __typename?: 'PartyVestingStats', rewardBonusMultiplier: string, quantumBalance: string, epochSeq: number } | null } | null };
|
||||
|
||||
export type MarketForRewardsQueryVariables = Types.Exact<{
|
||||
marketId: Types.Scalars['ID'];
|
||||
}>;
|
||||
|
||||
|
||||
export type MarketForRewardsQuery = { __typename?: 'Query', market?: { __typename?: 'Market', tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null } } } } | null };
|
||||
|
||||
|
||||
export const RewardsPageDocument = gql`
|
||||
query RewardsPage($partyId: ID!) {
|
||||
@@ -415,4 +422,48 @@ export function useVestingDetailsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt
|
||||
}
|
||||
export type VestingDetailsQueryHookResult = ReturnType<typeof useVestingDetailsQuery>;
|
||||
export type VestingDetailsLazyQueryHookResult = ReturnType<typeof useVestingDetailsLazyQuery>;
|
||||
export type VestingDetailsQueryResult = Apollo.QueryResult<VestingDetailsQuery, VestingDetailsQueryVariables>;
|
||||
export type VestingDetailsQueryResult = Apollo.QueryResult<VestingDetailsQuery, VestingDetailsQueryVariables>;
|
||||
export const MarketForRewardsDocument = gql`
|
||||
query MarketForRewards($marketId: ID!) {
|
||||
market(id: $marketId) {
|
||||
tradableInstrument {
|
||||
instrument {
|
||||
id
|
||||
name
|
||||
code
|
||||
metadata {
|
||||
tags
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useMarketForRewardsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useMarketForRewardsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMarketForRewardsQuery` 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 } = useMarketForRewardsQuery({
|
||||
* variables: {
|
||||
* marketId: // value for 'marketId'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useMarketForRewardsQuery(baseOptions: Apollo.QueryHookOptions<MarketForRewardsQuery, MarketForRewardsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<MarketForRewardsQuery, MarketForRewardsQueryVariables>(MarketForRewardsDocument, options);
|
||||
}
|
||||
export function useMarketForRewardsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketForRewardsQuery, MarketForRewardsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<MarketForRewardsQuery, MarketForRewardsQueryVariables>(MarketForRewardsDocument, options);
|
||||
}
|
||||
export type MarketForRewardsQueryHookResult = ReturnType<typeof useMarketForRewardsQuery>;
|
||||
export type MarketForRewardsLazyQueryHookResult = ReturnType<typeof useMarketForRewardsLazyQuery>;
|
||||
export type MarketForRewardsQueryResult = Apollo.QueryResult<MarketForRewardsQuery, MarketForRewardsQueryVariables>;
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useActiveRewardsQuery } from './__generated__/Rewards';
|
||||
import {
|
||||
useActiveRewardsQuery,
|
||||
useMarketForRewardsQuery,
|
||||
} from './__generated__/Rewards';
|
||||
import { useT } from '../../lib/use-t';
|
||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||
import { addDecimalsFormatNumber, formatNumber } from '@vegaprotocol/utils';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
Icon,
|
||||
@@ -25,9 +28,39 @@ import {
|
||||
DispatchMetric,
|
||||
DispatchMetricDescription,
|
||||
DispatchMetricLabels,
|
||||
type RecurringTransfer,
|
||||
} from '@vegaprotocol/types';
|
||||
import { Card } from '../card/card';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const isActiveReward = (node: TransferNode, currentEpoch: number) => {
|
||||
const { transfer } = node;
|
||||
if (transfer.kind.__typename !== 'RecurringTransfer') {
|
||||
return false;
|
||||
}
|
||||
const { dispatchStrategy } = transfer.kind;
|
||||
|
||||
if (!dispatchStrategy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (transfer.kind.endEpoch && transfer.kind.endEpoch < currentEpoch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (transfer.status !== TransferStatus.STATUS_PENDING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.transfer.reference !== 'reward') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
|
||||
const t = useT();
|
||||
const { data: activeRewardsData } = useActiveRewardsQuery({
|
||||
variables: {
|
||||
isReward: true,
|
||||
@@ -36,27 +69,42 @@ export const ActiveRewards = ({ currentEpoch }: { currentEpoch: number }) => {
|
||||
|
||||
const transfers = activeRewardsData?.transfersConnection?.edges
|
||||
?.map((e) => e?.node as TransferNode)
|
||||
.filter((node) => node.transfer.reference === 'reward');
|
||||
.filter((node) => isActiveReward(node, currentEpoch));
|
||||
|
||||
if (!transfers) return null;
|
||||
if (!transfers || !transfers.length) return null;
|
||||
|
||||
return (
|
||||
<div className="grid gap-x-8 gap-y-10 h-fit grid-cols-[repeat(auto-fill,_minmax(230px,_1fr))] md:grid-cols-[repeat(auto-fill,_minmax(230px,_1fr))] lg:grid-cols-[repeat(auto-fill,_minmax(320px,_1fr))] xl:grid-cols-[repeat(auto-fill,_minmax(343px,_1fr))]">
|
||||
{transfers.map((node, i) => {
|
||||
return (
|
||||
node && (
|
||||
<ActiveRewardCard
|
||||
key={i}
|
||||
transferNode={node}
|
||||
currentEpoch={currentEpoch}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Card title={t('Active rewards')} className="lg:col-span-full">
|
||||
<div className="grid gap-x-8 gap-y-10 h-fit grid-cols-[repeat(auto-fill,_minmax(230px,_1fr))] md:grid-cols-[repeat(auto-fill,_minmax(230px,_1fr))] lg:grid-cols-[repeat(auto-fill,_minmax(320px,_1fr))] xl:grid-cols-[repeat(auto-fill,_minmax(343px,_1fr))]">
|
||||
{transfers.map((node, i) => {
|
||||
const { transfer } = node;
|
||||
|
||||
if (!isActiveReward(node, currentEpoch)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (transfer.kind.__typename !== 'RecurringTransfer') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
node && (
|
||||
<ActiveRewardCard
|
||||
key={i}
|
||||
transferNode={node}
|
||||
kind={transfer.kind}
|
||||
currentEpoch={currentEpoch}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
// This was built to be a status indicator for the rewards based on the transfer status
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const StatusIndicator = ({
|
||||
status,
|
||||
reason,
|
||||
@@ -114,26 +162,42 @@ const StatusIndicator = ({
|
||||
export const ActiveRewardCard = ({
|
||||
transferNode,
|
||||
currentEpoch,
|
||||
kind,
|
||||
}: {
|
||||
transferNode: TransferNode;
|
||||
currentEpoch: number;
|
||||
kind: RecurringTransfer;
|
||||
}) => {
|
||||
const t = useT();
|
||||
|
||||
const { transfer } = transferNode;
|
||||
if (transfer.kind.__typename !== 'RecurringTransfer') {
|
||||
return null;
|
||||
}
|
||||
const { dispatchStrategy } = transfer.kind;
|
||||
const { dispatchStrategy } = kind;
|
||||
const marketIds = dispatchStrategy?.marketIdsInScope;
|
||||
|
||||
const { data: marketNameData } = useMarketForRewardsQuery({
|
||||
variables: {
|
||||
marketId: marketIds ? marketIds[0] : '',
|
||||
},
|
||||
});
|
||||
|
||||
const marketName = useMemo(() => {
|
||||
if (marketNameData && marketIds && marketIds.length > 1) {
|
||||
return 'Specific markets';
|
||||
} else if (
|
||||
marketNameData &&
|
||||
marketIds &&
|
||||
marketNameData &&
|
||||
marketIds.length === 1
|
||||
) {
|
||||
return marketNameData?.market?.tradableInstrument?.instrument?.name || '';
|
||||
}
|
||||
return '';
|
||||
}, [marketIds, marketNameData]);
|
||||
|
||||
if (!dispatchStrategy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (transfer.kind.endEpoch && transfer.kind.endEpoch < currentEpoch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { gradientClassName, mainClassName } = getGradientClasses(
|
||||
dispatchStrategy.dispatchMetric
|
||||
);
|
||||
@@ -170,7 +234,7 @@ export const ActiveRewardCard = ({
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2 items-center text-center">
|
||||
<span className="flex flex-col gap-1 font-alpha calt text-2xl shrink-1 text-center">
|
||||
<span className="flex flex-col gap-1 font-alpha liga text-2xl shrink-1 text-center">
|
||||
<span>
|
||||
{addDecimalsFormatNumber(
|
||||
transferNode.transfer.amount,
|
||||
@@ -210,40 +274,44 @@ export const ActiveRewardCard = ({
|
||||
/>
|
||||
<span className="text-muted text-xs whitespace-nowrap">
|
||||
{t('{{lock}} epochs', {
|
||||
lock: transfer.kind.dispatchStrategy?.lockPeriod,
|
||||
lock: kind.dispatchStrategy?.lockPeriod,
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span className="border-[0.5px] border-gray-700" />
|
||||
|
||||
{/* TODO use market symbol or market name */}
|
||||
<span>
|
||||
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]} •{' '}
|
||||
{transfer.asset?.symbol} • {transfer.asset?.name}
|
||||
{DispatchMetricLabels[dispatchStrategy.dispatchMetric]}
|
||||
{marketName && ` • ${marketName}`}
|
||||
</span>
|
||||
|
||||
<div className="flex items-center gap-8 flex-wrap">
|
||||
{
|
||||
{kind.endEpoch && (
|
||||
<span className="flex flex-col">
|
||||
<span className="text-muted text-xs">{t('Ends in')}</span>
|
||||
<span>
|
||||
{t('{{epochs}} epochs', {
|
||||
epochs: transfer.kind.endEpoch
|
||||
? transfer.kind.endEpoch - currentEpoch
|
||||
epochs: kind.endEpoch
|
||||
? formatNumber(kind.endEpoch - currentEpoch)
|
||||
: '-',
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
)}
|
||||
|
||||
{
|
||||
<span className="flex flex-col">
|
||||
<span className="text-muted text-xs">{t('Assessed over')}</span>
|
||||
<span>
|
||||
{t('{{epochs}} epochs', {
|
||||
epochs: transfer.kind.dispatchStrategy?.windowLength,
|
||||
})}
|
||||
{dispatchStrategy.windowLength === 1
|
||||
? t('{{epochs}} epoch', {
|
||||
epochs: formatNumber(dispatchStrategy.windowLength),
|
||||
})
|
||||
: t('{{epochs}} epoch(s)', {
|
||||
epochs: formatNumber(dispatchStrategy.windowLength),
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
@@ -264,10 +332,10 @@ export const ActiveRewardCard = ({
|
||||
</span>
|
||||
|
||||
<span className="flex items-center gap-1">
|
||||
{transfer.kind.dispatchStrategy?.teamScope && (
|
||||
{kind.dispatchStrategy?.teamScope && (
|
||||
<Tooltip
|
||||
description={
|
||||
<span>{transfer.kind.dispatchStrategy?.teamScope}</span>
|
||||
<span>{kind.dispatchStrategy?.teamScope}</span>
|
||||
}
|
||||
>
|
||||
<span className="flex items-center p-1 rounded-full border border-gray-600">
|
||||
@@ -275,12 +343,10 @@ export const ActiveRewardCard = ({
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{transfer.kind.dispatchStrategy?.individualScope && (
|
||||
{kind.dispatchStrategy?.individualScope && (
|
||||
<Tooltip
|
||||
description={
|
||||
<span>
|
||||
{transfer.kind.dispatchStrategy?.individualScope}
|
||||
</span>
|
||||
<span>{kind.dispatchStrategy?.individualScope}</span>
|
||||
}
|
||||
>
|
||||
<span className="flex items-center p-1 rounded-full border border-gray-600">
|
||||
@@ -288,10 +354,11 @@ export const ActiveRewardCard = ({
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
<StatusIndicator
|
||||
{/* Shows transfer status */}
|
||||
{/* <StatusIndicator
|
||||
status={transfer.status}
|
||||
reason={transfer.reason}
|
||||
/>
|
||||
/> */}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -301,32 +368,24 @@ export const ActiveRewardCard = ({
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
{addDecimalsFormatNumber(
|
||||
transfer.kind.dispatchStrategy?.stakingRequirement || 0,
|
||||
kind.dispatchStrategy?.stakingRequirement || 0,
|
||||
transfer.asset?.decimals || 0
|
||||
)}{' '}
|
||||
{transfer.asset?.symbol}
|
||||
{/* <StatusIndicator
|
||||
status={transfer.status}
|
||||
reason={transfer.reason}
|
||||
/> */}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span className="flex flex-col gap-1">
|
||||
<span className="flex items-center gap-1 text-muted">
|
||||
{t('Notional TWAP Requirement')}{' '}
|
||||
{t('Notional TWAP')}{' '}
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
{addDecimalsFormatNumber(
|
||||
transfer.kind.dispatchStrategy
|
||||
kind.dispatchStrategy
|
||||
?.notionalTimeWeightedAveragePositionRequirement || 0,
|
||||
transfer.asset?.decimals || 0
|
||||
)}{' '}
|
||||
{transfer.asset?.symbol}
|
||||
{/* <StatusIndicator
|
||||
status={transfer.status}
|
||||
reason={transfer.reason}
|
||||
/> */}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -345,8 +404,8 @@ const getGradientClasses = (d: DispatchMetric | undefined) => {
|
||||
};
|
||||
case DispatchMetric.DISPATCH_METRIC_LP_FEES_RECEIVED:
|
||||
return {
|
||||
gradientClassName: 'from-vega-purple-500 to-vega-blue-400',
|
||||
mainClassName: 'from-vega-purple-400 dark:from-vega-purple-600 to-20%',
|
||||
gradientClassName: 'from-vega-green-500 to-vega-yellow-500',
|
||||
mainClassName: 'from-vega-green-400 dark:from-vega-green-600 to-20%',
|
||||
};
|
||||
case DispatchMetric.DISPATCH_METRIC_MAKER_FEES_PAID:
|
||||
return {
|
||||
@@ -354,11 +413,11 @@ const getGradientClasses = (d: DispatchMetric | undefined) => {
|
||||
mainClassName: 'from-vega-orange-400 dark:from-vega-orange-600 to-20%',
|
||||
};
|
||||
case DispatchMetric.DISPATCH_METRIC_MARKET_VALUE:
|
||||
return {
|
||||
gradientClassName: 'from-vega-green-500 to-vega-yellow-500',
|
||||
mainClassName: 'from-vega-green-400 dark:from-vega-green-600 to-20%',
|
||||
};
|
||||
case DispatchMetric.DISPATCH_METRIC_RELATIVE_RETURN:
|
||||
return {
|
||||
gradientClassName: 'from-vega-purple-500 to-vega-blue-400',
|
||||
mainClassName: 'from-vega-purple-400 dark:from-vega-purple-600 to-20%',
|
||||
};
|
||||
case DispatchMetric.DISPATCH_METRIC_RETURN_VOLATILITY:
|
||||
return {
|
||||
gradientClassName: 'from-vega-blue-500 to-vega-green-400',
|
||||
@@ -367,8 +426,8 @@ const getGradientClasses = (d: DispatchMetric | undefined) => {
|
||||
case DispatchMetric.DISPATCH_METRIC_VALIDATOR_RANKING:
|
||||
default:
|
||||
return {
|
||||
gradientClassName: 'from-vega-purple-500 to-vega-blue-400',
|
||||
mainClassName: 'from-vega-purple-400 dark:from-vega-purple-600 to-20%',
|
||||
gradientClassName: 'from-vega-pink-500 to-vega-purple-400',
|
||||
mainClassName: 'from-vega-pink-400 dark:from-vega-pink-600 to-20%',
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -254,7 +254,7 @@ export const RewardsContainer = () => {
|
||||
);
|
||||
})}
|
||||
{pubKey && streaks && (
|
||||
<Card title={t('Activity streak')} className="lg:col-span-full">
|
||||
<Card title={t('Activity Streak')} className="lg:col-span-full">
|
||||
<span className="flex flex-col mx-8">
|
||||
{streaks.map((streak, i) => (
|
||||
<ActivityStreak
|
||||
@@ -279,9 +279,7 @@ export const RewardsContainer = () => {
|
||||
</span>
|
||||
</Card>
|
||||
)}
|
||||
<Card title={t('Active rewards')} className="lg:col-span-full">
|
||||
<ActiveRewards currentEpoch={Number(epochData?.epoch.id)} />
|
||||
</Card>
|
||||
<ActiveRewards currentEpoch={Number(epochData?.epoch.id)} />
|
||||
<Card
|
||||
title={t('Rewards history')}
|
||||
className="lg:col-span-full"
|
||||
|
||||
@@ -48,6 +48,8 @@ export const ActivityStreak = ({
|
||||
return userTier;
|
||||
};
|
||||
|
||||
if (!tiers || tiers.length === 0) return null;
|
||||
|
||||
const userTierIndex = getUserTier();
|
||||
|
||||
const safeProgress = (i: number) => {
|
||||
@@ -62,6 +64,11 @@ export const ActivityStreak = ({
|
||||
.toNumber();
|
||||
};
|
||||
|
||||
const epochsStreak =
|
||||
tiers[userTierIndex].minimum_activity_streak - streak.activeFor >= 0
|
||||
? tiers[userTierIndex].minimum_activity_streak - streak.activeFor
|
||||
: 0;
|
||||
|
||||
const progressBarHeight = 'h-10';
|
||||
|
||||
return (
|
||||
@@ -179,13 +186,7 @@ export const ActivityStreak = ({
|
||||
<span>
|
||||
<span className="text-vega-pink-500">
|
||||
{t('{{epochs}} epochs streak', {
|
||||
epochs:
|
||||
tiers[userTierIndex].minimum_activity_streak -
|
||||
streak.activeFor >=
|
||||
0
|
||||
? tiers[userTierIndex].minimum_activity_streak -
|
||||
streak.activeFor
|
||||
: 0,
|
||||
epochs: formatNumber(epochsStreak),
|
||||
})}
|
||||
</span>
|
||||
{' '}
|
||||
|
||||
@@ -32,9 +32,12 @@ export const RewardHoarderBonus = ({
|
||||
);
|
||||
return userTier;
|
||||
};
|
||||
|
||||
if (!tiers || tiers.length === 0) return null;
|
||||
const userTierIndex = getUserTier() - 1;
|
||||
|
||||
// TODO: extract qUSD from the API
|
||||
const qAsset = 'qUSD';
|
||||
|
||||
const safeProgress = (i: number) => {
|
||||
if (i < userTierIndex) return 100;
|
||||
if (i > userTierIndex) return 0;
|
||||
@@ -71,9 +74,7 @@ export const RewardHoarderBonus = ({
|
||||
})}
|
||||
</span>
|
||||
<span className="text-muted text-xs">
|
||||
{t('{{epochs}} qUSD', {
|
||||
epochs: formatNumber(tier.minimum_quantum_balance),
|
||||
})}
|
||||
{formatNumber(tier.minimum_quantum_balance)} {qAsset}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -147,7 +148,9 @@ export const RewardHoarderBonus = ({
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<VegaIcon name={VegaIconNames.STREAK} />
|
||||
<span>{vestingDetails.quantumBalance} qUSD</span>
|
||||
<span>
|
||||
{formatNumber(vestingDetails.quantumBalance)} {qAsset}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user