import debounce from 'lodash/debounce'; import { useMemo, useState } from 'react'; import BigNumber from 'bignumber.js'; import type { ColDef, ValueFormatterFunc } from 'ag-grid-community'; import { type AssetFieldsFragment } from '@vegaprotocol/assets'; import { addDecimalsFormatNumberQuantum, formatNumberPercentage, } from '@vegaprotocol/utils'; import { AgGrid, StackedCell } from '@vegaprotocol/datagrid'; import { TradingButton, VegaIcon, VegaIconNames, } from '@vegaprotocol/ui-toolkit'; import { useRewardsHistoryQuery, type RewardsHistoryQuery, } from '../../lib/hooks/__generated__/Rewards'; import { useRewardsRowData } from './use-reward-row-data'; import { useT } from '../../lib/use-t'; export const RewardsHistoryContainer = ({ epoch, pubKey, assets, }: { pubKey: string | undefined; epoch: number; assets: Record; }) => { const [epochVariables, setEpochVariables] = useState(() => ({ from: epoch - 1, to: epoch, })); // No need to specify the fromEpoch as it will by default give you the last const { refetch, data, loading } = useRewardsHistoryQuery({ variables: { partyId: pubKey || '', fromEpoch: epochVariables.from, toEpoch: epochVariables.to, }, }); const debouncedRefetch = useMemo( () => debounce((variables) => refetch(variables), 800), [refetch] ); const handleEpochChange = (incoming: { from: number; to: number }) => { if (!Number.isInteger(incoming.from) || !Number.isInteger(incoming.to)) { return; } if (incoming.from > incoming.to) { return; } // Must be at least the first epoch if (incoming.from < 0 || incoming.to < 0) { return; } if (incoming.from > epoch || incoming.to > epoch) { return; } setEpochVariables({ from: incoming.from, to: Math.min(incoming.to, epoch), }); debouncedRefetch({ partyId: pubKey || '', fromEpoch: incoming.from, toEpoch: incoming.to, }); }; return ( ); }; const defaultColDef = { flex: 1, minWidth: 62, resizable: true, sortable: true, }; interface RewardRow { asset: AssetFieldsFragment; staking: number; priceTaking: number; priceMaking: number; liquidityProvision: number; marketCreation: number; averagePosition: number; relativeReturns: number; returnsVolatility: number; validatorRanking: number; total: number; } export type PartyRewardsConnection = NonNullable< RewardsHistoryQuery['party'] >['rewardsConnection']; export const RewardHistoryTable = ({ epochRewardSummaries, partyRewards, assets, pubKey, epochVariables, epoch, onEpochChange, loading, }: { epochRewardSummaries: RewardsHistoryQuery['epochRewardSummaries']; partyRewards: PartyRewardsConnection; assets: Record | null; pubKey: string | undefined; epoch: number; epochVariables: { from: number; to: number; }; onEpochChange: (epochVariables: { from: number; to: number }) => void; loading: boolean; }) => { const t = useT(); const [isParty, setIsParty] = useState(false); const rowData = useRewardsRowData({ epochRewardSummaries, partyRewards, assets, partyId: isParty ? pubKey : undefined, }); const columnDefs = useMemo[]>(() => { const rewardValueFormatter: ValueFormatterFunc = ({ data, value, ...rest }) => { if (!value || !data) { return '-'; } return addDecimalsFormatNumberQuantum( value, data.asset.decimals, data.asset.quantum ); }; const rewardCellRenderer = ({ data, value, valueFormatted, }: { data: RewardRow; value: number; valueFormatted: string; }) => { if (!value || value <= 0 || !data) { return -; } const pctOfTotal = new BigNumber(value).dividedBy(data.total).times(100); return ( ); }; const colDefs: ColDef[] = [ { field: 'asset.symbol', cellRenderer: ({ value, data }: { value: string; data: RewardRow }) => { if (!value || !data) return -; return ; }, sort: 'desc', pinned: 'left', width: 150, }, { field: 'infrastructureFees', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'staking', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'priceTaking', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'priceMaking', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'liquidityProvision', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'marketCreation', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'averagePosition', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'relativeReturns', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'returnsVolatility', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'validatorRanking', valueFormatter: rewardValueFormatter, cellRenderer: rewardCellRenderer, }, { field: 'total', type: 'rightAligned', valueFormatter: rewardValueFormatter, }, ]; return colDefs; }, []); return (

onEpochChange({ from: value, to: epochVariables.to, }) } onIncrement={() => onEpochChange({ from: epochVariables.from + 1, to: epochVariables.to, }) } onDecrement={() => onEpochChange({ from: epochVariables.from - 1, to: epochVariables.to, }) } /> onEpochChange({ from: epochVariables.from, to: value, }) } onIncrement={() => onEpochChange({ from: epochVariables.from, to: epochVariables.to + 1, }) } onDecrement={() => onEpochChange({ from: epochVariables.from, to: epochVariables.to - 1, }) } />

setIsParty(false)} size="extra-small" minimal={isParty} data-testid="total-distributed-button" > {t('Total distributed')} setIsParty(true)} size="extra-small" disabled={!pubKey} minimal={!isParty} data-testid="earned-by-me-button" > {t('Earned by me')}
); }; const EpochInput = ({ id, value, max, min = 1, step = 1, onChange, onIncrement, onDecrement, }: { id: string; value: number; max?: number; min?: number; step?: number; onChange: (value: number) => void; onIncrement: () => void; onDecrement: () => void; }) => { return ( {value} onChange(Number(e.target.value))} value={value} className="dark:focus:bg-vega-cdark-700 absolute left-0 top-0 h-full w-full appearance-none bg-transparent px-2 focus:outline-none" type="number" step={step} min={min} max={max} id={id} name={id} /> ); };