-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpage.tsx
More file actions
114 lines (104 loc) · 4.02 KB
/
page.tsx
File metadata and controls
114 lines (104 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import Link from 'next/link';
import { ArrowUpRight } from 'lucide-react';
import { getCoinDetails, getCoinOHLC, fetchPools, fetchTopPool } from '@/lib/coingecko.actions';
import { Converter } from '@/components/coin-details/Converter';
import { TopGainersLosers } from '@/components/coin-details/TopGainersLosers';
import LiveDataWrapper from '@/components/LiveDataWrapper';
import { DataTable } from '@/components/DataTable';
import { formatPrice, timeAgo } from '@/lib/utils';
export default async function CoinDetailsPage({ params }: CoinDetailsPageProps) {
const { id } = await params;
const [coinData, coinOHLCData] = await Promise.all([getCoinDetails(id), getCoinOHLC(id, 1, 'usd', 'hourly', 'full')]);
const platformId = coinData.asset_platform_id;
const platform = platformId ? coinData.detail_platforms?.[platformId] : null;
const network = platform?.geckoterminal_url?.split('/')[3] ?? null;
const contractAddress = platform?.contract_address ?? null;
const pool = network && contractAddress ? await fetchTopPool(network, contractAddress) : await fetchPools(id);
const marketStats = [
{ label: 'Market Cap', value: formatPrice(coinData.market_data.market_cap.usd) },
{ label: 'Rank', value: `#${coinData.market_cap_rank}` },
{ label: 'Volume', value: formatPrice(coinData.market_data.total_volume.usd) },
{ label: 'Website', link: coinData.links.homepage[0], linkText: 'Official Site' },
{ label: 'Explorer', link: coinData.links.blockchain_site[0], linkText: 'Blockchain' },
{ label: 'Community', link: coinData.links.subreddit_url, linkText: 'Reddit' },
];
const exchangeColumns: DataTableColumn<Ticker>[] = [
{
header: 'Exchange',
cellClassName: 'exchange-name',
cell: (ticker) => (
<>
{ticker.market.name}
<Link href={ticker.trade_url} target='_blank' />
</>
),
},
{
header: 'Pair',
cell: (ticker) => (
<div
className='pair font-medium text-purple-100 truncate max-w-[120px]'
title={`${ticker.base}/${ticker.target}`}
>
{ticker.base}/{ticker.target}
</div>
),
},
{
header: 'Price',
cellClassName: 'price-cell font-bold',
cell: (ticker) => formatPrice(ticker.converted_last.usd),
},
{
header: 'Last Traded',
cellClassName: 'time-cell text-end text-purple-100 text-sm',
cell: (ticker) => timeAgo(ticker.timestamp),
},
];
return (
<main id='coin-details-page'>
<section className='primary'>
<LiveDataWrapper coinId={id} poolId={pool?.id || ''} coin={coinData} coinOHLCData={coinOHLCData}>
<div className='exchange-section'>
<h4>Exchange Listings</h4>
<DataTable
tableClassName='exchange-table'
columns={exchangeColumns}
data={coinData.tickers.slice(0, 7)}
rowKey={(ticker: Ticker, index: number) => `${ticker.market.name}-${ticker.target}-${index}`}
bodyCellClassName='py-3!'
/>
</div>
</LiveDataWrapper>
</section>
<section className='secondary'>
<Converter
symbol={coinData.symbol}
icon={coinData.image.small}
priceList={coinData.market_data.current_price}
/>
<div className='details'>
<h4>Asset Information</h4>
<ul className='details-grid'>
{marketStats.map((stat, index) => (
<li key={index}>
<p className='label'>{stat.label}</p>
{stat.link ? (
<div className='link'>
<Link href={stat.link} target='_blank'>
{stat.linkText}
</Link>
<ArrowUpRight size={14} className='opacity-70' />
</div>
) : (
<p className='value font-bold'>{stat.value}</p>
)}
</li>
))}
</ul>
</div>
<TopGainersLosers />
</section>
</main>
);
}