Skip to content

Commit c1ddb57

Browse files
Copilotelecterious
andcommitted
Replace human-number with Intl.NumberFormat and add tests
Co-authored-by: electerious <[email protected]>
1 parent f2b0c88 commit c1ddb57

File tree

7 files changed

+103
-38
lines changed

7 files changed

+103
-38
lines changed

package-lock.json

Lines changed: 0 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@
6464
"classnames": "^2.3.1",
6565
"formbase": "^12.0.2",
6666
"history": "^5.3.0",
67-
"human-number": "^2.0.1",
6867
"mocked-env": "^1.3.5",
6968
"mongodb-memory-server": "^10.3.0",
7069
"nodemon": "^3.1.10",
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Format a number using compact notation with SI prefixes (K, M, B, T)
3+
* @param {number} num - The number to format
4+
* @param {number} maximumFractionDigits - Maximum number of fraction digits (default: 1)
5+
* @returns {string} The formatted number
6+
*/
7+
export default (num, maximumFractionDigits = 1) => {
8+
const formatter = new Intl.NumberFormat('en', {
9+
notation: 'compact',
10+
compactDisplay: 'short',
11+
maximumFractionDigits,
12+
})
13+
14+
return formatter.format(num)
15+
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
import humanNumber from 'human-number'
1+
import formatCompactNumber from './formatCompactNumber'
22

33
export default (num) => {
4-
const formattedNum = humanNumber(num, (num) => Number.parseFloat(num).toFixed(2))
5-
const cleanNum = formattedNum.replace('.00', '')
6-
7-
return cleanNum
4+
return formatCompactNumber(num, 2)
85
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
import humanNumber from 'human-number'
1+
import formatCompactNumber from './formatCompactNumber'
22

33
export default (num) => {
44
const roundedNum = Math.round(num)
5-
const formattedNum = humanNumber(roundedNum, (num) => Number.parseFloat(num).toFixed(1))
6-
const cleanNum = formattedNum.replace('.0', '')
7-
8-
return cleanNum
5+
return formatCompactNumber(roundedNum, 1)
96
}

src/utils/formatCompactNumber.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict'
2+
3+
/**
4+
* Format a number using compact notation with SI prefixes (K, M, B, T)
5+
* @param {number} num - The number to format
6+
* @param {number} maximumFractionDigits - Maximum number of fraction digits (default: 1)
7+
* @returns {string} The formatted number
8+
*/
9+
module.exports = (num, maximumFractionDigits = 1) => {
10+
const formatter = new Intl.NumberFormat('en', {
11+
notation: 'compact',
12+
compactDisplay: 'short',
13+
maximumFractionDigits,
14+
})
15+
16+
return formatter.format(num)
17+
}

test/utils/formatCompactNumber.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
'use strict'
2+
3+
const test = require('ava')
4+
5+
const formatCompactNumber = require('../../src/utils/formatCompactNumber')
6+
7+
test('format numbers less than 1000 without suffix', (t) => {
8+
t.is(formatCompactNumber(0), '0')
9+
t.is(formatCompactNumber(100), '100')
10+
t.is(formatCompactNumber(999), '999')
11+
})
12+
13+
test('format thousands with K suffix', (t) => {
14+
t.is(formatCompactNumber(1000), '1K')
15+
t.is(formatCompactNumber(1500), '1.5K')
16+
t.is(formatCompactNumber(10000), '10K')
17+
t.is(formatCompactNumber(10500), '10.5K')
18+
t.is(formatCompactNumber(99999), '100K')
19+
})
20+
21+
test('format millions with M suffix', (t) => {
22+
t.is(formatCompactNumber(1000000), '1M')
23+
t.is(formatCompactNumber(1500000), '1.5M')
24+
t.is(formatCompactNumber(10000000), '10M')
25+
t.is(formatCompactNumber(10500000), '10.5M')
26+
})
27+
28+
test('format billions with B suffix', (t) => {
29+
t.is(formatCompactNumber(1000000000), '1B')
30+
t.is(formatCompactNumber(1500000000), '1.5B')
31+
})
32+
33+
test('format trillions with T suffix', (t) => {
34+
t.is(formatCompactNumber(1000000000000), '1T')
35+
t.is(formatCompactNumber(1500000000000), '1.5T')
36+
})
37+
38+
test('respect maximumFractionDigits parameter', (t) => {
39+
// Default is 1
40+
t.is(formatCompactNumber(1234), '1.2K')
41+
42+
// With 0 fraction digits
43+
t.is(formatCompactNumber(1234, 0), '1K')
44+
45+
// With 2 fraction digits
46+
t.is(formatCompactNumber(1234, 2), '1.23K')
47+
t.is(formatCompactNumber(123.456, 2), '123.46')
48+
})
49+
50+
test('handle decimal numbers', (t) => {
51+
t.is(formatCompactNumber(1234.56, 2), '1.23K')
52+
t.is(formatCompactNumber(123.456, 2), '123.46')
53+
t.is(formatCompactNumber(12.34, 2), '12.34')
54+
})
55+
56+
test('handle negative numbers', (t) => {
57+
t.is(formatCompactNumber(-1000), '-1K')
58+
t.is(formatCompactNumber(-1500), '-1.5K')
59+
t.is(formatCompactNumber(-1000000), '-1M')
60+
})
61+
62+
test('handle edge cases', (t) => {
63+
t.is(formatCompactNumber(999.9), '999.9')
64+
t.is(formatCompactNumber(999.4), '999.4')
65+
t.is(formatCompactNumber(1000), '1K')
66+
t.is(formatCompactNumber(0.1, 2), '0.1')
67+
})

0 commit comments

Comments
 (0)