Skip to content

Commit eefebc5

Browse files
committed
refactor: pages and components
1 parent 10cc61d commit eefebc5

15 files changed

Lines changed: 282 additions & 328 deletions

.vscode/settings.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"editor.defaultFormatter": "esbenp.prettier-vscode",
3+
"editor.formatOnSave": true,
4+
"editor.codeActionsOnSave": {
5+
"source.fixAll.eslint": "explicit",
6+
"source.addMissingImports": "explicit"
7+
},
8+
"prettier.tabWidth": 2,
9+
"prettier.useTabs": false,
10+
"prettier.semi": true,
11+
"prettier.singleQuote": true,
12+
"prettier.jsxSingleQuote": true,
13+
"prettier.trailingComma": "es5",
14+
"prettier.arrowParens": "always",
15+
"[typescriptreact]": {
16+
"editor.defaultFormatter": "esbenp.prettier-vscode"
17+
}
18+
}

app/coins/[id]/page.tsx

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,64 @@ import {
44
fetchPools,
55
fetchTopPool,
66
} from '@/lib/coingecko.actions';
7-
import { Converter } from '@/components/Converter';
7+
import { Converter } from '@/components/coin-details/Converter';
88
import LiveDataWrapper from '@/components/LiveDataWrapper';
9-
import { ExchangeListings } from '@/components/ExchangeListings';
10-
import { CoinDetailsSection } from '@/components/CoinDetailsSection';
11-
import { TopGainersLosers } from '@/components/TopGainersLosers';
9+
import { TopGainersLosers } from '@/components/coin-details/TopGainersLosers';
10+
import {
11+
Table,
12+
TableBody,
13+
TableCell,
14+
TableHead,
15+
TableHeader,
16+
TableRow,
17+
} from '@/components/ui/table';
18+
import { formatPrice, timeAgo } from '@/lib/utils';
19+
import Link from 'next/link';
20+
import { ArrowUpRight } from 'lucide-react';
1221

