feat(trading): show commission earned on referrer stats from last 30 days (#5467)

This commit is contained in:
Bartłomiej Głownia 2023-12-18 15:33:40 +01:00 committed by GitHub
parent 902ee2696c
commit 665ab6693a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 160 additions and 28 deletions

View File

@ -2,6 +2,7 @@ import { removePaginationWrapper } from '@vegaprotocol/utils';
import { useCallback } from 'react';
import { useRefereesQuery } from './__generated__/Referees';
import compact from 'lodash/compact';
import pick from 'lodash/pick';
import type {
ReferralSetsQuery,
ReferralSetsQueryVariables,
@ -122,6 +123,66 @@ export const useReferral = (args: UseReferralArgs) => {
};
};
type Referee = NonNullable<
NonNullable<ReturnType<typeof useReferral>['data']>['referee']
>;
type RefereeProperties = (keyof Referee)[];
const findReferee = (referee: Referee, referees: Referee[]) =>
referees.find((r) => r.refereeId === referee?.refereeId) || referee;
const updateReferee = (
referee: Referee,
referees: Referee[],
properties: RefereeProperties
) => ({
...referee,
...pick(findReferee(referee, referees), properties),
});
export const useUpdateReferees = (
referral: ReturnType<typeof useReferral>,
aggregationEpochs: number,
properties: RefereeProperties,
skip?: boolean
): ReturnType<typeof useReferral> => {
const { data, loading, error, refetch } = useRefereesQuery({
variables: {
code: referral?.data?.code as string,
aggregationEpochs,
},
skip: skip || !referral?.data?.code,
fetchPolicy: 'cache-and-network',
context: { isEnlargedTimeout: true },
});
const refetchAll = useCallback(() => {
refetch();
referral.refetch();
}, [refetch, referral]);
if (!referral.data || skip) {
return referral;
}
const referees = compact(
removePaginationWrapper(data?.referralSetReferees.edges)
);
return {
data: data && {
...referral.data,
referees: referral.data.referees.map((referee) =>
updateReferee(referee, referees, properties)
),
referee:
referral.data.referee &&
updateReferee(referral.data.referee, referees, properties),
},
loading: loading || referral.loading,
error: error || referral.error,
refetch: refetchAll,
};
};
const retrieveReferralSetData = (data: ReferralSetsQuery | undefined) =>
data?.referralSets.edges && data.referralSets.edges.length > 0
? data.referralSets.edges[0]?.node

View File

@ -151,6 +151,27 @@ const MOCK_REFEREES: RefereesQuery = {
},
};
const MOCK_REFEREES_30: RefereesQuery = {
referralSetReferees: {
__typename: 'ReferralSetRefereeConnection',
edges: [
{
node: {
atEpoch: 1,
joinedAt: '2023-11-21T14:17:09.257235Z',
refereeId:
'0987654321098765432109876543210987654321098765432109876543219876',
referralSetId:
'3772e570fbab89e50e563036b01dd949c554e5b5fe7908449672dfce9a8adffa',
totalRefereeGeneratedRewards: '12340',
totalRefereeNotionalTakerVolume: '56780',
__typename: 'ReferralSetReferee',
},
},
],
},
};
const programMock: MockedResponse<ReferralProgramQuery> = {
request: {
query: ReferralProgramDocument,
@ -262,6 +283,19 @@ const refereesMock: MockedResponse<RefereesQuery, RefereesQueryVariables> = {
},
};
const refereesMock30: MockedResponse<RefereesQuery, RefereesQueryVariables> = {
request: {
query: RefereesDocument,
variables: {
code: MOCK_REFERRER_SET.referralSets.edges[0]?.node.id as string,
aggregationEpochs: 30,
},
},
result: {
data: MOCK_REFEREES_30,
},
};
jest.mock('@vegaprotocol/wallet', () => {
return {
...jest.requireActual('@vegaprotocol/wallet'),
@ -297,6 +331,7 @@ describe('ReferralStatistics', () => {
noReferralSetAsRefereeMock,
stakeAvailableMock,
refereesMock,
refereesMock30,
]}
showWarnings={false}
>
@ -313,6 +348,10 @@ describe('ReferralStatistics', () => {
expect(queryByTestId('referral-statistics')?.dataset.as).toEqual(
'referrer'
);
// gets commision from 30 epochs query
expect(queryByTestId('total-commission-value')).toHaveTextContent(
'12,340'
);
});
});

View File

@ -4,10 +4,15 @@ import {
VegaIcon,
VegaIconNames,
truncateMiddle,
TextChildrenTooltip as Tooltip,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { DEFAULT_AGGREGATION_DAYS, useReferral } from './hooks/use-referral';
import {
DEFAULT_AGGREGATION_DAYS,
useReferral,
useUpdateReferees,
} from './hooks/use-referral';
import classNames from 'classnames';
import { Table } from './table';
import {
@ -41,11 +46,17 @@ export const ReferralStatistics = () => {
role: 'referee',
aggregationEpochs: program.details?.windowLength,
});
const { data: referrer, refetch: referrerRefetch } = useReferral({
pubKey,
role: 'referrer',
aggregationEpochs: program.details?.windowLength,
});
const { data: referrer, refetch: referrerRefetch } = useUpdateReferees(
useReferral({
pubKey,
role: 'referrer',
aggregationEpochs: program.details?.windowLength,
}),
DEFAULT_AGGREGATION_DAYS,
['totalRefereeGeneratedRewards'],
DEFAULT_AGGREGATION_DAYS === program.details?.windowLength
);
const refetch = useCallback(() => {
refereeRefetch();
@ -76,11 +87,9 @@ export const ReferralStatistics = () => {
export const useStats = ({
data,
program,
as,
}: {
data?: NonNullable<ReturnType<typeof useReferral>['data']>;
program: ReturnType<typeof useReferralProgram>;
as?: 'referrer' | 'referee';
}) => {
const { benefitTiers } = program;
const { data: epochData } = useCurrentEpochInfoQuery({
@ -181,7 +190,7 @@ export const Statistics = ({
nextBenefitTierValue,
nextBenefitTierVolumeValue,
nextBenefitTierEpochsValue,
} = useStats({ data, program, as });
} = useStats({ data, program });
const isApplyCodePreview = useMemo(
() => data.referee === null,
@ -293,11 +302,27 @@ export const Statistics = ({
.reduce((all, r) => all.plus(r), new BigNumber(0));
const totalCommissionTile = (
<StatTile
title={t('totalCommission', 'Total commission (last {{count}} epochs)', {
count: details?.windowLength || DEFAULT_AGGREGATION_DAYS,
})}
description={<QUSDTooltip />}
testId="total-commission"
title={
<Trans
i18nKey="totalCommission"
defaults="Total commission (<0>last {{count}} epochs</0>)"
values={{
count: DEFAULT_AGGREGATION_DAYS,
}}
components={[
<Tooltip
key="1"
description={t(
'Depending on data node retention you may not be able see the full 30 days'
)}
>
last 30 epochs
</Tooltip>,
]}
/>
}
description={<QUSDTooltip />}
>
{getNumberFormat(0).format(Number(totalCommissionValue))}
</StatTile>
@ -503,12 +528,21 @@ export const RefereesTable = ({
displayName: (
<Trans
i18nKey="referralStatisticsCommission"
defaults="Commission earned in <0>qUSD</0> (last {{count}} epochs)"
defaults="Commission earned in <0>qUSD</0> (<1>last {{count}} epochs</1>)"
components={[
<QUSDTooltip key="0" />,
<Tooltip
key="1"
description={t(
'Depending on data node retention you may not be able see the full 30 days'
)}
>
last 30 epochs
</Tooltip>,
]}
values={{
count:
details?.windowLength || DEFAULT_AGGREGATION_DAYS,
count: DEFAULT_AGGREGATION_DAYS,
}}
components={[<QUSDTooltip key="qusd" />]}
ns={ns}
/>
),

View File

@ -31,7 +31,7 @@ export const Tile = ({
};
type StatTileProps = {
title: string;
title: ReactNode;
testId?: string;
description?: ReactNode;
children?: ReactNode;
@ -70,7 +70,7 @@ export const StatTile = ({
export const NoProgramTile = ({ title }: Pick<StatTileProps, 'title'>) => {
const t = useT();
return (
<Tile title={title}>
<Tile>
<h3 className="mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100 calt">
{title}
</h3>

View File

@ -57,6 +57,7 @@
"Current tier": "Current tier",
"Dark mode": "Dark mode",
"Date Joined": "Date Joined",
"Depending on data node retention you may not be able see the full 30 days": "Depending on data node retention you may not be able see the full 30 days",
"Deposit": "Deposit",
"Deposit funds": "Deposit funds",
"Deposits": "Deposits",
@ -224,9 +225,9 @@
"Referral benefits": "Referral benefits",
"Referral discount": "Referral discount",
"Referrals": "Referrals",
"referralStatisticsCommission": "Commission earned in <0>qUSD</0> (last {{count}} epochs)",
"referralStatisticsCommission_one": "Commission earned in <0>qUSD</0> (last {{count}} epoch)",
"referralStatisticsCommission_other": "Commission earned in <0>qUSD</0> (last {{count}} epochs)",
"referralStatisticsCommission": "Commission earned in <0>qUSD</0> (<1>last {{count}} epochs</1>)",
"referralStatisticsCommission_one": "Commission earned in <0>qUSD</0> (<1>last {{count}} epoch</1>)",
"referralStatisticsCommission_other": "Commission earned in <0>qUSD</0> (<1>last {{count}} epochs</1>)",
"Referrer commission": "Referrer commission",
"Referrer trading discount": "Referrer trading discount",
"Referrers earn commission based on a percentage of the taker fees their referees pay": "Referrers earn commission based on a percentage of the taker fees their referees pay",
@ -295,9 +296,9 @@
"Total distributed": "Total distributed",
"Total fee after discount": "Total fee after discount",
"Total fee before discount": "Total fee before discount",
"totalCommission": "Total commission (last {{count}}} epochs)",
"totalCommission_one": "Total commission (last {{count}}} epoch)",
"totalCommission_other": "Total commission (last {{count}}} epochs)",
"totalCommission": "Total commission (<0>last {{count}} epochs</0>)",
"totalCommission_one": "Total commission (<0>last {{count}} epoch</0>)",
"totalCommission_other": "Total commission (<0>last {{count}} epochs</0>)",
"Trader": "Trader",
"Trades": "Trades",
"Trading": "Trading",
@ -308,9 +309,6 @@
"Trading on Market {{name}} may stop. There are open proposals to close this market": "Trading on Market {{name}} may stop. There are open proposals to close this market",
"Trading on Market {{name}} will stop on {{date}}": "Trading on Market {{name}} will stop on {{date}}",
"Transfer": "Transfer",
"totalCommission": "Total commission (last {{count}} epochs)",
"totalCommission_one": "Total commission (last {{count}} epoch)",
"totalCommission_other": "Total commission (last {{count}} epochs)",
"Unknown": "Unknown",
"Unknown settlement date": "Unknown settlement date",
"Vega chart": "Vega chart",