Skip to content

Commit

Permalink
Finish delegatee table
Browse files Browse the repository at this point in the history
  • Loading branch information
jmrossy committed Mar 9, 2024
1 parent b9a3468 commit 4ec7e7d
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 57 deletions.
2 changes: 1 addition & 1 deletion public/logos/delegatees/default.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions src/components/icons/Identicon.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import jazzicon from '@metamask/jazzicon';
import Image from 'next/image';
import { CSSProperties, PureComponent } from 'react';
import { Circle } from 'src/components/icons/Circle';
import { ZERO_ADDRESS } from 'src/config/consts';
import { isValidAddress, normalizeAddress } from 'src/utils/addresses';

type Props = {
Expand Down Expand Up @@ -38,3 +41,31 @@ export class Identicon extends PureComponent<Props> {
);
}
}

export function ImageOrIdenticon({
imgSrc,
address,
size,
}: {
imgSrc?: string;
address: Address;
size: number;
}) {
return (
<>
{imgSrc ? (
<Image
src={imgSrc}
height={size}
width={size}
alt=""
className="rounded-full border border-taupe-300"
/>
) : !address || address === ZERO_ADDRESS ? (
<Circle size={size} className="bg-yellow-500" />
) : (
<Identicon address={address} size={size} />
)}
</>
);
}
2 changes: 1 addition & 1 deletion src/components/logos/SocialLinkLogo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function SocialLinkLogo({ href, svgProps, type, className, size = 18 }: P
if (!Logo) throw new Error(`No logo for type ${type}`);

return (
<A_Blank href={href} title={type} className={className}>
<A_Blank href={href} title={type} className={className} onClick={(e) => e.stopPropagation()}>
<Logo {...svgProps} width={size} height={size} />
</A_Blank>
);
Expand Down
12 changes: 6 additions & 6 deletions src/config/delegates.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
[
{
{
"0xef268b5C05452D63a17Da12f562368e88a036Ef1": {
"name": "Celo Whale",
"address": "0xef268b5C05452D63a17Da12f562368e88a036Ef1",
"logoUri": "/logos/delegatees/default.svg",
"date": "2024-03-08",
"links": {
"website": "https://celowhale.com",
"twitter": "https://twitter.com/celowhale",
"github": "https://twitter.com/celowhale"
"website": "https://www.google.com/search?q=whale",
"twitter": "https://twitter.com",
"github": "https://github.com"
},
"interests": ["Fish", "Water", "Swimming"],
"description": "An unknown Celo whale account. One of the largest CELO holders in the world."
}
]
}
31 changes: 31 additions & 0 deletions src/features/delegation/DelegateeLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ImageOrIdenticon } from 'src/components/icons/Identicon';
import { getDelegateeMetadata } from 'src/features/delegation/delegateeMetadata';
import { shortenAddress } from 'src/utils/addresses';

export function DelegateeLogo({ address, size }: { address: Address; size: number }) {
const metadata = getDelegateeMetadata();
const imgSrc = metadata[address]?.logoUri;
return <ImageOrIdenticon imgSrc={imgSrc} address={address} size={size} />;
}

export function DelegateeLogoAndName({
address,
name,
size = 30,
className,
}: {
address: Address;
name?: string;
size?: number;
className?: string;
}) {
return (
<div className={`flex items-center ${className}`}>
<DelegateeLogo address={address} size={size} />
<div className="ml-2 flex flex-col">
<span>{name || 'Unknown Delegate'}</span>
<span className="font-mono text-xs text-taupe-600">{shortenAddress(address)}</span>
</div>
</div>
);
}
22 changes: 14 additions & 8 deletions src/features/delegation/DelegateesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import { useEffect, useMemo, useState } from 'react';
import { TabHeaderButton } from 'src/components/buttons/TabHeaderButton';
import { TableSortChevron } from 'src/components/icons/TableSortChevron';
import { SearchField } from 'src/components/input/SearchField';
import { SocialLinkLogo } from 'src/components/logos/SocialLinkLogo';
import { formatNumberString } from 'src/components/numbers/Amount';
import { SocialLinkType } from 'src/config/types';
import { DelegateeLogoAndName } from 'src/features/delegation/DelegateeLogo';
import { Delegatee } from 'src/features/delegation/types';
import { ValidatorGroupLogoAndName } from 'src/features/validators/ValidatorGroupLogo';
import { useIsMobile } from 'src/styles/mediaQueries';

const DESKTOP_ONLY_COLUMNS = ['interests', 'links'];
Expand Down Expand Up @@ -121,7 +123,11 @@ function useTableColumns() {
columnHelper.accessor('name', {
header: 'Name',
cell: (props) => (
<ValidatorGroupLogoAndName address={props.row.original.address} size={30} />
<DelegateeLogoAndName
address={props.row.original.address}
size={34}
name={props.getValue()}
/>
),
}),
columnHelper.accessor('interests', {
Expand All @@ -135,22 +141,22 @@ function useTableColumns() {
))}
</div>
),
enableSorting: false,
}),
columnHelper.accessor('links', {
header: 'Social',
cell: (props) => (
<div className="flex space-x-2">
{Object.entries(props.getValue()).map(([key, value], i) => (
<span key={i} className="rounded-md bg-taupe-100 px-2 py-1 text-xs">
{key + value}
</span>
<div className="flex space-x-3">
{Object.entries(props.getValue()).map(([type, href], i) => (
<SocialLinkLogo key={i} type={type as SocialLinkType} href={href} />
))}
</div>
),
enableSorting: false,
}),
columnHelper.accessor('delegatedBalance', {
header: 'Delegated',
cell: (props) => <div>{formatNumberString(props.getValue(), 0, true)}</div>,
cell: (props) => <div>{formatNumberString(props.getValue(), 0, true) + ' CELO'}</div>,
}),
];
}, []);
Expand Down
4 changes: 2 additions & 2 deletions src/features/delegation/DelegationsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { sortAndCombineChartData } from 'src/components/charts/chartData';
import { HeaderAndSubheader } from 'src/components/layout/HeaderAndSubheader';
import { DropdownMenu } from 'src/components/menus/Dropdown';
import { formatNumberString } from 'src/components/numbers/Amount';
import { DelegateeLogoAndName } from 'src/features/delegation/DelegateeLogo';
import { DelegateActionType, Delegatee, DelegationAmount } from 'src/features/delegation/types';
import { TransactionFlowType } from 'src/features/transactions/TransactionFlowType';
import { useTransactionModal } from 'src/features/transactions/TransactionModal';
import { ValidatorGroupLogoAndName } from 'src/features/validators/ValidatorGroupLogo';
import Ellipsis from 'src/images/icons/ellipsis.svg';
import { tableClasses } from 'src/styles/common';
import { fromWei } from 'src/utils/amount';
Expand Down Expand Up @@ -81,7 +81,7 @@ export function DelegationsTable({
{tableData.map(({ address, name, amount, percentage }) => (
<tr key={address}>
<td className={tableClasses.td}>
<ValidatorGroupLogoAndName address={address} name={name} />
<DelegateeLogoAndName address={address} name={name} />
</td>
<td className={tableClasses.td}>{formatNumberString(amount, 2) + ' CELO'}</td>
<td className={tableClasses.td}>{percentage + '%'}</td>
Expand Down
21 changes: 21 additions & 0 deletions src/features/delegation/delegateeMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import DelegateeJsonData from 'src/config/delegates.json';
import { DelegateeMetadata, DelegateeMetadataMapSchema } from 'src/features/delegation/types';
import { logger } from 'src/utils/logger';

let cachedMetadata: AddressTo<DelegateeMetadata>;

export function getDelegateeMetadata(): AddressTo<DelegateeMetadata> {
if (!cachedMetadata) {
cachedMetadata = parseDelegateeMetadata();
}
return cachedMetadata;
}

function parseDelegateeMetadata(): AddressTo<DelegateeMetadata> {
try {
return DelegateeMetadataMapSchema.parse(DelegateeJsonData);
} catch (error) {
logger.error('Error parsing delegatee metadata', error);
throw new Error('Invalid delegatee metadata');
}
}
2 changes: 1 addition & 1 deletion src/features/delegation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const DelegateeMetadataSchema = z.object({
description: z.string().min(1).max(1500),
});

export const DelegateeMetadataListSchema = z.array(DelegateeMetadataSchema);
export const DelegateeMetadataMapSchema = z.record(z.string(), DelegateeMetadataSchema);

export type DelegateeMetadata = z.infer<typeof DelegateeMetadataSchema>;

Expand Down
21 changes: 4 additions & 17 deletions src/features/delegation/useDelegatees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ import { lockedGoldABI } from '@celo/abis';
import { useQuery } from '@tanstack/react-query';
import { useToastError } from 'src/components/notifications/useToastError';
import { Addresses } from 'src/config/contracts';
import DelegateeJsonData from 'src/config/delegates.json';
import {
Delegatee,
DelegateeMetadata,
DelegateeMetadataListSchema,
} from 'src/features/delegation/types';
import { getDelegateeMetadata } from 'src/features/delegation/delegateeMetadata';
import { Delegatee, DelegateeMetadata } from 'src/features/delegation/types';
import { logger } from 'src/utils/logger';
import { MulticallReturnType, PublicClient } from 'viem';
import { usePublicClient } from 'wagmi';
Expand All @@ -20,8 +16,8 @@ export function useDelegatees() {
queryFn: async () => {
if (!publicClient) return null;
logger.debug('Fetching delegatees');
const metadata = parseDelegateeMetadata();
const addressToDelegatee = await fetchDelegateeStats(publicClient, metadata);
const cachedMetadata = Object.values(getDelegateeMetadata());
const addressToDelegatee = await fetchDelegateeStats(publicClient, cachedMetadata);
const delegatees = Object.values(addressToDelegatee);
return { addressToDelegatee, delegatees };
},
Expand All @@ -39,15 +35,6 @@ export function useDelegatees() {
};
}

function parseDelegateeMetadata(): DelegateeMetadata[] {
try {
return DelegateeMetadataListSchema.parse(DelegateeJsonData);
} catch (error) {
logger.error('Error parsing delegatee metadata', error);
throw new Error('Invalid delegatee metadata');
}
}

async function fetchDelegateeStats(
publicClient: PublicClient,
metadata: DelegateeMetadata[],
Expand Down
24 changes: 3 additions & 21 deletions src/features/validators/ValidatorGroupLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
import Image from 'next/image';
import { Circle } from 'src/components/icons/Circle';
import { Identicon } from 'src/components/icons/Identicon';
import { ZERO_ADDRESS } from 'src/config/consts';
import { ImageOrIdenticon } from 'src/components/icons/Identicon';
import { VALIDATOR_GROUPS } from 'src/config/validators';
import { shortenAddress } from 'src/utils/addresses';

export function ValidatorGroupLogo({ address, size }: { address: Address; size: number }) {
return (
<>
{VALIDATOR_GROUPS[address] ? (
<Image
src={VALIDATOR_GROUPS[address].logo}
height={size}
width={size}
alt=""
className="rounded-full border border-taupe-300"
/>
) : !address || address === ZERO_ADDRESS ? (
<Circle size={size} className="bg-yellow-500" />
) : (
<Identicon address={address} size={size} />
)}
</>
);
const imgSrc = VALIDATOR_GROUPS[address]?.logo;
return <ImageOrIdenticon imgSrc={imgSrc} address={address} size={size} />;
}

export function ValidatorGroupLogoAndName({
Expand Down

0 comments on commit 4ec7e7d

Please sign in to comment.