From 70628fb87aebe0409182d0fcc952e3011c6119c1 Mon Sep 17 00:00:00 2001 From: ManiBAJPAI22 Date: Fri, 22 Aug 2025 15:24:12 +0530 Subject: [PATCH 1/2] feat: add loading and error states to stats component --- web/src/hooks/useCoinPrice.tsx | 11 ++++++-- .../pages/Courts/CourtDetails/Stats/index.tsx | 25 ++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/web/src/hooks/useCoinPrice.tsx b/web/src/hooks/useCoinPrice.tsx index 1fc6aff61..9d4a5c3cd 100644 --- a/web/src/hooks/useCoinPrice.tsx +++ b/web/src/hooks/useCoinPrice.tsx @@ -13,7 +13,12 @@ export type Prices = { export const useCoinPrice = (coinIds: string[]) => { const isEnabled = coinIds !== undefined; - const { data: prices, isError } = useQuery({ + const { + data: prices, + isError, + isLoading, + error, + } = useQuery({ queryKey: [`coinPrice${coinIds}`], enabled: isEnabled, queryFn: async () => fetchCoinPrices(coinIds), @@ -21,5 +26,7 @@ export const useCoinPrice = (coinIds: string[]) => { return { prices, isError, + isLoading, + error, }; -}; +}; \ No newline at end of file diff --git a/web/src/pages/Courts/CourtDetails/Stats/index.tsx b/web/src/pages/Courts/CourtDetails/Stats/index.tsx index 0ae92d7f2..aea9057ce 100644 --- a/web/src/pages/Courts/CourtDetails/Stats/index.tsx +++ b/web/src/pages/Courts/CourtDetails/Stats/index.tsx @@ -14,6 +14,7 @@ import { useCourtDetails } from "queries/useCourtDetails"; import { landscapeStyle } from "styles/landscapeStyle"; import StatsContent from "./StatsContent"; +import Spinner from "components/Spinner"; const Container = styled.div` padding: 0 24px 12px 24px; @@ -50,13 +51,31 @@ const StyledAccordion = styled(Accordion)` )} `; +const ErrorMessage = styled.div` + display: flex; + align-items: center; + justify-content: center; + padding: 24px; + color: ${({ theme }) => theme.error}; + font-size: 16px; + font-weight: 500; +`; + const Stats = () => { const { id } = useParams(); - const { data } = useCourtDetails(id); + const { data, isLoading: isLoadingCourt, error: courtError } = useCourtDetails(id); const coinIds = [CoinIds.PNK, CoinIds.ETH]; - const { prices: pricesData } = useCoinPrice(coinIds); + const { prices: pricesData, isLoading: isLoadingPrices, error: pricesError } = useCoinPrice(coinIds); const isDesktop = useIsDesktop(); + if (isLoadingCourt || isLoadingPrices) { + return ; + } + + if (courtError || pricesError) { + return Failed to load statistics; + } + return isDesktop ? (
Statistics
@@ -75,4 +94,4 @@ const Stats = () => { ); }; -export default Stats; +export default Stats; \ No newline at end of file From 83a7e8b27c957fda4c880c6a653bfb9045ed5c9e Mon Sep 17 00:00:00 2001 From: ManiBAJPAI22 Date: Sat, 23 Aug 2025 13:48:42 +0530 Subject: [PATCH 2/2] feat(useCoinPrice): improve query stability and error handling --- web/src/hooks/useCoinPrice.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/web/src/hooks/useCoinPrice.tsx b/web/src/hooks/useCoinPrice.tsx index 9d4a5c3cd..8f95ce652 100644 --- a/web/src/hooks/useCoinPrice.tsx +++ b/web/src/hooks/useCoinPrice.tsx @@ -1,9 +1,12 @@ import { useQuery } from "@tanstack/react-query"; -const fetchCoinPrices = async (...coinIds) => { - const response = await fetch(`https://coins.llama.fi/prices/current/${coinIds.join(",")}?searchWidth=1h`); +const fetchCoinPrices = async (coinIds: readonly string[]): Promise => { + const ids = Array.from(new Set(coinIds)).filter(Boolean).sort().map(encodeURIComponent).join(","); + if (!ids) return {}; + const response = await fetch(`https://coins.llama.fi/prices/current/${ids}?searchWidth=1h`); + if (!response.ok) throw new Error(`Failed to fetch coin prices (${response.status})`); const data = await response.json(); - return data.coins; + return (data?.coins ?? {}) as Prices; }; export type Prices = { @@ -11,17 +14,15 @@ export type Prices = { }; export const useCoinPrice = (coinIds: string[]) => { - const isEnabled = coinIds !== undefined; - const { data: prices, isError, isLoading, error, } = useQuery({ - queryKey: [`coinPrice${coinIds}`], - enabled: isEnabled, - queryFn: async () => fetchCoinPrices(coinIds), + queryKey: ["coinPrice", coinIds], + enabled: Array.isArray(coinIds) && coinIds.length > 0, + queryFn: () => fetchCoinPrices(coinIds), }); return { prices, @@ -29,4 +30,4 @@ export const useCoinPrice = (coinIds: string[]) => { isLoading, error, }; -}; \ No newline at end of file +};