Skip to content

Commit e35e701

Browse files
authored
Merge pull request #2217 from pyth-network/cprussin/optimizations
feat(insights): optimize page payload sizes
2 parents 426c758 + c7ca871 commit e35e701

29 files changed

+925
-491
lines changed

apps/insights/src/components/ChangePercent/index.tsx

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const ONE_HOUR_IN_MS = 60 * ONE_MINUTE_IN_MS;
1414
const REFRESH_YESTERDAYS_PRICES_INTERVAL = ONE_HOUR_IN_MS;
1515

1616
type Props = Omit<ComponentProps<typeof YesterdaysPricesContext>, "value"> & {
17-
feeds: (Feed & { symbol: string })[];
17+
feeds: Record<string, string>;
1818
};
1919

2020
const YesterdaysPricesContext = createContext<
@@ -23,7 +23,7 @@ const YesterdaysPricesContext = createContext<
2323

2424
export const YesterdaysPricesProvider = ({ feeds, ...props }: Props) => {
2525
const state = useData(
26-
["yesterdaysPrices", feeds.map((feed) => feed.symbol)],
26+
["yesterdaysPrices", Object.keys(feeds)],
2727
() => getYesterdaysPrices(feeds),
2828
{
2929
refreshInterval: REFRESH_YESTERDAYS_PRICES_INTERVAL,
@@ -34,22 +34,16 @@ export const YesterdaysPricesProvider = ({ feeds, ...props }: Props) => {
3434
};
3535

3636
const getYesterdaysPrices = async (
37-
feeds: (Feed & { symbol: string })[],
37+
feeds: Props["feeds"],
3838
): Promise<Map<string, number>> => {
3939
const url = new URL("/yesterdays-prices", window.location.origin);
40-
for (const feed of feeds) {
41-
url.searchParams.append("symbols", feed.symbol);
40+
for (const symbol of Object.keys(feeds)) {
41+
url.searchParams.append("symbols", symbol);
4242
}
4343
const response = await fetch(url);
44-
const data: unknown = await response.json();
44+
const data = yesterdaysPricesSchema.parse(await response.json());
4545
return new Map(
46-
Object.entries(yesterdaysPricesSchema.parse(data)).map(
47-
([symbol, value]) => [
48-
feeds.find((feed) => feed.symbol === symbol)?.product.price_account ??
49-
"",
50-
value,
51-
],
52-
),
46+
Object.entries(data).map(([symbol, value]) => [feeds[symbol] ?? "", value]),
5347
);
5448
};
5549

@@ -67,39 +61,28 @@ const useYesterdaysPrices = () => {
6761

6862
type ChangePercentProps = {
6963
className?: string | undefined;
70-
feed: Feed;
64+
feedKey: string;
7165
};
7266

73-
type Feed = {
74-
product: {
75-
price_account: string;
76-
};
77-
};
78-
79-
export const ChangePercent = ({ feed, className }: ChangePercentProps) => {
67+
export const ChangePercent = ({ feedKey, className }: ChangePercentProps) => {
8068
const yesterdaysPriceState = useYesterdaysPrices();
8169

8270
switch (yesterdaysPriceState.type) {
83-
case StateType.Error: {
84-
// eslint-disable-next-line unicorn/no-null
85-
return null;
86-
}
87-
71+
case StateType.Error:
8872
case StateType.Loading:
8973
case StateType.NotLoaded: {
9074
return <ChangeValue className={className} isLoading />;
9175
}
9276

9377
case StateType.Loaded: {
94-
const yesterdaysPrice = yesterdaysPriceState.data.get(
95-
feed.product.price_account,
96-
);
97-
// eslint-disable-next-line unicorn/no-null
98-
return yesterdaysPrice === undefined ? null : (
78+
const yesterdaysPrice = yesterdaysPriceState.data.get(feedKey);
79+
return yesterdaysPrice === undefined ? (
80+
<ChangeValue className={className} isLoading />
81+
) : (
9982
<ChangePercentLoaded
10083
className={className}
10184
priorPrice={yesterdaysPrice}
102-
feed={feed}
85+
feedKey={feedKey}
10386
/>
10487
);
10588
}
@@ -109,15 +92,15 @@ export const ChangePercent = ({ feed, className }: ChangePercentProps) => {
10992
type ChangePercentLoadedProps = {
11093
className?: string | undefined;
11194
priorPrice: number;
112-
feed: Feed;
95+
feedKey: string;
11396
};
11497

11598
const ChangePercentLoaded = ({
11699
className,
117100
priorPrice,
118-
feed,
101+
feedKey,
119102
}: ChangePercentLoadedProps) => {
120-
const currentPrice = useLivePrice(feed);
103+
const currentPrice = useLivePrice(feedKey);
121104

122105
return currentPrice === undefined ? (
123106
<ChangeValue className={className} isLoading />

apps/insights/src/components/FeedKey/index.tsx

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ import { toHex, truncateHex } from "../../hex";
44
import { CopyButton } from "../CopyButton";
55

66
type OwnProps = {
7-
feed: {
8-
product: {
9-
price_account: string;
10-
};
11-
};
7+
feedKey: string;
128
};
139

1410
type Props = Omit<
@@ -17,15 +13,12 @@ type Props = Omit<
1713
> &
1814
OwnProps;
1915

20-
export const FeedKey = ({ feed, ...props }: Props) => {
21-
const key = useMemo(
22-
() => toHex(feed.product.price_account),
23-
[feed.product.price_account],
24-
);
25-
const truncatedKey = useMemo(() => truncateHex(key), [key]);
16+
export const FeedKey = ({ feedKey, ...props }: Props) => {
17+
const hexKey = useMemo(() => toHex(feedKey), [feedKey]);
18+
const truncatedKey = useMemo(() => truncateHex(hexKey), [hexKey]);
2619

2720
return (
28-
<CopyButton text={key} {...props}>
21+
<CopyButton text={hexKey} {...props}>
2922
{truncatedKey}
3023
</CopyButton>
3124
);

apps/insights/src/components/LivePrices/index.tsx

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,35 +38,28 @@ type LivePricesProviderProps = Omit<
3838
"value"
3939
>;
4040

41-
export const LivePricesProvider = ({ ...props }: LivePricesProviderProps) => {
41+
export const LivePricesProvider = (props: LivePricesProviderProps) => {
4242
const priceData = usePriceData();
4343

4444
return <LivePricesContext value={priceData} {...props} />;
4545
};
4646

47-
type Feed = {
48-
product: {
49-
price_account: string;
50-
};
51-
};
52-
53-
export const useLivePrice = (feed: Feed) => {
54-
const { price_account } = feed.product;
47+
export const useLivePrice = (feedKey: string) => {
5548
const { priceData, addSubscription, removeSubscription } = useLivePrices();
5649

5750
useEffect(() => {
58-
addSubscription(price_account);
51+
addSubscription(feedKey);
5952
return () => {
60-
removeSubscription(price_account);
53+
removeSubscription(feedKey);
6154
};
62-
}, [addSubscription, removeSubscription, price_account]);
55+
}, [addSubscription, removeSubscription, feedKey]);
6356

64-
return priceData.get(price_account);
57+
return priceData.get(feedKey);
6558
};
6659

67-
export const LivePrice = ({ feed }: { feed: Feed }) => {
60+
export const LivePrice = ({ feedKey }: { feedKey: string }) => {
6861
const numberFormatter = useNumberFormatter({ maximumSignificantDigits: 5 });
69-
const price = useLivePrice(feed);
62+
const price = useLivePrice(feedKey);
7063

7164
return price === undefined ? (
7265
<Skeleton width={SKELETON_WIDTH} />
@@ -77,9 +70,9 @@ export const LivePrice = ({ feed }: { feed: Feed }) => {
7770
);
7871
};
7972

80-
export const LiveConfidence = ({ feed }: { feed: Feed }) => {
73+
export const LiveConfidence = ({ feedKey }: { feedKey: string }) => {
8174
const numberFormatter = useNumberFormatter({ maximumSignificantDigits: 5 });
82-
const price = useLivePrice(feed);
75+
const price = useLivePrice(feedKey);
8376

8477
return (
8578
<span className={styles.confidence}>
@@ -93,8 +86,8 @@ export const LiveConfidence = ({ feed }: { feed: Feed }) => {
9386
);
9487
};
9588

96-
export const LiveLastUpdated = ({ feed }: { feed: Feed }) => {
97-
const price = useLivePrice(feed);
89+
export const LiveLastUpdated = ({ feedKey }: { feedKey: string }) => {
90+
const price = useLivePrice(feedKey);
9891
const formatterWithDate = useDateFormatter({
9992
dateStyle: "short",
10093
timeStyle: "medium",
@@ -118,18 +111,18 @@ export const LiveLastUpdated = ({ feed }: { feed: Feed }) => {
118111

119112
type LiveValueProps<T extends keyof PriceData> = {
120113
field: T;
121-
feed: Feed & {
122-
price: Record<T, ReactNode>;
123-
};
114+
feedKey: string;
115+
defaultValue?: ReactNode | undefined;
124116
};
125117

126118
export const LiveValue = <T extends keyof PriceData>({
127-
feed,
119+
feedKey,
128120
field,
121+
defaultValue,
129122
}: LiveValueProps<T>) => {
130-
const price = useLivePrice(feed);
123+
const price = useLivePrice(feedKey);
131124

132-
return price?.[field]?.toString() ?? feed.price[field];
125+
return price?.[field]?.toString() ?? defaultValue;
133126
};
134127

135128
const isToday = (date: Date) => {

apps/insights/src/components/PriceFeed/layout.tsx

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
LiveLastUpdated,
2424
LiveValue,
2525
} from "../LivePrices";
26+
import { PriceFeedIcon } from "../PriceFeedIcon";
2627
import { PriceFeedTag } from "../PriceFeedTag";
2728
import { TabPanel, TabRoot, Tabs } from "../Tabs";
2829

@@ -61,33 +62,57 @@ export const PriceFeedLayout = async ({ children, params }: Props) => {
6162
feeds={data
6263
.filter((feed) => feed.symbol !== symbol)
6364
.map((feed) => ({
64-
id: encodeURIComponent(feed.symbol),
65+
id: feed.symbol,
6566
key: toHex(feed.product.price_account),
6667
displaySymbol: feed.product.display_symbol,
67-
name: <PriceFeedTag compact feed={feed} />,
68-
assetClassText: feed.product.asset_type,
69-
assetClass: (
70-
<Badge variant="neutral" style="outline" size="xs">
71-
{feed.product.asset_type.toUpperCase()}
72-
</Badge>
73-
),
68+
icon: <PriceFeedIcon symbol={feed.symbol} />,
69+
assetClass: feed.product.asset_type,
7470
}))}
7571
>
76-
<PriceFeedTag feed={feed} />
72+
<PriceFeedTag
73+
symbol={feed.product.display_symbol}
74+
description={feed.product.description}
75+
icon={<PriceFeedIcon symbol={feed.symbol} />}
76+
/>
7777
</PriceFeedSelect>
7878
<div className={styles.rightGroup}>
7979
<FeedKey
8080
variant="ghost"
8181
size="sm"
8282
className={styles.feedKey ?? ""}
83-
feed={feed}
83+
feedKey={feed.product.price_account}
8484
/>
8585
<DrawerTrigger>
8686
<Button variant="outline" size="sm" beforeIcon={ListDashes}>
8787
Reference Data
8888
</Button>
8989
<Drawer fill title="Reference Data">
90-
<ReferenceData feed={feed} />
90+
<ReferenceData
91+
feed={{
92+
symbol: feed.symbol,
93+
feedKey: feed.product.price_account,
94+
assetClass: feed.product.asset_type,
95+
base: feed.product.base,
96+
description: feed.product.description,
97+
country: feed.product.country,
98+
quoteCurrency: feed.product.quote_currency,
99+
tenor: feed.product.tenor,
100+
cmsSymbol: feed.product.cms_symbol,
101+
cqsSymbol: feed.product.cqs_symbol,
102+
nasdaqSymbol: feed.product.nasdaq_symbol,
103+
genericSymbol: feed.product.generic_symbol,
104+
weeklySchedule: feed.product.weekly_schedule,
105+
schedule: feed.product.schedule,
106+
contractId: feed.product.contract_id,
107+
displaySymbol: feed.product.display_symbol,
108+
exponent: feed.price.exponent,
109+
numComponentPrices: feed.price.numComponentPrices,
110+
numQuoters: feed.price.numQuoters,
111+
minPublishers: feed.price.minPublishers,
112+
lastSlot: feed.price.lastSlot,
113+
validSlot: feed.price.validSlot,
114+
}}
115+
/>
91116
</Drawer>
92117
</DrawerTrigger>
93118
</div>
@@ -96,11 +121,11 @@ export const PriceFeedLayout = async ({ children, params }: Props) => {
96121
<StatCard
97122
variant="primary"
98123
header="Aggregated Price"
99-
stat={<LivePrice feed={feed} />}
124+
stat={<LivePrice feedKey={feed.product.price_account} />}
100125
/>
101126
<StatCard
102127
header="Confidence"
103-
stat={<LiveConfidence feed={feed} />}
128+
stat={<LiveConfidence feedKey={feed.product.price_account} />}
104129
corner={
105130
<AlertTrigger>
106131
<Button
@@ -135,14 +160,16 @@ export const PriceFeedLayout = async ({ children, params }: Props) => {
135160
<StatCard
136161
header="1-Day Price Change"
137162
stat={
138-
<YesterdaysPricesProvider feeds={[feed]}>
139-
<ChangePercent feed={feed} />
163+
<YesterdaysPricesProvider
164+
feeds={{ [feed.symbol]: feed.product.price_account }}
165+
>
166+
<ChangePercent feedKey={feed.product.price_account} />
140167
</YesterdaysPricesProvider>
141168
}
142169
/>
143170
<StatCard
144171
header="Last Updated"
145-
stat={<LiveLastUpdated feed={feed} />}
172+
stat={<LiveLastUpdated feedKey={feed.product.price_account} />}
146173
/>
147174
</section>
148175
</section>
@@ -158,7 +185,11 @@ export const PriceFeedLayout = async ({ children, params }: Props) => {
158185
<div className={styles.priceComponentsTabLabel}>
159186
<span>Publishers</span>
160187
<Badge size="xs" style="filled" variant="neutral">
161-
<LiveValue feed={feed} field="numComponentPrices" />
188+
<LiveValue
189+
feedKey={feed.product.price_account}
190+
field="numComponentPrices"
191+
defaultValue={feed.price.numComponentPrices}
192+
/>
162193
</Badge>
163194
</div>
164195
),

0 commit comments

Comments
 (0)