Skip to content

Commit 10cc61d

Browse files
committed
fix
1 parent b7eb308 commit 10cc61d

File tree

5 files changed

+111
-135
lines changed

5 files changed

+111
-135
lines changed

app/coins/[id]/page.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
getCoinDetails,
33
getCoinOHLC,
44
fetchPools,
5+
fetchTopPool,
56
} from '@/lib/coingecko.actions';
67
import { Converter } from '@/components/Converter';
78
import LiveDataWrapper from '@/components/LiveDataWrapper';
@@ -12,19 +13,21 @@ import { TopGainersLosers } from '@/components/TopGainersLosers';
1213
const CoinDetails = async ({ params }: { params: Promise<{ id: string }> }) => {
1314
const { id } = await params;
1415
const coinData = await getCoinDetails(id);
15-
const pool = await fetchPools(id);
16+
const pool = coinData.asset_platform_id
17+
? await fetchTopPool(coinData.asset_platform_id, coinData.contract_address)
18+
: await fetchPools(id);
1619
const coinOHLCData = await getCoinOHLC(id, 1, 'usd', 'hourly', 'full');
1720

1821
return (
1922
<main className='coin-details-main'>
2023
<section className='size-full xl:col-span-2'>
2124
<LiveDataWrapper
2225
coinId={id}
23-
pool={pool}
26+
poolId={pool.id}
2427
coin={coinData}
2528
coinOHLCData={coinOHLCData}
2629
>
27-
{/* Exchange Listings - pass it as a child of a client componentso it will be render server side */}
30+
{/* Exchange Listings - pass it as a child of a client component so it will be render server side */}
2831
<ExchangeListings coinData={coinData} />
2932
</LiveDataWrapper>
3033
</section>

components/CoinHeader.tsx

Lines changed: 67 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -17,108 +17,80 @@ export default function CoinHeader({
1717

1818
return (
1919
<div className='coin-header-container'>
20-
{name ? (
21-
<div className='coin-header-container'>
22-
<h3 className='text-3xl font-medium'>{name}</h3>
23-
<div className='coin-header-info'>
24-
<Image
25-
src={image}
26-
alt={name}
27-
width={77}
28-
height={77}
29-
className='coin-header-image'
30-
/>
31-
<div className='flex gap-4'>
32-
<h1 className='coin-header-price'>{formatPrice(livePrice)}</h1>
33-
<Badge
34-
className={cn(
35-
'coin-header-badge',
36-
isTrendingUp
37-
? 'bg-green-600/20 text-green-600'
38-
: 'bg-red-500/20 text-red-500'
39-
)}
40-
>
41-
{formatPercentage(livePriceChangePercentage24h)}
42-
{isTrendingUp ? <TrendingUp /> : <TrendingDown />}
43-
(24h)
44-
</Badge>
45-
</div>
20+
<div className='coin-header-container'>
21+
<h3 className='text-3xl font-medium'>{name}</h3>
22+
<div className='coin-header-info'>
23+
<Image
24+
src={image}
25+
alt={name}
26+
width={77}
27+
height={77}
28+
className='coin-header-image'
29+
/>
30+
<div className='flex gap-4'>
31+
<h1 className='coin-header-price'>{formatPrice(livePrice)}</h1>
32+
<Badge
33+
className={cn(
34+
'coin-header-badge',
35+
isTrendingUp
36+
? 'bg-green-600/20 text-green-600'
37+
: 'bg-red-500/20 text-red-500'
38+
)}
39+
>
40+
{formatPercentage(livePriceChangePercentage24h)}
41+
{isTrendingUp ? <TrendingUp /> : <TrendingDown />}
42+
(24h)
43+
</Badge>
4644
</div>
47-
<div className='coin-header-stats'>
48-
<div className='coin-header-stat'>
49-
<p className='coin-header-stat-label'>Today</p>
50-
<div
51-
className={cn('coin-header-stat-value', {
52-
'text-green-500': livePriceChangePercentage24h > 0,
53-
'text-red-500': livePriceChangePercentage24h < 0,
54-
})}
55-
>
56-
<p>{formatPercentage(livePriceChangePercentage24h)}</p>
57-
{isTrendingUp ? (
58-
<TrendingUp width={16} height={16} />
59-
) : (
60-
<TrendingDown width={16} height={16} />
61-
)}
62-
</div>
45+
</div>
46+
<div className='coin-header-stats'>
47+
<div className='coin-header-stat'>
48+
<p className='coin-header-stat-label'>Today</p>
49+
<div
50+
className={cn('coin-header-stat-value', {
51+
'text-green-500': livePriceChangePercentage24h > 0,
52+
'text-red-500': livePriceChangePercentage24h < 0,
53+
})}
54+
>
55+
<p>{formatPercentage(livePriceChangePercentage24h)}</p>
56+
{isTrendingUp ? (
57+
<TrendingUp width={16} height={16} />
58+
) : (
59+
<TrendingDown width={16} height={16} />
60+
)}
6361
</div>
62+
</div>
6463

65-
<div className='coin-header-stat'>
66-
<p className='coin-header-stat-label'>30 Days</p>
67-
<div
68-
className={cn('coin-header-stat-value-30d', {
69-
'text-green-500': priceChangePercentage30d > 0,
70-
'text-red-500': priceChangePercentage30d < 0,
71-
})}
72-
>
73-
<p>{formatPercentage(priceChangePercentage30d)}</p>
74-
{isTrendingUp ? (
75-
<TrendingUp width={16} height={16} />
76-
) : (
77-
<TrendingDown width={16} height={16} />
78-
)}
79-
</div>
64+
<div className='coin-header-stat'>
65+
<p className='coin-header-stat-label'>30 Days</p>
66+
<div
67+
className={cn('coin-header-stat-value-30d', {
68+
'text-green-500': priceChangePercentage30d > 0,
69+
'text-red-500': priceChangePercentage30d < 0,
70+
})}
71+
>
72+
<p>{formatPercentage(priceChangePercentage30d)}</p>
73+
{isTrendingUp ? (
74+
<TrendingUp width={16} height={16} />
75+
) : (
76+
<TrendingDown width={16} height={16} />
77+
)}
8078
</div>
79+
</div>
8180

82-
<div className='text-base flex flex-col gap-2'>
83-
<p className='coin-header-stat-label'>Price Change (24h)</p>
84-
<p
85-
className={cn('coin-header-stat-price', {
86-
'text-green-500': priceChange24h > 0,
87-
'text-red-500': priceChange24h < 0,
88-
})}
89-
>
90-
{formatPrice(priceChange24h)}
91-
</p>
92-
</div>
81+
<div className='text-base flex flex-col gap-2'>
82+
<p className='coin-header-stat-label'>Price Change (24h)</p>
83+
<p
84+
className={cn('coin-header-stat-price', {
85+
'text-green-500': priceChange24h > 0,
86+
'text-red-500': priceChange24h < 0,
87+
})}
88+
>
89+
{formatPrice(priceChange24h)}
90+
</p>
9391
</div>
9492
</div>
95-
) : (
96-
<>
97-
<div className='coin-header-info'>
98-
<div className='coin-header-skeleton-image' />
99-
<div className='flex gap-4'>
100-
<div className='coin-header-skeleton-price' />
101-
<div className='coin-header-skeleton-badge' />
102-
</div>
103-
</div>
104-
<div className='coin-header-stats'>
105-
{[1, 2, 3].map((i) => (
106-
<div
107-
key={i}
108-
className={cn(
109-
'text-base flex flex-col gap-2',
110-
i < 3 && 'border-r border-purple-600'
111-
)}
112-
>
113-
<p className='coin-header-stat-label'>
114-
{i === 1 ? 'Today' : i === 2 ? 'Market Cap' : 'Volume 24h'}
115-
</p>
116-
<div className='coin-header-skeleton-stat' />
117-
</div>
118-
))}
119-
</div>
120-
</>
121-
)}
93+
</div>
12294
</div>
12395
);
12496
}

components/LiveDataWrapper.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,18 @@ import { useCoinGeckoWebSocket } from '@/hooks/useCoinGeckoWebSocket';
1616

1717
export default function LiveDataWrapper({
1818
coinId,
19-
pool,
19+
poolId,
2020
coin,
2121
coinOHLCData,
2222
children,
2323
}: LiveDataProps) {
2424
const { price, trades, ohlcv } = useCoinGeckoWebSocket({
2525
coinId,
26-
poolId: pool.id,
26+
poolId,
2727
});
2828

29+
console.log('=========poolId', poolId);
30+
2931
return (
3032
<section className='size-full xl:col-span-2'>
3133
<CoinHeader

lib/coingecko.actions.ts

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ const header = {
1111

1212
// Get detailed information about a specific coin by its ID
1313
export async function getCoinDetails(id: string) {
14-
const res = await fetch(`${baseUrl}/coins/${id}`, header);
14+
const res = await fetch(
15+
`${baseUrl}/coins/${id}?dex_pair_format=contract_address`,
16+
header
17+
);
1518

1619
if (!res.ok) throw new Error('Failed to fetch CoinGecko API data');
1720
return res.json();
@@ -52,17 +55,15 @@ export async function getTrendingCoins() {
5255

5356
// Get coin categories
5457
export async function getCategories() {
55-
const res = await fetch(
56-
`${baseUrl}/coins/categories`,
57-
header
58-
);
58+
const res = await fetch(`${baseUrl}/coins/categories`, header);
5959

6060
if (!res.ok) throw new Error('Failed to fetch categories');
6161

6262
const data = await res.json();
6363
return data.slice(0, 10) || [];
6464
}
6565

66+
// Get a list of coins with market data
6667
export async function getCoinList(page: number = 1, perPage: number = 50) {
6768
const params = new URLSearchParams({
6869
vs_currency: 'usd',
@@ -80,6 +81,7 @@ export async function getCoinList(page: number = 1, perPage: number = 50) {
8081
return res.json();
8182
}
8283

84+
// Get top gainers and losers
8385
export async function getTopGainersLosers() {
8486
const res = await fetch(
8587
`${baseUrl}/coins/top_gainers_losers?vs_currency=usd`,
@@ -95,7 +97,8 @@ export async function getTopGainersLosers() {
9597
};
9698
}
9799

98-
export async function searchCoins(query: string): Promise<SearchCoin[]> {
100+
// Search for coins by query
101+
export async function searchCoins(query: string) {
99102
if (!query || query.trim().length === 0) return [];
100103

101104
const res = await fetch(
@@ -154,32 +157,33 @@ export async function searchCoins(query: string): Promise<SearchCoin[]> {
154157
return coins.slice(0, 10);
155158
}
156159

157-
export async function fetchPools(
158-
id: string
159-
): Promise<{ id: string; address: string; name: string; network: string }> {
160-
try {
161-
// Fetch onchain data for the coin which includes pool information
162-
const res = await fetch(
163-
`${baseUrl}/onchain/search/pools?query=${encodeURIComponent(id)}`,
164-
header
165-
);
160+
// Fetch the top pool for a given network and contract address
161+
export async function fetchTopPool(network: string, contractAddress: string) {
162+
const res = await fetch(
163+
`${baseUrl}/onchain/networks/${network}/tokens/${contractAddress}/pools`,
164+
header
165+
);
166166

167-
if (!res.ok) {
168-
console.warn(`No pool data found for ${id}`);
169-
return { id: '', address: '', name: '', network: '' };
170-
}
167+
if (!res.ok) throw new Error('Failed to fetch top pool data');
171168

172-
const data = await res.json();
173-
const pool = data.data[1];
169+
const data = await res.json();
170+
return data.data[0];
171+
}
174172

175-
return {
176-
id: pool.id as string,
177-
address: pool.attributes.address as string,
178-
name: pool.attributes.name as string,
179-
network: pool.id.split('_')[0] as string,
180-
};
181-
} catch (error) {
182-
console.error('Failed to fetch pools', error);
173+
// Fetch pools by coin ID for coins that has no specific network
174+
export async function fetchPools(id: string) {
175+
const res = await fetch(
176+
`${baseUrl}/onchain/search/pools?query=${encodeURIComponent(id)}`,
177+
header
178+
);
179+
180+
if (!res.ok) {
181+
console.warn(`No pool data found for ${id}`);
183182
return { id: '', address: '', name: '', network: '' };
184183
}
184+
185+
const data = await res.json();
186+
return data.data[0];
185187
}
188+
189+

types.d.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,7 @@ interface CoinDetailsData {
218218

219219
interface LiveDataProps {
220220
coinId: string;
221-
pool: {
222-
id: string;
223-
address: string;
224-
name: string;
225-
network: string;
226-
};
221+
poolId: string;
227222
coin: CoinDetailsData;
228223
coinOHLCData?: OHLCData[];
229224
children?: React.ReactNode;

0 commit comments

Comments
 (0)