setDropdown(false)} />
+ )}
-
-
-
-
- Rank |
- Address |
- Balance (SOL) |
- % of Total Supply |
- Details |
-
-
-
- {accounts.map((account, index) =>
- renderAccountRow(account, index, supply)
- )}
-
-
+
+
+
+
+
Largest Accounts
+
+
+
+ setDropdown(show => !show)}
+ show={showDropdown}
+ />
+
+
+
+
+
+
+
+
+ Rank |
+ Address |
+ Balance (SOL) |
+ % of {header} Supply |
+ Details |
+
+
+
+ {accounts.map((account, index) =>
+ renderAccountRow(account, index, supplyCount)
+ )}
+
+
+
-
+ >
);
}
-const renderHeader = () => {
+const useQueryFilter = (): Filter => {
+ const query = useQuery();
+ const filter = query.get("filter");
+ if (filter === "circulating" || filter === "nonCirculating") {
+ return filter;
+ } else {
+ return null;
+ }
+};
+
+const filterTitle = (filter: Filter): string => {
+ switch (filter) {
+ case "circulating": {
+ return "Circulating";
+ }
+ case "nonCirculating": {
+ return "Non-Circulating";
+ }
+ default: {
+ return "All";
+ }
+ }
+};
+
+type DropdownProps = {
+ filter: Filter;
+ toggle: () => void;
+ show: boolean;
+};
+
+const FilterDropdown = ({ filter, toggle, show }: DropdownProps) => {
+ const buildLocation = (location: Location, filter: Filter) => {
+ const params = new URLSearchParams(location.search);
+ if (filter === null) {
+ params.delete("filter");
+ } else {
+ params.set("filter", filter);
+ }
+ return {
+ ...location,
+ search: params.toString()
+ };
+ };
+
+ const FILTERS: Filter[] = [null, "circulating", "nonCirculating"];
return (
-
-
-
-
Largest Accounts
-
+
+
+
+ {FILTERS.map(filterOption => {
+ return (
+ buildLocation(location, filterOption)}
+ className={`dropdown-item${
+ filterOption === filter ? " active" : ""
+ }`}
+ onClick={toggle}
+ >
+ {filterTitle(filterOption)}
+
+ );
+ })}
);
diff --git a/explorer/src/providers/richList.tsx b/explorer/src/providers/richList.tsx
index d236542b67..daf0a9f5cc 100644
--- a/explorer/src/providers/richList.tsx
+++ b/explorer/src/providers/richList.tsx
@@ -9,13 +9,13 @@ export enum Status {
Connecting
}
-type RichList = {
- accounts: AccountBalancePair[];
- totalSupply: number;
- circulatingSupply: number;
+type RichLists = {
+ total: AccountBalancePair[];
+ circulating: AccountBalancePair[];
+ nonCirculating: AccountBalancePair[];
};
-type State = RichList | Status | string;
+type State = RichLists | Status | string;
type Dispatch = React.Dispatch
>;
const StateContext = React.createContext(undefined);
@@ -28,9 +28,16 @@ export function RichListProvider({ children }: Props) {
React.useEffect(() => {
if (state !== Status.Idle) {
- if (clusterStatus === ClusterStatus.Connecting)
- setState(Status.Disconnected);
- if (clusterStatus === ClusterStatus.Connected) fetch(setState, url);
+ switch (clusterStatus) {
+ case ClusterStatus.Connecting: {
+ setState(Status.Disconnected);
+ break;
+ }
+ case ClusterStatus.Connected: {
+ fetch(setState, url);
+ break;
+ }
+ }
}
}, [clusterStatus, url]); // eslint-disable-line react-hooks/exhaustive-deps
@@ -48,17 +55,19 @@ async function fetch(dispatch: Dispatch, url: string) {
try {
const connection = new Connection(url, "max");
- const supply = (await connection.getSupply()).value;
- const accounts = (await connection.getLargestAccounts()).value;
+
+ const [total, circulating, nonCirculating] = (
+ await Promise.all([
+ connection.getLargestAccounts(),
+ connection.getLargestAccounts({ filter: "circulating" }),
+ connection.getLargestAccounts({ filter: "nonCirculating" })
+ ])
+ ).map(response => response.value);
// Update state if still connecting
dispatch(state => {
if (state !== Status.Connecting) return state;
- return {
- accounts,
- totalSupply: supply.total,
- circulatingSupply: supply.circulating
- };
+ return { total, circulating, nonCirculating };
});
} catch (err) {
console.error("Failed to fetch", err);