Skip to content

Commit a1b0ded

Browse files
committed
feat: improve percentage formatting for hypercert display
- add utility functions to format percentages - format percentages to the first non zero digit on hypercert-window
1 parent 6561393 commit a1b0ded

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

components/hypercert/hypercert-window.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { SUPPORTED_CHAINS, SupportedChainIdType } from "@/configs/constants";
33
import { HypercertListFragment } from "@/hypercerts/fragments/hypercert-list.fragment";
44
import { getEvaluationStatus } from "@/hypercerts/getEvaluationStatus";
55
import { calculateBigIntPercentage } from "@/lib/calculateBigIntPercentage";
6+
import { formatPercentageToFirstNonZeroDigit } from "@/lib/formatPercentage";
67
import { getCurrencyByAddress } from "@/marketplace/utils";
78
import Image from "next/image";
89
import Link from "next/link";
@@ -95,7 +96,12 @@ const HypercertWindow = memo(
9596
<section className="flex text-xs justify-between">
9697
<section>
9798
<h6 className="opacity-70">for sale</h6>
98-
<p> {percentAvailable ? `${percentAvailable}%` : "--"}</p>
99+
<p>
100+
{" "}
101+
{percentAvailable
102+
? `${formatPercentageToFirstNonZeroDigit(percentAvailable)}%`
103+
: "--"}
104+
</p>
99105
</section>
100106
<section>
101107
<h6 className="text-end opacity-70">lowest per %</h6>

lib/formatPercentage.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
export const formatPercentageToFirstNonZeroDigit = (
2+
percentage: number,
3+
): string => {
4+
if (percentage === 0) return "0";
5+
6+
if (percentage < 1) {
7+
const NumberFormat = new Intl.NumberFormat("en-US", {
8+
style: "decimal",
9+
notation: "standard",
10+
maximumSignificantDigits: 21,
11+
});
12+
13+
const result = NumberFormat.format(percentage);
14+
15+
// Match the first 2 non-zero digits after the decimal point
16+
const match = result.match(/\d*\.\d*?[1-9](?:\d*[1-9]|\d)?/);
17+
18+
// If no decimal or no non-zero digits after decimal, return rounded integer
19+
if (!match) {
20+
return Math.round(percentage).toString();
21+
}
22+
23+
// Check if we found 1 or 2 non-zero digits after the decimal point
24+
// Skip leading zeros after decimal points
25+
const numbersAfterDecimal = match[0].split(".")[1];
26+
const isSingleNonZeroDigit =
27+
numbersAfterDecimal.replace(/^0+/, "").length === 1;
28+
29+
// If we have 1 significant digit, return the match
30+
if (isSingleNonZeroDigit) {
31+
return match[0];
32+
}
33+
34+
// If we have 2 significant digits, get the number of digits after the decimal point
35+
const fractionDigits = numbersAfterDecimal.length;
36+
return new Intl.NumberFormat("en-US", {
37+
style: "decimal",
38+
notation: "standard",
39+
// maximumSignificantDigits: decimalDigits - 1,
40+
maximumFractionDigits: fractionDigits - 1,
41+
}).format(percentage);
42+
}
43+
44+
// Round to 1 digit, strip trailing zeros
45+
return percentage.toFixed(1).replace(/\.?0+$/, "");
46+
};

test/lib/formatPercentage.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { describe, it, expect } from "vitest";
2+
import { formatPercentageToFirstNonZeroDigit } from "@/lib/formatPercentage";
3+
4+
describe("formatPercentage", () => {
5+
it("should return the original integer if its more than 1", () => {
6+
expect(formatPercentageToFirstNonZeroDigit(97)).to.eq("97");
7+
});
8+
9+
it("should round to 1 decimal place if the integer is more than 1", () => {
10+
expect(formatPercentageToFirstNonZeroDigit(97.5)).to.eq("97.5");
11+
expect(formatPercentageToFirstNonZeroDigit(97.001)).to.eq("97");
12+
expect(formatPercentageToFirstNonZeroDigit(97.01)).to.eq("97");
13+
expect(formatPercentageToFirstNonZeroDigit(1.008)).to.eq("1");
14+
expect(formatPercentageToFirstNonZeroDigit(1.99)).to.eq("2");
15+
expect(formatPercentageToFirstNonZeroDigit(97.0000000000081)).to.eq("97");
16+
expect(formatPercentageToFirstNonZeroDigit(97.0000000000081)).to.eq("97");
17+
});
18+
19+
it("should round to the first non-zero digit", () => {
20+
expect(formatPercentageToFirstNonZeroDigit(0.008)).to.eq("0.008");
21+
expect(formatPercentageToFirstNonZeroDigit(0.0081)).to.eq("0.008");
22+
expect(formatPercentageToFirstNonZeroDigit(0.000000000008)).to.eq(
23+
"0.000000000008",
24+
);
25+
});
26+
27+
it("should take the second non-zero digit to round the first non-zero digit", () => {
28+
expect(formatPercentageToFirstNonZeroDigit(0.99)).to.eq("1");
29+
expect(formatPercentageToFirstNonZeroDigit(0.109)).to.eq("0.11");
30+
expect(formatPercentageToFirstNonZeroDigit(0.0000000000081)).to.eq(
31+
"0.000000000008",
32+
);
33+
expect(formatPercentageToFirstNonZeroDigit(0.0000000000085)).to.eq(
34+
"0.000000000009",
35+
);
36+
});
37+
});

0 commit comments

Comments
 (0)