1322
const CoinDetails = async ({ params }: { params: Promise<{ id: string }> }) => {
1423
const { id } = await params;
1524
const coinData = await getCoinDetails(id);
25+
1626
const pool = coinData.asset_platform_id
1727
? await fetchTopPool(coinData.asset_platform_id, coinData.contract_address)
1828
: await fetchPools(id);
29+
1930
const coinOHLCData = await getCoinOHLC(id, 1, 'usd', 'hourly', 'full');
2031

32+
const coinDetails = [
33+
{
34+
label: 'Market Cap',
35+
value: formatPrice(coinData.market_data.market_cap.usd),
36+
},
37+
{
38+
label: 'Market Cap Rank',
39+
value: `# ${coinData.market_cap_rank}`,
40+
},
41+
{
42+
label: 'Total Volume',
43+
value: formatPrice(coinData.market_data.total_volume.usd),
44+
},
45+
{
46+
label: 'Website',
47+
value: '-',
48+
link: coinData.links.homepage[0],
49+
linkText: 'Website',
50+
},
51+
{
52+
label: 'Explorer',
53+
value: '-',
54+
link: coinData.links.blockchain_site[0],
55+
linkText: 'Explorer',
56+
},
57+
{
58+
label: 'Community Link',
59+
value: '-',
60+
link: coinData.links.subreddit_url,
61+
linkText: 'Community',
62+
},
63+
];
64+
2165
return (
2266
<main className='coin-details-main'>
2367
<section className='size-full xl:col-span-2'>
@@ -27,8 +71,62 @@ const CoinDetails = async ({ params }: { params: Promise<{ id: string }> }) => {
2771
coin={coinData}
2872
coinOHLCData={coinOHLCData}
2973
>
30-
{/* Exchange Listings - pass it as a child of a client component so it will be render server side */}
31-
<ExchangeListings coinData={coinData} />
74+
<div className='w-full mt-8 space-y-4'>
75+
<h4 className='section-title'>Exchange Listings</h4>
76+
<div className='custom-scrollbar mt-5 exchange-container'>
77+
<Table>
78+
<TableHeader className='text-purple-100'>
79+
<TableRow className='hover:bg-transparent'>
80+
<TableHead className='exchange-header-left'>
81+
Exchange
82+
</TableHead>
83+
<TableHead className='text-purple-100'>Pair</TableHead>
84+
<TableHead className='text-purple-100'>Price</TableHead>
85+
<TableHead className='exchange-header-right'>
86+
Last Traded
87+
</TableHead>
88+
</TableRow>
89+
</TableHeader>
90+
<TableBody>
91+
{coinData.tickers
92+
.slice(0, 7)
93+
.map((ticker: Ticker, index: number) => (
94+
<TableRow
95+
key={index}
96+
className='overflow-hidden rounded-lg hover:bg-dark-400/30!'
97+
>
98+
<TableCell className=' text-green-500 font-bold'>
99+
<Link
100+
href={ticker.trade_url}
101+
target='_blank'
102+
className='exchange-link'
103+
>
104+
{ticker.market.name}
105+
</Link>
106+
</TableCell>
107+
<TableCell>
108+
<div className='exchange-pair'>
109+
<p className='truncate max-w-[100px] h-full'>
110+
{ticker.base}
111+
</p>
112+
/
113+
<p className='truncate max-w-[100px] h-full ml-2'>
114+
{ticker.target}
115+
</p>
116+
</div>
117+
</TableCell>
118+
<TableCell className='font-medium'>
119+
{formatPrice(ticker.converted_last.usd)}
120+
</TableCell>
121+
<TableCell className='exchange-timestamp'>
122+
{timeAgo(ticker.timestamp)}
123+
</TableCell>
124+
</TableRow>
125+
))}
126+
</TableBody>
127+
</Table>
128+
</div>
129+
</div>
32130
</LiveDataWrapper>
33131
</section>
34132

@@ -41,7 +139,26 @@ const CoinDetails = async ({ params }: { params: Promise<{ id: string }> }) => {
41139
/>
42140

43141
{/* Coin Details */}
44-
<CoinDetailsSection coinData={coinData} />
142+
<div className='w-full mt-8 space-y-4'>
143+
<h4 className='section-title pb-3'>Coin Details</h4>
144+
<div className='coin-details-grid'>
145+
{coinDetails.map(({ label, value, link, linkText }, index) => (
146+
<div key={index} className='detail-card'>
147+
<p className='text-purple-100'>{label}</p>
148+
{link ? (
149+
<div className='detail-link'>
150+
<Link href={link} target='_blank'>
151+
{linkText || label}
152+
</Link>
153+
<ArrowUpRight size={16} />
154+
</div>
155+
) : (
156+
<p className='text-base font-medium'>{value}</p>
157+
)}
158+
</div>
159+
))}
160+
</div>
161+
</div>
45162

46163
{/* Top Gainers / Losers */}
47164
<TopGainersLosers />

app/coins/page.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import {
88
TableRow,
99
} from '@/components/ui/table';
1010
import Image from 'next/image';
11-
import { cn, formatPercentage, formatPrice } from '@/lib/utils';
11+
import Link from 'next/link';
12+
1213
import CoinsPagination from '@/components/CoinsPagination';
13-
import { ClickableTableRow } from '@/components/ClickableTableRow';
14+
import { cn, formatPercentage, formatPrice } from '@/lib/utils';
1415

1516
const Coins = async ({
1617
searchParams,
@@ -50,14 +51,16 @@ const Coins = async ({
5051
<TableBody>
5152
{coinsData.map((coin: CoinMarketData) => {
5253
const isTrendingUp = coin.price_change_percentage_24h > 0;
54+
5355
return (
54-
<ClickableTableRow
55-
key={coin.id}
56-
href={`/coins/${coin.id}`}
57-
className='coins-row'
58-
>
56+
<TableRow key={coin.id} className='coins-row relative'>
5957
<TableCell className='coins-rank'>
6058
#{coin.market_cap_rank}
59+
<Link
60+
href={`/coins/${coin.id}`}
61+
className='absolute inset-0 z-10'
62+
aria-label='View coin'
63+
/>
6164
</TableCell>
6265
<TableCell className='coins-token'>
6366
<div className='coins-token-info'>
@@ -67,7 +70,7 @@ const Coins = async ({
6770
width={36}
6871
height={36}
6972
/>
70-
<p className='max-w-[100%] truncate'>
73+
<p className='max-w-full truncate'>
7174
{coin.name} ({coin.symbol.toUpperCase()})
7275
</p>
7376
</div>
@@ -89,7 +92,7 @@ const Coins = async ({
8992
<TableCell className='coins-market-cap'>
9093
{formatPrice(coin.market_cap)}
9194
</TableCell>
92-
</ClickableTableRow>
95+
</TableRow>
9396
);
9497
})}
9598
</TableBody>

app/page.tsx

Lines changed: 14 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,38 @@
11
import { Suspense } from 'react';
22

33
import {
4-
Table,
5-
TableBody,
6-
TableCell,
7-
TableHead,
8-
TableHeader,
9-
TableRow,
10-
} from '@/components/ui/table';
11-
12-
import { Skeleton } from '@/components/ui/skeleton';
13-
import { CoinOverviewSection } from '@/components/CoinOverviewSection';
14-
import { CategoriesSection } from '@/components/CategoriesSection';
15-
import { TrendingCoinsSection } from '@/components/TrendingCoinsSection';
4+
Categories,
5+
CategoriesFallback,
6+
} from '@/components/home/Categories';
7+
import {
8+
CoinOverview,
9+
CoinOverviewFallback,
10+
} from '@/components/home/CoinOverview';
11+
import {
12+
TrendingCoins,
13+
TrendingCoinsFallback,
14+
} from '@/components/home/TrendingCoins';
1615

1716
const Home = () => {
1817
return (
1918
<main className='main-container'>
2019
<section className='home-grid'>
2120
<Suspense fallback={<CoinOverviewFallback />}>
22-
<CoinOverviewSection />
21+
<CoinOverview />
2322
</Suspense>
2423

2524
<Suspense fallback={<TrendingCoinsFallback />}>
26-
<TrendingCoinsSection />
25+
<TrendingCoins />
2726
</Suspense>
2827
</section>
2928

3029
<section className='w-full mt-7 space-y-4'>
3130
<Suspense fallback={<CategoriesFallback />}>
32-
<CategoriesSection />
31+
<Categories />
3332
</Suspense>
3433
</section>
3534
</main>
3635
);
3736
};
3837

3938
export default Home;
40-
41-
const CoinOverviewFallback = () => (
42-
<div className='chart-section-container'>
43-
<div className='w-full h-full min-h-[420px] rounded-2xl bg-dark-500/60 p-6'>
44-
<div className='flex items-center gap-4 mb-6'>
45-
<Skeleton className='h-14 w-14 rounded-full skeleton' />
46-
<div className='flex flex-col gap-2 flex-1'>
47-
<Skeleton className='h-4 w-1/3 skeleton' />
48-
<Skeleton className='h-8 w-1/2 skeleton' />
49-
</div>
50-
</div>
51-
<Skeleton className='h-[280px] w-full rounded-xl skeleton' />
52-
</div>
53-
</div>
54-
);
55-
56-
const TrendingCoinsFallback = () => (
57-
<div className='top-movers-container'>
58-
<h4 className='section-title px-5'>Trending Coins</h4>
59-
<div className='table-scrollbar-container custom-scrollbar'>
60-
<Table>
61-
<TableHeader className='table-header-cell'>
62-
<TableRow className='hover:bg-transparent'>
63-
<TableHead className='table-head-left'>Name</TableHead>
64-
<TableHead className='table-header-cell table-cell'>
65-
24h Change
66-
</TableHead>
67-
<TableHead className='table-head-right'>Price</TableHead>
68-
</TableRow>
69-
</TableHeader>
70-
<TableBody>
71-
{Array.from({ length: 6 }).map((_, index) => (
72-
<TableRow key={index} className='table-row-hover'>
73-
<TableCell className='font-bold'>
74-
<div className='flex items-center gap-3'>
75-
<Skeleton className='h-9 w-9 rounded-full skeleton' />
76-
<Skeleton className='h-4 w-24 skeleton' />
77-
</div>
78-
</TableCell>
79-
<TableCell className='table-cell-change'>
80-
<Skeleton className='h-4 w-16 skeleton' />
81-
</TableCell>
82-
<TableCell className='table-cell-price'>
83-
<Skeleton className='h-4 w-20 skeleton' />
84-
</TableCell>
85-
</TableRow>
86-
))}
87-
</TableBody>
88-
</Table>
89-
</div>
90-
</div>
91-
);
92-
93-
const CategoriesFallback = () => (
94-
<div className='custom-scrollbar categories-container'>
95-
<h4 className='section-title pl-5'>Top Categories</h4>
96-
<Table>
97-
<TableHeader className='text-purple-100'>
98-
<TableRow className='hover:bg-transparent'>
99-
<TableHead className='exchange-header-left'>Category</TableHead>
100-
<TableHead className='text-purple-100'>Top Gainers</TableHead>
101-
<TableHead className='text-purple-100 pl-7'>24h Change</TableHead>
102-
<TableHead className='text-purple-100'>Market Cap</TableHead>
103-
<TableHead className='text-purple-100'>24h Volume</TableHead>
104-
</TableRow>
105-
</TableHeader>
106-
<TableBody>
107-
{Array.from({ length: 6 }).map((_, index) => (
108-
<TableRow
109-
key={index}
110-
className='md:text-base rounded-lg hover:!bg-dark-400/30'
111-
>
112-
<TableCell className='pl-5 font-bold'>
113-
<Skeleton className='h-4 w-32 skeleton' />
114-
</TableCell>
115-
<TableCell className='flex gap-1 mr-5'>
116-
{Array.from({ length: 3 }).map((__, coinIndex) => (
117-
<Skeleton
118-
key={coinIndex}
119-
className='h-7 w-7 rounded-full skeleton'
120-
/>
121-
))}
122-
</TableCell>
123-
<TableCell className='font-medium'>
124-
<Skeleton className='h-4 w-16 skeleton' />
125-
</TableCell>
126-
<TableCell className='font-medium'>
127-
<Skeleton className='h-4 w-20 skeleton' />
128-
</TableCell>
129-
<TableCell className='font-medium'>
130-
<Skeleton className='h-4 w-24 skeleton' />
131-
</TableCell>
132-
</TableRow>
133-
))}
134-
</TableBody>
135-
</Table>
136-
</div>
137-
);

0 commit comments

Comments
 (0)