fix(twenty-shared): derive short-number suffix from the rounded value (#21591)
`formatToShortNumber` (`packages/twenty-shared/src/utils/format/formatToShortNumber.ts`) picked the unit suffix from the **raw** value but printed the **rounded** figure, so `999999` rendered as `"1000k"` instead of `"1m"`, and `999999999` as `"1000m"` instead of `"1b"`. This affects number/currency cells, column-footer aggregates, and dashboard charts. The fix replaces the hard-coded band branches with a promotion loop that derives the suffix from the rounded display value, so the suffix and figure always agree at boundaries. Adds boundary, just-below-boundary, and negative-boundary tests. Red-green proven: the two new boundary tests fail on the original source (`expected "1m" but got "1000k"`); the 11 pre-existing tests still pass; all 13 pass with the fix. Verified with a standalone strict `tsc` (0 errors) and oxlint on both changed files. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21591?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -30,6 +30,17 @@ describe('formatToShortNumber', () => {
|
||||
expect(formatToShortNumber(0)).toBe('0');
|
||||
});
|
||||
|
||||
it('promotes to the next unit when rounding reaches the boundary', () => {
|
||||
expect(formatToShortNumber(999999)).toBe('1m');
|
||||
expect(formatToShortNumber(999950)).toBe('1m');
|
||||
expect(formatToShortNumber(999999999)).toBe('1b');
|
||||
});
|
||||
|
||||
it('does not promote just below a rounding boundary', () => {
|
||||
expect(formatToShortNumber(999949)).toBe('999.9k');
|
||||
expect(formatToShortNumber(999)).toBe('999');
|
||||
});
|
||||
|
||||
describe('negative numbers', () => {
|
||||
it('formats negative numbers less than 1000 correctly', () => {
|
||||
expect(formatToShortNumber(-500)).toBe('-500');
|
||||
@@ -50,5 +61,9 @@ describe('formatToShortNumber', () => {
|
||||
expect(formatToShortNumber(-1200000000)).toBe('-1.2b');
|
||||
expect(formatToShortNumber(-987654321987)).toBe('-987.7b');
|
||||
});
|
||||
|
||||
it('promotes negative numbers when rounding reaches the boundary', () => {
|
||||
expect(formatToShortNumber(-999999)).toBe('-1m');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,25 +2,17 @@ export const formatToShortNumber = (amount: number) => {
|
||||
const sign = amount < 0 ? '-' : '';
|
||||
const absoluteAmount = Math.abs(amount);
|
||||
|
||||
if (absoluteAmount < 1000) {
|
||||
return sign + absoluteAmount.toFixed(1).replace(/\.?0+$/, '');
|
||||
}
|
||||
const format = (scaled: number, suffix: string) =>
|
||||
sign + scaled.toFixed(1).replace(/\.?0+$/, '') + suffix;
|
||||
|
||||
if (absoluteAmount < 1_000_000) {
|
||||
return (
|
||||
sign + (absoluteAmount / 1000).toFixed(1).replace(/\.?0+$/, '') + 'k'
|
||||
);
|
||||
if (Number(absoluteAmount.toFixed(1)) < 1000) {
|
||||
return format(absoluteAmount, '');
|
||||
}
|
||||
|
||||
if (absoluteAmount < 1_000_000_000) {
|
||||
return (
|
||||
sign + (absoluteAmount / 1_000_000).toFixed(1).replace(/\.?0+$/, '') + 'm'
|
||||
);
|
||||
if (Number((absoluteAmount / 1_000).toFixed(1)) < 1000) {
|
||||
return format(absoluteAmount / 1_000, 'k');
|
||||
}
|
||||
|
||||
return (
|
||||
sign +
|
||||
(absoluteAmount / 1_000_000_000).toFixed(1).replace(/\.?0+$/, '') +
|
||||
'b'
|
||||
);
|
||||
if (Number((absoluteAmount / 1_000_000).toFixed(1)) < 1000) {
|
||||
return format(absoluteAmount / 1_000_000, 'm');
|
||||
}
|
||||
return format(absoluteAmount / 1_000_000_000, 'b');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user