Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 51 additions & 18 deletions src/pages/Crypto.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* ----------------------
* Easy:
* - [ ] Sort buttons (Market Cap, Price, 24h %)
* - [ ] Show coin symbol & small logo (image URL in API)
* - [ ] Format numbers with utility (abbreviate large caps: 1.2B)
* - [ ] Highlight positive vs negative 24h change (green/red)
* - [x] Show coin symbol & small logo (image URL in API)
* - [x] Format numbers with utility (abbreviate large caps: 1.2B)
* - [x] Highlight positive vs negative 24h change (green/red)
* Medium:
* - [ ] Add pagination (Top 50 -> allow next pages)
* - [x] Add pagination (Top 50 -> allow next pages)
* - [ ] Client-side caching with timestamp (avoid re-fetch spam)
* - [ ] Mini sparkline (use canvas or simple SVG)
* - [ ] Favorites (star) + localStorage persistence
Expand All @@ -18,10 +18,12 @@
* - [ ] Dark mode adaptive coloring for charts
* - [ ] Extract to service + custom hook (useCryptoMarkets)
*/

import { useEffect, useState } from "react";
import Loading from "../components/Loading.jsx";
import ErrorMessage from "../components/ErrorMessage.jsx";
import Card from "../components/Card.jsx";
import formatNumber from "../utilities/numberFormatter.js";

export default function Crypto() {
const [coins, setCoins] = useState([]);
Expand Down Expand Up @@ -57,30 +59,61 @@ export default function Crypto() {

return (
<div>
<h2>Cryptocurrency Tracker</h2>
<h2>💹 Cryptocurrency Tracker</h2>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search coin"
placeholder="Search coin..."
style={{ marginBottom: "1rem" }}
/>

{loading && <Loading />}
<ErrorMessage error={error} />

<div className="grid">
{filtered.map((c) => (
<Card
key={c.id}
title={c.name}
footer={<span>${c.current_price}</span>}
>
<p>Market Cap: ${c.market_cap.toLocaleString()}</p>
<p>24h: {c.price_change_percentage_24h?.toFixed(2)}%</p>
{/* TODO: Add mini sparkline chart */}
</Card>
))}
{filtered.map((c) => {
const isPositive = c.price_change_percentage_24h >= 0;
return (
<Card
key={c.id}
title={
<span style={{ display: "flex", alignItems: "center", gap: 8 }}>
<img
src={c.image}
alt={c.symbol}
style={{ width: 24, height: 24, borderRadius: "50%" }}
/>
{c.name} ({c.symbol.toUpperCase()})
</span>
}
footer={<strong>${c.current_price.toLocaleString()}</strong>}
>
<p>Market Cap: ${formatNumber(c.market_cap)}</p>
<p
style={{
color: isPositive ? "#16a34a" : "#dc2626",
fontWeight: 600,
}}
>
24h: {isPositive ? "+" : ""}
{c.price_change_percentage_24h?.toFixed(2)}%
</p>
{/* TODO: Add mini sparkline chart */}
</Card>
);
})}
</div>

<div className="pagination">
<div
className="pagination"
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
gap: "1rem",
marginTop: "1.5rem",
}}
>
<button onClick={() => setPage((p) => p - 1)} disabled={page === 1}>
Previous
</button>
Expand Down
9 changes: 9 additions & 0 deletions src/utilities/numberFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function formatNumber(number) {
return new Intl.NumberFormat("en", {
notation: "compact",

maximumFractionDigits: 1,
}).format(number);
}

// TODO: we can make here different type of currency