Skip to content

Commit 17f9b75

Browse files
committed
resolved comments
1 parent 1a298ee commit 17f9b75

File tree

3 files changed

+584
-171
lines changed

3 files changed

+584
-171
lines changed

components/PriceFeedTable.tsx

Lines changed: 145 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,161 @@
11
import { useState, useEffect } from "react";
2-
import { TextField, Select, MenuItem, Box } from "@mui/material";
3-
import { HermesClient } from "@pythnetwork/hermes-client";
2+
import { TextField, Select, MenuItem } from "@mui/material";
3+
import { HermesClient, PriceFeedMetadata } from "@pythnetwork/hermes-client";
44
import { Table, Td, Th, Tr, CopyToClipboard } from "nextra/components";
55

6-
interface PriceFeed {
7-
id: string;
8-
name: string;
9-
assetType: string;
6+
const fetchStablePriceFeeds = async () => {
7+
const priceFeeds = await new HermesClient(
8+
"https://hermes.pyth.network"
9+
).getPriceFeeds();
10+
const assetTypes = Array.from(
11+
new Set(priceFeeds.map((feed) => feed.attributes.asset_type ?? ""))
12+
);
13+
console.log(priceFeeds);
14+
return { priceFeeds, assetTypes };
15+
};
16+
17+
const fetchBetaPriceFeeds = async () => {
18+
const priceFeeds = await new HermesClient(
19+
"https://hermes-beta.pyth.network"
20+
).getPriceFeeds();
21+
const assetTypes = Array.from(
22+
new Set(priceFeeds.map((feed) => feed.attributes.asset_type ?? ""))
23+
);
24+
console.log(priceFeeds);
25+
return { priceFeeds, assetTypes };
26+
};
27+
28+
type AssetTypesSelectorProps = {
29+
priceFeedsState: PriceFeedsState;
30+
selectedAssetType: string;
31+
setSelectedAssetType: (assetType: string) => void;
32+
};
33+
34+
enum PriceFeedsStateType {
35+
NotLoaded,
36+
Loading,
37+
Loaded,
38+
Error,
1039
}
1140

12-
export function PriceFeedTable() {
13-
const [priceFeeds, setPriceFeeds] = useState<PriceFeed[]>([]);
14-
const [searchTerm, setSearchTerm] = useState("");
15-
const [selectedAssetType, setSelectedAssetType] = useState("All");
41+
const PriceFeedsState = {
42+
NotLoaded: () => ({ type: PriceFeedsStateType.NotLoaded as const }),
43+
Loading: () => ({ type: PriceFeedsStateType.Loading as const }),
44+
Loaded: (priceFeeds: PriceFeedMetadata[], assetTypes: string[]) => ({
45+
type: PriceFeedsStateType.Loaded as const,
46+
priceFeeds,
47+
assetTypes,
48+
}),
49+
Error: (error: unknown) => ({
50+
type: PriceFeedsStateType.Error as const,
51+
error,
52+
}),
53+
};
54+
55+
type PriceFeedsState = ReturnType<
56+
typeof PriceFeedsState[keyof typeof PriceFeedsState]
57+
>;
1658

17-
// enum AssetTypesStateType {
18-
// NotLoaded,
19-
// Loading,
20-
// Loaded,
21-
// Error,
22-
// }
23-
24-
// const AssetTypesState = {
25-
// NotLoaded: () => ({ type: AssetTypesStateType.NotLoaded as const }),
26-
// Loading: () => ({ type: AssetTypesStateType.Loading as const }),
27-
// Loaded: (assetTypes: string[]) => ({
28-
// type: AssetTypesStateType.Loaded as const,
29-
// assetTypes,
30-
// }),
31-
// Error: (error: unknown) => ({
32-
// type: AssetTypesStateType.Error as const,
33-
// error,
34-
// }),
35-
// };
36-
37-
const fetchAssetTypes = async () => {
38-
const hermesClient = new HermesClient("https://hermes.pyth.network");
39-
const feeds = await hermesClient.getPriceFeeds();
40-
return Array.from(
41-
new Set(feeds.map((feed) => feed.attributes.asset_type ?? ""))
42-
);
43-
};
44-
45-
// const useAssetTypes = (): typeof AssetTypesState => {
46-
// const [assetTypes, setAssetTypes] = useState<typeof AssetTypesState>(
47-
// AssetTypesState.NotLoaded()
48-
// );
49-
50-
// useEffect(() => {
51-
// setAssetTypes(AssetTypesState.Loading());
52-
// }, []);
53-
54-
// return assetTypes;
55-
// };
56-
57-
// type AssetTypesSelectorProps = {
58-
// selectedAssetType: string;
59-
// setSelectedAssetType: (assetType: string) => void;
60-
// };
61-
62-
// const AssetTypesSelector = ({
63-
// selectedAssetType,
64-
// setSelectedAssetType,
65-
// }: AssetTypesSelectorProps) => {
66-
// const assetTypes = useAssetTypes();
67-
// };
59+
const usePriceFeeds = (): PriceFeedsState => {
60+
const [priceFeeds, setPriceFeeds] = useState<PriceFeedsState>(
61+
PriceFeedsState.NotLoaded()
62+
);
6863

6964
useEffect(() => {
70-
const fetchPriceFeeds = async () => {
71-
const hermesClient = new HermesClient("https://hermes.pyth.network");
72-
const feeds = await hermesClient.getPriceFeeds();
73-
const transformedFeeds = feeds.map((feed) => ({
74-
id: feed.id,
75-
name: feed.attributes.display_symbol || "",
76-
assetType: feed.attributes.asset_type || "",
77-
}));
78-
setPriceFeeds(transformedFeeds);
79-
};
80-
81-
fetchPriceFeeds();
65+
setPriceFeeds(PriceFeedsState.Loading());
66+
fetchStablePriceFeeds()
67+
.then(({ priceFeeds, assetTypes }) => {
68+
setPriceFeeds(PriceFeedsState.Loaded(priceFeeds, assetTypes));
69+
})
70+
.catch((error) => {
71+
setPriceFeeds(PriceFeedsState.Error(error));
72+
});
8273
}, []);
8374

84-
const filteredData = priceFeeds.filter((feed) => {
85-
const matchesSearch =
86-
feed.id.toLowerCase().includes(searchTerm.toLowerCase()) ||
87-
feed.name.toLowerCase().includes(searchTerm.toLowerCase());
88-
const matchesAssetType =
89-
selectedAssetType === "All" || feed.assetType === selectedAssetType;
90-
return matchesSearch && matchesAssetType;
91-
});
92-
return (
93-
<Box>
94-
<Box sx={{ mb: 3, display: "flex", gap: 2 }}>
95-
<TextField
96-
label="Search price feeds"
97-
variant="outlined"
98-
size="small"
99-
value={searchTerm}
100-
onChange={(e) => setSearchTerm(e.target.value)}
101-
sx={{ width: 300 }}
102-
/>
75+
return priceFeeds;
76+
};
77+
78+
const AssetTypesSelect = ({
79+
priceFeedsState,
80+
selectedAssetType,
81+
setSelectedAssetType,
82+
}: AssetTypesSelectorProps) => {
83+
const priceFeeds = usePriceFeeds();
84+
85+
switch (priceFeeds.type) {
86+
case PriceFeedsStateType.NotLoaded:
87+
case PriceFeedsStateType.Loading:
88+
case PriceFeedsStateType.Error:
89+
return <p>Error loading asset types</p>;
90+
case PriceFeedsStateType.Loaded:
91+
return (
10392
<Select
10493
value={selectedAssetType}
10594
onChange={(e) => setSelectedAssetType(e.target.value)}
10695
size="small"
10796
sx={{ width: 200 }}
10897
>
10998
<MenuItem value="All">All Asset Types</MenuItem>
110-
{Array.from(new Set(priceFeeds.map((feed) => feed.assetType))).map(
111-
(type) => (
112-
<MenuItem key={type} value={type}>
113-
{type || "Uncategorized"}
114-
</MenuItem>
115-
)
116-
)}
99+
{priceFeeds.assetTypes.map((type) => (
100+
<MenuItem key={type} value={type}>
101+
{type ?? "Uncategorized"}
102+
</MenuItem>
103+
))}
117104
</Select>
118-
</Box>
105+
);
106+
}
107+
};
108+
109+
export function PriceFeedTable() {
110+
const [searchTerm, setSearchTerm] = useState("");
111+
const [selectedAssetType, setSelectedAssetType] = useState("All");
112+
const priceFeedsState = usePriceFeeds();
113+
114+
<AssetTypesSelect
115+
priceFeedsState={priceFeedsState}
116+
selectedAssetType={selectedAssetType}
117+
setSelectedAssetType={setSelectedAssetType}
118+
/>;
119+
120+
let filteredData: PriceFeedMetadata[] = [];
121+
if (priceFeedsState.type === PriceFeedsStateType.Loaded) {
122+
filteredData = priceFeedsState.priceFeeds.filter((feed) => {
123+
const matchesSearch =
124+
feed.id.toLowerCase().includes(searchTerm.toLowerCase()) ||
125+
feed.attributes.display_symbol
126+
.toLowerCase()
127+
.includes(searchTerm.toLowerCase());
128+
const matchesAssetType =
129+
selectedAssetType === "All" ||
130+
feed.attributes.asset_type === selectedAssetType;
131+
return matchesSearch && matchesAssetType;
132+
});
133+
}
134+
135+
return (
136+
<>
137+
<TextField
138+
label="Search price feeds"
139+
variant="outlined"
140+
size="small"
141+
value={searchTerm}
142+
onChange={(e) => setSearchTerm(e.target.value)}
143+
sx={{ width: 300 }}
144+
/>
145+
<Select
146+
value={selectedAssetType}
147+
onChange={(e) => setSelectedAssetType(e.target.value)}
148+
size="small"
149+
sx={{ width: 200 }}
150+
>
151+
<MenuItem value="All">All Asset Types</MenuItem>
152+
{priceFeedsState.type === PriceFeedsStateType.Loaded &&
153+
priceFeedsState.assetTypes.map((type) => (
154+
<MenuItem key={type} value={type}>
155+
{type || "Uncategorized"}
156+
</MenuItem>
157+
))}
158+
</Select>
119159

120160
<Table>
121161
<thead>
@@ -128,16 +168,16 @@ export function PriceFeedTable() {
128168
<tbody>
129169
{filteredData.map((feed) => (
130170
<Tr key={feed.id}>
131-
<Td>{feed.name}</Td>
132-
<Td>{feed.assetType}</Td>
133-
<Td>
171+
<Td>{feed.attributes.display_symbol}</Td>
172+
<Td>{feed.attributes.asset_type}</Td>
173+
<Td className="font-mono whitespace-nowrap">
134174
{feed.id}
135-
<CopyToClipboard getValue={() => feed.id} />
175+
<CopyToClipboard className="ml-2" getValue={() => feed.id} />
136176
</Td>
137177
</Tr>
138178
))}
139179
</tbody>
140180
</Table>
141-
</Box>
181+
</>
142182
);
143183
}

0 commit comments

Comments
 (0)