Skip to content

Commit c2fd55b

Browse files
Added Rich List Page
1 parent ddb52b2 commit c2fd55b

9 files changed

Lines changed: 229 additions & 3 deletions

File tree

src/app/rich-list/page.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import ViewRichList from '@/views/rich-list';
2+
3+
export default function PageRichList() {
4+
return (
5+
<>
6+
<ViewRichList />
7+
8+
</>
9+
);
10+
}

src/app/validators/page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export default function PageValidators() {
44
return (
55
<>
66
<ViewValidators />
7-
{/* <pre>{JSON.stringify(producersData, null, 2)}</pre> */}
87
</>
98
);
109
}

src/components/header.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import HeaderSearch from './header-search';
1313

1414
const links = [
1515
{
16-
url: '/',
17-
label: 'Dashboard',
16+
url: '/rich-list',
17+
label: 'Rich List',
1818
},
1919
{
2020
url: '/validators',

src/hooks/api.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import type {
1818
ResponseOrdinalsMarketcap,
1919
ResponseGetDefillama,
2020
ResponseChainInfo2,
21+
ResponseLiquidRichList,
22+
ResponseStakedRichList,
2123
ParamsGetAccountTokens,
2224
ResponseGetAccountTokens,
2325
} from '@/types';
@@ -114,6 +116,20 @@ export const useProducers = () => {
114116
});
115117
};
116118

