Skip to content

Commit 690d3e1

Browse files
Merge pull request #62 from yousefsaad12/feature/compact-number-format
feat(#39): format large numbers with compact display (1.2B, 900M, etc.)
2 parents b264b3c + 5e5b9ba commit 690d3e1

File tree

2 files changed

+60
-18
lines changed

2 files changed

+60
-18
lines changed

src/pages/Crypto.jsx

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
* ----------------------
44
* Easy:
55
* - [ ] Sort buttons (Market Cap, Price, 24h %)
6-
* - [ ] Show coin symbol & small logo (image URL in API)
7-
* - [ ] Format numbers with utility (abbreviate large caps: 1.2B)
8-
* - [ ] Highlight positive vs negative 24h change (green/red)
6+
* - [x] Show coin symbol & small logo (image URL in API)
7+
* - [x] Format numbers with utility (abbreviate large caps: 1.2B)
8+
* - [x] Highlight positive vs negative 24h change (green/red)
99
* Medium:
10-
* - [ ] Add pagination (Top 50 -> allow next pages)
10+
* - [x] Add pagination (Top 50 -> allow next pages)
1111
* - [ ] Client-side caching with timestamp (avoid re-fetch spam)
1212
* - [ ] Mini sparkline (use canvas or simple SVG)
1313
* - [ ] Favorites (star) + localStorage persistence
@@ -18,10 +18,12 @@
1818
* - [ ] Dark mode adaptive coloring for charts
1919
* - [ ] Extract to service + custom hook (useCryptoMarkets)
2020
*/
21+
2122
import { useEffect, useState } from "react";
2223
import Loading from "../components/Loading.jsx";
2324
import ErrorMessage from "../components/ErrorMessage.jsx";
2425
import Card from "../components/Card.jsx";
26+
import formatNumber from "../utilities/numberFormatter.js";
2527

2628
export default function Crypto() {
2729
const [coins, setCoins] = useState([]);
@@ -57,30 +59,61 @@ export default function Crypto() {
5759

5860
return (
5961
<div>
60-
<h2>Cryptocurrency Tracker</h2>
62+
<h2>💹 Cryptocurrency Tracker</h2>
6163
<input
6264
value={query}
6365
onChange={(e) => setQuery(e.target.value)}
64-
placeholder="Search coin"
66+
placeholder="Search coin..."
67+
style={{ marginBottom: "1rem" }}
6568
/>
6669

6770
{loading && <Loading />}
6871
<ErrorMessage error={error} />
72+
6973
<div className="grid">
70-
{filtered.map((c) => (
71-
<Card
72-
key={c.id}
73-
title={c.name}
74-
footer={<span>${c.current_price}</span>}
75-
>
76-
<p>Market Cap: ${c.market_cap.toLocaleString()}</p>
77-
<p>24h: {c.price_change_percentage_24h?.toFixed(2)}%</p>
78-
{/* TODO: Add mini sparkline chart */}
79-
</Card>
80-
))}
74+
{filtered.map((c) => {
75+
const isPositive = c.price_change_percentage_24h >= 0;
76+
return (
77+
<Card
78+
key={c.id}
79+
title={
80+
<span style={{ display: "flex", alignItems: "center", gap: 8 }}>
81+
<img
82+
src={c.image}
83+
alt={c.symbol}
84+
style={{ width: 24, height: 24, borderRadius: "50%" }}
85+
/>
86+
{c.name} ({c.symbol.toUpperCase()})
87+
</span>
88+
}
89+
footer={<strong>${c.current_price.toLocaleString()}</strong>}
90+
>
91+
<p>Market Cap: ${formatNumber(c.market_cap)}</p>
92+
<p
93+
style={{
94+
color: isPositive ? "#16a34a" : "#dc2626",
95+
fontWeight: 600,
96+
}}
97+
>
98+
24h: {isPositive ? "+" : ""}
99+
{c.price_change_percentage_24h?.toFixed(2)}%
100+
</p>
101+
{/* TODO: Add mini sparkline chart */}
102+
</Card>
103+
);
104+
})}
81105
</div>
82106

83-
<div className="pagination">
107+
<div
108+
className="pagination"
109+
style={{
110+
display: "flex",
111+
justifyContent: "center",
112+
alignItems: "center",
113+
gap: "1rem",
114+
marginTop: "1.5rem",
115+
}}
116+
>
84117
<button onClick={() => setPage((p) => p - 1)} disabled={page === 1}>
85118
Previous
86119
</button>

src/utilities/numberFormatter.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default function formatNumber(number) {
2+
return new Intl.NumberFormat("en", {
3+
notation: "compact",
4+
5+
maximumFractionDigits: 1,
6+
}).format(number);
7+
}
8+
9+
// TODO: we can make here different type of currency

0 commit comments

Comments
 (0)