Commit bc383c17 authored by isstuev's avatar isstuev

Celo: Epoch rewards tab on Address view

parent b6181940
...@@ -37,6 +37,7 @@ import type { ...@@ -37,6 +37,7 @@ import type {
AddressMudRecordsFilter, AddressMudRecordsFilter,
AddressMudRecordsSorting, AddressMudRecordsSorting,
AddressMudRecord, AddressMudRecord,
AddressEpochRewardsResponse,
} from 'types/api/address'; } from 'types/api/address';
import type { AddressesResponse, AddressesMetadataSearchResult, AddressesMetadataSearchFilters } from 'types/api/addresses'; import type { AddressesResponse, AddressesMetadataSearchResult, AddressesMetadataSearchFilters } from 'types/api/addresses';
import type { AddressMetadataInfo, PublicTagTypesResponse } from 'types/api/addressMetadata'; import type { AddressMetadataInfo, PublicTagTypesResponse } from 'types/api/addressMetadata';
...@@ -505,6 +506,11 @@ export const RESOURCES = { ...@@ -505,6 +506,11 @@ export const RESOURCES = {
pathParams: [ 'hash' as const ], pathParams: [ 'hash' as const ],
filterFields: [], filterFields: [],
}, },
address_epoch_rewards: {
path: '/api/v2/addresses/:hash/election-rewards',
pathParams: [ 'hash' as const ],
filterFields: [],
},
// CONTRACT // CONTRACT
contract: { contract: {
...@@ -1002,7 +1008,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' | 'block_election_reward ...@@ -1002,7 +1008,7 @@ export type PaginatedResources = 'blocks' | 'block_txs' | 'block_election_reward
'addresses' | 'addresses_metadata_search' | 'addresses' | 'addresses_metadata_search' |
'address_txs' | 'address_internal_txs' | 'address_token_transfers' | 'address_blocks_validated' | 'address_coin_balance' | 'address_txs' | 'address_internal_txs' | 'address_token_transfers' | 'address_blocks_validated' | 'address_coin_balance' |
'search' | 'search' |
'address_logs' | 'address_tokens' | 'address_nfts' | 'address_collections' | 'address_logs' | 'address_tokens' | 'address_nfts' | 'address_collections' | 'address_epoch_rewards' |
'token_transfers' | 'token_holders' | 'token_inventory' | 'tokens' | 'tokens_bridged' | 'token_transfers' | 'token_holders' | 'token_inventory' | 'tokens' | 'tokens_bridged' |
'token_instance_transfers' | 'token_instance_holders' | 'token_instance_transfers' | 'token_instance_holders' |
'verified_contracts' | 'verified_contracts' |
...@@ -1182,6 +1188,7 @@ Q extends 'address_mud_tables' ? AddressMudTables : ...@@ -1182,6 +1188,7 @@ Q extends 'address_mud_tables' ? AddressMudTables :
Q extends 'address_mud_tables_count' ? number : Q extends 'address_mud_tables_count' ? number :
Q extends 'address_mud_records' ? AddressMudRecords : Q extends 'address_mud_records' ? AddressMudRecords :
Q extends 'address_mud_record' ? AddressMudRecord : Q extends 'address_mud_record' ? AddressMudRecord :
Q extends 'address_epoch_rewards' ? AddressEpochRewardsResponse :
Q extends 'withdrawals' ? WithdrawalsResponse : Q extends 'withdrawals' ? WithdrawalsResponse :
Q extends 'withdrawals_counters' ? WithdrawalsCounters : Q extends 'withdrawals_counters' ? WithdrawalsCounters :
never; never;
......
import type { AddressEpochRewardsResponse } from 'types/api/address';
import { tokenInfo } from 'mocks/tokens/tokenInfo';
import { withEns, withName, withoutName } from './address';
export const epochRewards: AddressEpochRewardsResponse = {
items: [
{
type: 'delegated_payment',
amount: '136609473658452408568',
account: withName,
associated_account: withName,
block_hash: '0x',
block_number: 26369280,
epoch_number: 1526,
token: tokenInfo,
},
{
type: 'group',
amount: '117205842355246195095',
account: withoutName,
associated_account: withoutName,
block_hash: '0x',
block_number: 26352000,
epoch_number: 1525,
token: tokenInfo,
},
{
type: 'validator',
amount: '125659647325556554060',
account: withEns,
associated_account: withEns,
block_hash: '0x',
block_number: 26300160,
epoch_number: 1524,
token: tokenInfo,
},
],
next_page_params: null,
};
...@@ -3,6 +3,7 @@ import type { ...@@ -3,6 +3,7 @@ import type {
AddressCoinBalanceHistoryItem, AddressCoinBalanceHistoryItem,
AddressCollection, AddressCollection,
AddressCounters, AddressCounters,
AddressEpochRewardsItem,
AddressMudTableItem, AddressMudTableItem,
AddressNFT, AddressNFT,
AddressTabsCounters, AddressTabsCounters,
...@@ -10,7 +11,7 @@ import type { ...@@ -10,7 +11,7 @@ import type {
} from 'types/api/address'; } from 'types/api/address';
import type { AddressesItem } from 'types/api/addresses'; import type { AddressesItem } from 'types/api/addresses';
import { ADDRESS_HASH } from './addressParams'; import { ADDRESS_HASH, ADDRESS_PARAMS } from './addressParams';
import { MUD_SCHEMA, MUD_TABLE } from './mud'; import { MUD_SCHEMA, MUD_TABLE } from './mud';
import { TOKEN_INFO_ERC_1155, TOKEN_INFO_ERC_20, TOKEN_INFO_ERC_721, TOKEN_INFO_ERC_404, TOKEN_INSTANCE } from './token'; import { TOKEN_INFO_ERC_1155, TOKEN_INFO_ERC_20, TOKEN_INFO_ERC_721, TOKEN_INFO_ERC_404, TOKEN_INSTANCE } from './token';
import { TX_HASH } from './tx'; import { TX_HASH } from './tx';
...@@ -116,3 +117,14 @@ export const ADDRESS_MUD_TABLE_ITEM: AddressMudTableItem = { ...@@ -116,3 +117,14 @@ export const ADDRESS_MUD_TABLE_ITEM: AddressMudTableItem = {
schema: MUD_SCHEMA, schema: MUD_SCHEMA,
table: MUD_TABLE, table: MUD_TABLE,
}; };
export const EPOCH_REWARD_ITEM: AddressEpochRewardsItem = {
amount: '136609473658452408568',
block_number: 10355938,
type: 'voter',
token: TOKEN_INFO_ERC_20,
block_hash: '0x5956a847d8089e254e02e5111cad6992b99ceb9e5c2dc4343fd53002834c4dc6',
account: ADDRESS_PARAMS,
epoch_number: 1526,
associated_account: ADDRESS_PARAMS,
};
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import type { UserTags, AddressImplementation } from './addressParams'; import type { UserTags, AddressImplementation, AddressParam } from './addressParams';
import type { Block } from './block'; import type { Block, EpochRewardsType } from './block';
import type { InternalTransaction } from './internalTransaction'; import type { InternalTransaction } from './internalTransaction';
import type { MudWorldSchema, MudWorldTable } from './mudWorlds'; import type { MudWorldSchema, MudWorldTable } from './mudWorlds';
import type { NFTTokenType, TokenInfo, TokenInstance, TokenType } from './token'; import type { NFTTokenType, TokenInfo, TokenInstance, TokenType } from './token';
...@@ -191,6 +191,7 @@ export type AddressTabsCounters = { ...@@ -191,6 +191,7 @@ export type AddressTabsCounters = {
transactions_count: number | null; transactions_count: number | null;
validations_count: number | null; validations_count: number | null;
withdrawals_count: number | null; withdrawals_count: number | null;
celo_election_rewards_count?: number | null;
} }
// MUD framework // MUD framework
...@@ -245,3 +246,25 @@ export type AddressMudRecord = { ...@@ -245,3 +246,25 @@ export type AddressMudRecord = {
schema: MudWorldSchema; schema: MudWorldSchema;
table: MudWorldTable; table: MudWorldTable;
} }
export type AddressEpochRewardsResponse = {
items: Array<AddressEpochRewardsItem>;
next_page_params: {
amount: string;
associated_account_address_hash: string;
block_number: number;
items_count: number;
type: EpochRewardsType;
} | null;
}
export type AddressEpochRewardsItem = {
type: EpochRewardsType;
token: TokenInfo;
amount: string;
block_number: number;
block_hash: string;
account: AddressParam;
epoch_number: number;
associated_account: AddressParam;
}
...@@ -144,6 +144,8 @@ export interface BlockEpochElectionReward { ...@@ -144,6 +144,8 @@ export interface BlockEpochElectionReward {
total: string; total: string;
} }
export type EpochRewardsType = 'group' | 'validator' | 'delegated_payment' | 'voter';
export interface BlockEpoch { export interface BlockEpoch {
number: number; number: number;
distribution: { distribution: {
...@@ -151,12 +153,7 @@ export interface BlockEpoch { ...@@ -151,12 +153,7 @@ export interface BlockEpoch {
community_transfer: TokenTransfer | null; community_transfer: TokenTransfer | null;
reserve_bolster_transfer: TokenTransfer | null; reserve_bolster_transfer: TokenTransfer | null;
}; };
aggregated_election_rewards: { aggregated_election_rewards: Record<EpochRewardsType, BlockEpochElectionReward | null>;
delegated_payment: BlockEpochElectionReward | null;
group: BlockEpochElectionReward | null;
validator: BlockEpochElectionReward | null;
voter: BlockEpochElectionReward | null;
};
} }
export interface BlockEpochElectionRewardDetails { export interface BlockEpochElectionRewardDetails {
......
import { Box } from '@chakra-ui/react';
import React from 'react';
import { epochRewards } from 'mocks/address/epochRewards';
import { test, expect } from 'playwright/lib';
import AddressEpochRewards from './AddressEpochRewards';
const ADDRESS_HASH = '0x1234';
const hooksConfig = {
router: {
query: { hash: ADDRESS_HASH },
},
};
test('base view +@mobile', async({ render, mockApiResponse }) => {
await mockApiResponse('address_epoch_rewards', epochRewards, { pathParams: { hash: ADDRESS_HASH } });
const component = await render(
<Box pt={{ base: '134px', lg: 6 }}>
<AddressEpochRewards/>
</Box>,
{ hooksConfig },
);
await expect(component).toHaveScreenshot();
});
import { Hide, Show } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
import useIsMounted from 'lib/hooks/useIsMounted';
import getQueryParamString from 'lib/router/getQueryParamString';
import { EPOCH_REWARD_ITEM } from 'stubs/address';
import { generateListStub } from 'stubs/utils';
import AddressEpochRewardsTable from 'ui/address/epochRewards/AddressEpochRewardsTable';
import ActionBar, { ACTION_BAR_HEIGHT_DESKTOP } from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import AddressEpochRewardsListItem from './epochRewards/AddressEpochRewardsListItem';
type Props = {
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressEpochRewards = ({ scrollRef, shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const isMounted = useIsMounted();
const hash = getQueryParamString(router.query.hash);
const rewardsQuery = useQueryWithPages({
resourceName: 'address_epoch_rewards',
pathParams: {
hash,
},
scrollRef,
options: {
enabled: isQueryEnabled && Boolean(hash),
placeholderData: generateListStub<'address_epoch_rewards'>(EPOCH_REWARD_ITEM, 50, { next_page_params: {
amount: '1',
items_count: 50,
type: 'voter',
associated_account_address_hash: '1',
block_number: 10355938,
} }),
},
});
if (!isMounted || !shouldRender) {
return null;
}
const content = rewardsQuery.data?.items ? (
<>
<Hide below="lg" ssr={ false }>
<AddressEpochRewardsTable
items={ rewardsQuery.data.items }
top={ rewardsQuery.pagination.isVisible ? ACTION_BAR_HEIGHT_DESKTOP : 0 }
isLoading={ rewardsQuery.isPlaceholderData }
/>
</Hide>
<Show below="lg" ssr={ false }>
{ rewardsQuery.data.items.map((item, index) => (
<AddressEpochRewardsListItem
key={ item.block_hash + item.type + item.account.hash + item.associated_account.hash + (rewardsQuery.isPlaceholderData ? String(index) : '') }
item={ item }
isLoading={ rewardsQuery.isPlaceholderData }
/>
)) }
</Show>
</>
) : null;
const actionBar = rewardsQuery.pagination.isVisible ? (
<ActionBar mt={ -6 }>
<Pagination ml="auto" { ...rewardsQuery.pagination }/>
</ActionBar>
) : null;
return (
<DataListDisplay
isError={ rewardsQuery.isError }
items={ rewardsQuery.data?.items }
emptyText="There are no epoch rewards for this address."
content={ content }
actionBar={ actionBar }
/>
);
};
export default AddressEpochRewards;
import { Skeleton } from '@chakra-ui/react';
import React from 'react';
import type { AddressEpochRewardsItem } from 'types/api/address';
import getCurrencyValue from 'lib/getCurrencyValue';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EpochRewardTypeTag from 'ui/shared/EpochRewardTypeTag';
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
type Props = {
item: AddressEpochRewardsItem;
isLoading?: boolean;
};
const AddressEpochRewardsListItem = ({ item, isLoading }: Props) => {
const { valueStr } = getCurrencyValue({ value: item.amount, accuracy: 2, decimals: item.token.decimals });
return (
<ListItemMobileGrid.Container gridTemplateColumns="100px auto">
<ListItemMobileGrid.Label isLoading={ isLoading }>Block</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<BlockEntity
number={ Number(item.block_number) }
isLoading={ isLoading }
noIcon
/>
</ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>Epoch #</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
{ item.epoch_number }
</ListItemMobileGrid.Value>
{ /* <ListItemMobileGrid.Label isLoading={ isLoading }>Age</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<TimeAgoWithTooltip
timestamp={ item.timestamp }
isLoading={ isLoading }
color="text_secondary"
display="inline-block"
/>
</ListItemMobileGrid.Value> */ }
<ListItemMobileGrid.Label isLoading={ isLoading }>Reward type</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<EpochRewardTypeTag type={ item.type } isLoading={ isLoading }/>
</ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>Associated address</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<AddressEntity
address={ item.associated_account }
isLoading={ isLoading }
/>
</ListItemMobileGrid.Value>
<ListItemMobileGrid.Label isLoading={ isLoading }>Value</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<Skeleton isLoaded={ !isLoading } display="flex" alignItems="center" gap={ 2 }>
{ valueStr }
<TokenEntity token={ item.token } isLoading={ isLoading } onlySymbol width="auto" noCopy/>
</Skeleton>
</ListItemMobileGrid.Value>
</ListItemMobileGrid.Container>
);
};
export default AddressEpochRewardsListItem;
import { Table, Tbody, Th, Tr } from '@chakra-ui/react';
import React from 'react';
import type { AddressEpochRewardsItem } from 'types/api/address';
import { default as Thead } from 'ui/shared/TheadSticky';
import AddressEpochRewardsTableItem from './AddressEpochRewardsTableItem';
type Props = {
items: Array<AddressEpochRewardsItem>;
isLoading?: boolean;
top: number;
};
const AddressEpochRewardsTable = ({ items, isLoading, top }: Props) => {
return (
<Table variant="simple" size="sm" minW="1000px" style={{ tableLayout: 'auto' }}>
<Thead top={ top }>
<Tr>
<Th>Block</Th>
<Th>Reward type</Th>
<Th>Associated address</Th>
<Th isNumeric>Value</Th>
</Tr>
</Thead>
<Tbody>
{ items.map((item, index) => {
return (
<AddressEpochRewardsTableItem
key={ item.block_hash + item.type + item.account.hash + item.associated_account.hash + (isLoading ? String(index) : '') }
item={ item }
isLoading={ isLoading }
/>
);
}) }
</Tbody>
</Table>
);
};
export default AddressEpochRewardsTable;
import { Flex, Td, Tr, Text, Skeleton } from '@chakra-ui/react';
import React from 'react';
import type { AddressEpochRewardsItem } from 'types/api/address';
import getCurrencyValue from 'lib/getCurrencyValue';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EpochRewardTypeTag from 'ui/shared/EpochRewardTypeTag';
type Props = {
item: AddressEpochRewardsItem;
isLoading?: boolean;
};
const AddressEpochRewardsTableItem = ({ item, isLoading }: Props) => {
const { valueStr } = getCurrencyValue({ value: item.amount, decimals: item.token.decimals });
return (
<Tr>
<Td verticalAlign="middle">
<Flex alignItems="center" gap={ 3 }>
<BlockEntity number={ item.block_number } isLoading={ isLoading } noIcon/>
<Text color="text_secondary" fontWeight={ 600 }>{ `Epoch # ${ item.epoch_number }` }</Text>
{ /* no timestamp from API, will be added later */ }
{ /* <TimeAgoWithTooltip timestamp={ item } isLoading={ isLoading }/> */ }
</Flex>
</Td>
<Td verticalAlign="middle">
<EpochRewardTypeTag type={ item.type } isLoading={ isLoading }/>
</Td>
<Td verticalAlign="middle">
<AddressEntity address={ item.associated_account } isLoading={ isLoading }/>
</Td>
<Td verticalAlign="middle" isNumeric>
<Skeleton isLoaded={ !isLoading } display="flex" alignItems="center" gap={ 2 } justifyContent="flex-end">
{ valueStr }
<TokenEntity token={ item.token } isLoading={ isLoading } onlySymbol width="auto" noCopy/>
</Skeleton>
</Td>
</Tr>
);
};
export default AddressEpochRewardsTableItem;
import React from 'react';
import type { BlockEpoch } from 'types/api/block';
import Tag from 'ui/shared/chakra/Tag';
interface Props {
type: keyof BlockEpoch['aggregated_election_rewards'];
isLoading?: boolean;
}
const BlockEpochElectionRewardType = ({ type, isLoading }: Props) => {
switch (type) {
case 'delegated_payment':
return <Tag colorScheme="blue" isLoading={ isLoading }>Delegated payments</Tag>;
case 'group':
return <Tag colorScheme="teal" isLoading={ isLoading }>Validator group rewards</Tag>;
case 'validator':
return <Tag colorScheme="purple" isLoading={ isLoading }>Validator rewards</Tag>;
case 'voter':
return <Tag colorScheme="yellow" isLoading={ isLoading }>Voting rewards</Tag>;
}
};
export default React.memo(BlockEpochElectionRewardType);
...@@ -5,10 +5,10 @@ import type { BlockEpoch, BlockEpochElectionReward } from 'types/api/block'; ...@@ -5,10 +5,10 @@ import type { BlockEpoch, BlockEpochElectionReward } from 'types/api/block';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import TokenEntity from 'ui/shared/entities/token/TokenEntity'; import TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EpochRewardTypeTag from 'ui/shared/EpochRewardTypeTag';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import BlockEpochElectionRewardDetailsMobile from './BlockEpochElectionRewardDetailsMobile'; import BlockEpochElectionRewardDetailsMobile from './BlockEpochElectionRewardDetailsMobile';
import BlockEpochElectionRewardType from './BlockEpochElectionRewardType';
interface Props { interface Props {
data: BlockEpochElectionReward; data: BlockEpochElectionReward;
...@@ -53,7 +53,7 @@ const BlockEpochElectionRewardsListItem = ({ data, isLoading, type }: Props) => ...@@ -53,7 +53,7 @@ const BlockEpochElectionRewardsListItem = ({ data, isLoading, type }: Props) =>
/> />
</Skeleton> </Skeleton>
) : <Box boxSize={ 6 }/> } ) : <Box boxSize={ 6 }/> }
<BlockEpochElectionRewardType type={ type } isLoading={ isLoading }/> <EpochRewardTypeTag type={ type } isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading }>{ data.count }</Skeleton> <Skeleton isLoaded={ !isLoading }>{ data.count }</Skeleton>
<Flex columnGap={ 2 } alignItems="center" ml="auto" fontWeight={ 500 }> <Flex columnGap={ 2 } alignItems="center" ml="auto" fontWeight={ 500 }>
<Skeleton isLoaded={ !isLoading }>{ valueStr }</Skeleton> <Skeleton isLoaded={ !isLoading }>{ valueStr }</Skeleton>
......
...@@ -5,10 +5,10 @@ import type { BlockEpoch, BlockEpochElectionReward } from 'types/api/block'; ...@@ -5,10 +5,10 @@ import type { BlockEpoch, BlockEpochElectionReward } from 'types/api/block';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import TokenEntity from 'ui/shared/entities/token/TokenEntity'; import TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EpochRewardTypeTag from 'ui/shared/EpochRewardTypeTag';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import BlockEpochElectionRewardDetailsDesktop from './BlockEpochElectionRewardDetailsDesktop'; import BlockEpochElectionRewardDetailsDesktop from './BlockEpochElectionRewardDetailsDesktop';
import BlockEpochElectionRewardType from './BlockEpochElectionRewardType';
import { getRewardNumText } from './utils'; import { getRewardNumText } from './utils';
interface Props { interface Props {
...@@ -54,7 +54,7 @@ const BlockEpochElectionRewardsTableItem = ({ isLoading, data, type }: Props) => ...@@ -54,7 +54,7 @@ const BlockEpochElectionRewardsTableItem = ({ isLoading, data, type }: Props) =>
) } ) }
</Td> </Td>
<Td borderColor={ mainRowBorderColor }> <Td borderColor={ mainRowBorderColor }>
<BlockEpochElectionRewardType type={ type } isLoading={ isLoading }/> <EpochRewardTypeTag type={ type } isLoading={ isLoading }/>
</Td> </Td>
<Td borderColor={ mainRowBorderColor }> <Td borderColor={ mainRowBorderColor }>
<Skeleton isLoaded={ !isLoading } fontWeight={ 400 } my={ 1 }> <Skeleton isLoaded={ !isLoading } fontWeight={ 400 } my={ 1 }>
......
...@@ -24,6 +24,7 @@ import AddressBlocksValidated from 'ui/address/AddressBlocksValidated'; ...@@ -24,6 +24,7 @@ import AddressBlocksValidated from 'ui/address/AddressBlocksValidated';
import AddressCoinBalance from 'ui/address/AddressCoinBalance'; import AddressCoinBalance from 'ui/address/AddressCoinBalance';
import AddressContract from 'ui/address/AddressContract'; import AddressContract from 'ui/address/AddressContract';
import AddressDetails from 'ui/address/AddressDetails'; import AddressDetails from 'ui/address/AddressDetails';
import AddressEpochRewards from 'ui/address/AddressEpochRewards';
import AddressInternalTxs from 'ui/address/AddressInternalTxs'; import AddressInternalTxs from 'ui/address/AddressInternalTxs';
import AddressLogs from 'ui/address/AddressLogs'; import AddressLogs from 'ui/address/AddressLogs';
import AddressMud from 'ui/address/AddressMud'; import AddressMud from 'ui/address/AddressMud';
...@@ -195,6 +196,12 @@ const AddressPageContent = () => { ...@@ -195,6 +196,12 @@ const AddressPageContent = () => {
count: addressTabsCountersQuery.data?.internal_txs_count, count: addressTabsCountersQuery.data?.internal_txs_count,
component: <AddressInternalTxs scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>, component: <AddressInternalTxs scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
}, },
addressTabsCountersQuery.data?.celo_election_rewards_count ? {
id: 'epoch_rewards',
title: 'Epoch rewards',
count: addressTabsCountersQuery.data?.celo_election_rewards_count,
component: <AddressEpochRewards scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
} : undefined,
{ {
id: 'coin_balance_history', id: 'coin_balance_history',
title: 'Coin balance history', title: 'Coin balance history',
......
import { Tooltip } from '@chakra-ui/react';
import React from 'react';
import type { EpochRewardsType } from 'types/api/block';
import Tag from 'ui/shared/chakra/Tag';
type Props = {
type: EpochRewardsType;
isLoading?: boolean;
};
const TYPE_TAGS: Record<EpochRewardsType, { text: string; label: string; color: string }> = {
group: {
text: 'Validator group rewards',
// eslint-disable-next-line max-len
label: 'Reward given to a validator group. The address being viewed is the group\'s address; the associated address is the validator\'s address on whose behalf the reward was paid.',
color: 'teal',
},
validator: {
text: 'Validator rewards',
label: 'Reward given to a validator. The address being viewed is the validator\'s address; the associated address is the validator group\'s address.',
color: 'purple',
},
delegated_payment: {
text: 'Delegated payments',
// eslint-disable-next-line max-len
label: 'Reward portion delegated by a validator to another address. The address being viewed is the beneficiary receiving the reward; the associated address is the validator who set the delegation.',
color: 'blue',
},
voter: {
text: 'Voting rewards',
label: 'Reward given to a voter. The address being viewed is the voter\'s address; the associated address is the group address.',
color: 'yellow',
},
};
const EpochRewardTypeTag = ({ type, isLoading }: Props) => {
const { text, label, color } = TYPE_TAGS[type];
return (
<Tooltip label={ label } maxW="322px" textAlign="center">
<Tag colorScheme={ color } isLoading={ isLoading }>
{ text }
</Tag>
</Tooltip>
);
};
export default React.memo(EpochRewardTypeTag);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment