Skip to content

Commit 8f1c627

Browse files
alexcamboseaditya520
authored andcommitted
fix(dev-hub): feed ids
1 parent e50c60c commit 8f1c627

File tree

4 files changed

+155
-105
lines changed

4 files changed

+155
-105
lines changed

apps/developer-hub/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"katex": "catalog:",
3737
"next": "catalog:",
3838
"next-themes": "catalog:",
39+
"match-sorter": "catalog:",
3940
"@pythnetwork/react-hooks": "workspace:",
4041
"react": "catalog:",
4142
"react-aria": "catalog:",
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1-
.table {
2-
overflow-x: scroll;
1+
@use "@pythnetwork/component-library/theme";
2+
3+
.searchInput {
4+
width: 100%;
5+
}
6+
7+
.paginator {
8+
margin-bottom: theme.spacing(8);
39
}

apps/developer-hub/src/components/PriceFeedIdsCoreTable/index.tsx

Lines changed: 81 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,118 @@
11
"use client";
22

3+
import { Paginator } from "@pythnetwork/component-library/Paginator";
34
import { SearchInput } from "@pythnetwork/component-library/SearchInput";
4-
import { Spinner } from "@pythnetwork/component-library/Spinner";
5-
import type { ColumnConfig } from "@pythnetwork/component-library/Table";
6-
import { Table } from "@pythnetwork/component-library/Table";
5+
import { Table, type ColumnConfig } from "@pythnetwork/component-library/Table";
6+
import { useQueryParamFilterPagination } from "@pythnetwork/component-library/useQueryParamsPagination";
77
import { getPriceFeedAccountForProgram } from "@pythnetwork/pyth-solana-receiver";
88
import { Callout } from "fumadocs-ui/components/callout";
9-
import { useState, useEffect, useRef, useCallback, useMemo } from "react";
9+
import { matchSorter } from "match-sorter";
10+
import { useEffect, useState } from "react";
1011
import { z } from "zod";
11-
1212
import CopyAddress from "../CopyAddress";
1313
import styles from "./index.module.scss";
1414

1515
export const PriceFeedIdsCoreTable = () => {
16-
const isLoading = useRef(false);
1716
const [state, setState] = useState<State>(State.NotLoaded());
18-
1917
useEffect(() => {
20-
if (!isLoading.current) {
21-
setState(State.Loading());
22-
isLoading.current = true;
23-
getFeeds()
24-
.then((feeds) => {
25-
setState(State.Loaded(feeds));
26-
})
27-
.catch((error: unknown) => {
28-
setState(State.Failed(error));
29-
});
30-
}
31-
}, [isLoading]);
32-
33-
switch (state.type) {
34-
case StateType.Loading:
35-
case StateType.NotLoaded: {
36-
return <Spinner label="Fetching price feed ids..." />;
37-
}
38-
case StateType.Error: {
39-
return <Callout type="error">{errorToString(state.error)}</Callout>;
40-
}
41-
case StateType.Loaded: {
42-
return <LoadedResults feeds={state.feeds} />;
43-
}
44-
}
45-
};
18+
setState(State.Loading());
19+
getFeeds()
20+
.then((feeds) => {
21+
setState(State.Loaded(feeds));
22+
})
23+
.catch((error: unknown) => {
24+
setState(State.Failed(error));
25+
});
26+
}, []);
4627

47-
const LoadedResults = ({
48-
feeds,
49-
}: {
50-
feeds: Awaited<ReturnType<typeof getFeeds>>;
51-
}) => {
5228
const columns: ColumnConfig<Col>[] = [
53-
{ id: "symbol", name: "Symbol" },
29+
{ id: "symbol", name: "Symbol", isRowHeader: true },
5430
{ id: "stableFeedId", name: "Stable Price Feed ID" },
5531
{ id: "betaFeedId", name: "Beta Price Feed ID" },
5632
{ id: "solanaPriceFeedAccount", name: "Solana Price Feed Account" },
5733
];
58-
const [search, setSearch] = useState("");
59-
const handleSearchChange = useCallback((value: string) => {
60-
setSearch(value);
61-
}, []);
62-
const filteredFeeds = useMemo(
63-
() =>
64-
feeds.filter((feed) => {
65-
const searchLower = search.toLowerCase();
66-
return [
67-
feed.symbol,
68-
feed.stableFeedId,
69-
feed.betaFeedId,
70-
feed.solanaPriceFeedAccount,
71-
].some((value) => value?.toLowerCase().includes(searchLower));
72-
}),
73-
[feeds, search],
34+
35+
const {
36+
search,
37+
sortDescriptor,
38+
page,
39+
pageSize,
40+
updateSearch,
41+
updateSortDescriptor,
42+
updatePage,
43+
updatePageSize,
44+
paginatedItems,
45+
numPages,
46+
mkPageLink,
47+
} = useQueryParamFilterPagination(
48+
state.type === StateType.Loaded ? state.feeds : [],
49+
() => true,
50+
() => 1,
51+
(items, searchString) => {
52+
return matchSorter(items, searchString, {
53+
keys: [
54+
"symbol",
55+
"stableFeedId",
56+
"betaFeedId",
57+
"solanaPriceFeedAccount",
58+
],
59+
});
60+
},
61+
{ defaultSort: "symbol", defaultPageSize: 10 },
7462
);
7563

64+
if (state.type === StateType.Error) {
65+
return <Callout type="error">{errorToString(state.error)}</Callout>;
66+
}
67+
68+
const isLoading =
69+
state.type === StateType.Loading || state.type === StateType.NotLoaded;
70+
71+
const rows = paginatedItems.map((feed) => ({
72+
id: feed.symbol,
73+
data: {
74+
symbol: feed.symbol,
75+
stableFeedId: feed.stableFeedId ? (
76+
<CopyAddress maxLength={6} address={feed.stableFeedId} />
77+
) : undefined,
78+
betaFeedId: feed.betaFeedId ? (
79+
<CopyAddress maxLength={6} address={feed.betaFeedId} />
80+
) : undefined,
81+
solanaPriceFeedAccount: feed.solanaPriceFeedAccount ? (
82+
<CopyAddress maxLength={6} address={feed.solanaPriceFeedAccount} />
83+
) : undefined,
84+
},
85+
}));
86+
7687
return (
7788
<>
7889
<SearchInput
7990
label="Search price feeds"
8091
placeholder="Search by symbol or feed id"
8192
value={search}
82-
onChange={handleSearchChange}
83-
width={480}
93+
onChange={updateSearch}
94+
className={styles.searchInput ?? ""}
8495
/>
96+
8597
<Table<Col>
98+
{...(isLoading ? { isLoading: true } : { isLoading: false, rows })}
8699
label="Price feed ids"
87100
columns={columns}
88-
rows={filteredFeeds.map((feed) => ({
89-
id: feed.symbol,
90-
data: {
91-
symbol: feed.symbol,
92-
stableFeedId: feed.stableFeedId ? (
93-
<CopyAddress maxLength={6} address={feed.stableFeedId} />
94-
) : undefined,
95-
betaFeedId: feed.betaFeedId ? (
96-
<CopyAddress maxLength={6} address={feed.betaFeedId} />
97-
) : undefined,
98-
solanaPriceFeedAccount: feed.solanaPriceFeedAccount ? (
99-
<CopyAddress
100-
maxLength={6}
101-
address={feed.solanaPriceFeedAccount}
102-
/>
103-
) : undefined,
104-
},
105-
}))}
106-
className={styles.table ?? ""}
101+
onSortChange={updateSortDescriptor}
102+
sortDescriptor={sortDescriptor}
107103
stickyHeader="top"
108104
fill
109105
rounded
110106
/>
107+
<Paginator
108+
numPages={numPages}
109+
currentPage={page}
110+
onPageChange={updatePage}
111+
pageSize={pageSize}
112+
onPageSizeChange={updatePageSize}
113+
mkPageLink={mkPageLink}
114+
className={styles.paginator ?? ""}
115+
/>
111116
</>
112117
);
113118
};

0 commit comments

Comments
 (0)