119+
export const useLiquidRichList = () => {
120+
return useQuery<ResponseLiquidRichList, Error>({
121+
queryKey: ['liquidrichlist'],
122+
queryFn: api.getLiquidRichList,
123+
});
124+
};
125+
126+
export const useStakedRichList = () => {
127+
return useQuery<ResponseStakedRichList, Error>({
128+
queryKey: ['stakedrichlist'],
129+
queryFn: api.getStakedRichList,
130+
});
131+
};
132+
117133
export const useTokens = () => {
118134
return useQuery<ResponseGetTokens, Error>({
119135
queryKey: ['coinInfo'],

src/lib/api.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ export const getChainInfo2 = async () => {
2828
);
2929
return data;
3030
};
31+
export const getLiquidRichList = async () => {
32+
const { data } = await axios.get(
33+
`https://dashboard-api.libre.org/stats/libre/liquid`,
34+
);
35+
return data;
36+
};
37+
38+
export const getStakedRichList = async () => {
39+
const { data } = await axios.get(
40+
`https://dashboard-api.libre.org/stats/libre/staker-richlist`,
41+
);
42+
return data;
43+
};
3144

3245
export const getExchangeRates = async () => {
3346
const { data } = await axios.get(

src/types.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ export type ResponseChainInfo2 = {
3737
last_irreversible_block_time: string;
3838
};
3939

40+
41+
export type ResponseLiquidRichList = {
42+
account: string;
43+
amount: number;
44+
}[];
45+
46+
export type ResponseStakedRichList = {
47+
account: string;
48+
amount: number;
49+
}[];
50+
4051
export type ResponseExchangeRates = {
4152
PBTC: number;
4253
LIBRE: number;

src/views/rich-list/index.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use client';
2+
3+
import RichListTable from './table';
4+
import { useLiquidRichList, useStakedRichList } from '@/hooks/api';
5+
import Loading from '@/components/loading';
6+
7+
export default function ViewRichList() {
8+
9+
const liquidRichListQuery = useLiquidRichList();
10+
const stakedRichListQuery = useStakedRichList();
11+
12+
if (liquidRichListQuery.isLoading || stakedRichListQuery.isLoading) {
13+
return <Loading />;
14+
}
15+
16+
if (liquidRichListQuery.isError || stakedRichListQuery.isError) {
17+
return (
18+
<div className='container py-20 text-center'>
19+
<div className='mt-10'>
20+
Error: {liquidRichListQuery.error?.message || stakedRichListQuery.error?.message}
21+
</div>
22+
</div>
23+
);
24+
}
25+
const liquidRichListData = liquidRichListQuery.data ? liquidRichListQuery.data : [];
26+
const stakedRichListData = stakedRichListQuery.data ? stakedRichListQuery.data : [];
27+
28+
29+
return (
30+
<div className='container my-12'>
31+
<RichListTable data={liquidRichListData} data2={stakedRichListData} /> </div>
32+
);
33+
}

src/views/rich-list/table.tsx

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
'use client';
2+
3+
import { Table, TableHead, TableRow } from '@mui/material';
4+
import * as S from '@/styles/table';
5+
import { motion } from 'framer-motion';
6+
import type { RichListTableProps } from './types';
7+
import Link from 'next/link';
8+
import * as React from 'react';
9+
10+
import * as Switch from '@radix-ui/react-switch';
11+
import clsx from 'clsx';
12+
const MotionTableRow = motion(TableRow);
13+
14+
interface DataItem {
15+
rank: number;
16+
account: string;
17+
amount: number;
18+
url?: string;
19+
}
20+
21+
interface ValidatorsTableProps {
22+
liquidData: DataItem[];
23+
stakedData: DataItem[];
24+
}
25+
26+
export default function RichListTable({ data, data2 }: RichListTableProps) {
27+
const numberFormat = new Intl.NumberFormat('en-US', { style: 'decimal' });
28+
29+
const [showLiquid, setShowLiquid] = React.useState(false); // if (true) default:topstakers
30+
const toggleDataView = () => setShowLiquid(!showLiquid);
31+
const dataToDisplay = showLiquid ? data : data2;
32+
33+
34+
return (
35+
<>
36+
<div className='flex items-center mb-6 justify-center'>
37+
<div
38+
className={clsx('text-base font-medium leading-none transition', {
39+
'text-shade-400': showLiquid,
40+
'text-black': !showLiquid,
41+
})}
42+
>
43+
Top Holders
44+
</div>
45+
<Switch.Root
46+
checked={showLiquid}
47+
onCheckedChange={toggleDataView}
48+
className='relative mx-4 w-16 rounded-full bg-shade-100 py-1.5 outline-none border'
49+
style={{ WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)' }}
50+
>
51+
<Switch.Thumb className='block h-6 w-6 translate-x-1.5 rounded-full bg-indigo-500 transition will-change-transform data-[state=checked]:translate-x-[34px]' />
52+
</Switch.Root>
53+
<div className='relative'>
54+
<div
55+
className={clsx('text-base font-medium leading-none transition', {
56+
'text-shade-400': !showLiquid,
57+
'text-black': showLiquid,
58+
})}
59+
>
60+
Top Stakers
61+
</div>
62+
</div>
63+
</div>
64+
65+
66+
<div className='w-full overflow-x-auto rounded-md border border-shade-200 bg-white'>
67+
<Table aria-label='Validators Table'>
68+
<TableHead>
69+
<S.StyledTableRow>
70+
<S.StyledTableHeadCell size='medium'>RANK</S.StyledTableHeadCell>
71+
<S.StyledTableHeadCell size='medium'>
72+
ACCOUNT
73+
</S.StyledTableHeadCell>
74+
<S.StyledTableHeadCell size='medium'>
75+
TOTAL
76+
</S.StyledTableHeadCell>
77+
78+
</S.StyledTableRow>
79+
</TableHead>
80+
<S.StyledTableBody>
81+
{dataToDisplay.map((item, index) => (
82+
<MotionTableRow
83+
key={index}
84+
initial={{ height: 0, opacity: 0 }}
85+
animate={{
86+
height: 'auto',
87+
display: 'table-row',
88+
opacity: 1,
89+
transition: {
90+
duration: 0.6,
91+
},
92+
}}
93+
exit={{
94+
height: 0,
95+
opacity: 0,
96+
display: 'none',
97+
transition: {
98+
duration: 0.2,
99+
},
100+
}}
101+
>
102+
<S.StyledTableCell size='medium'>
103+
<span className='text-primary'>{index+1}</span>
104+
</S.StyledTableCell>
105+
<S.StyledTableCell size='medium'>
106+
<Link
107+
href={`/address/${item.account}`}
108+
className='inline-block max-w-full truncate align-middle hover:underline'
109+
>
110+
<span className=''>{item.account}</span>
111+
</Link>
112+
</S.StyledTableCell>
113+
<S.StyledTableCell size='medium'>
114+
<span className=''>{numberFormat.format(item.amount)}</span>
115+
</S.StyledTableCell>
116+
117+
118+
<S.StyledTableCell size='medium'>
119+
<a
120+
href="{row.url}"
121+
target='_blank'
122+
className='text-primary hover:underline'
123+
>
124+
125+
</a>
126+
</S.StyledTableCell>
127+
</MotionTableRow>
128+
))}
129+
</S.StyledTableBody>
130+
</Table>
131+
</div>
132+
</>
133+
);
134+
}

src/views/rich-list/types.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { ResponseLiquidRichList,ResponseStakedRichList } from '@/types';
2+
3+
4+
export type RichListTableProps = {
5+
data2: ResponseStakedRichList;
6+
data: ResponseLiquidRichList;
7+
};
8+
9+
10+

0 commit comments

Comments
 (0)