From 808be0649619b613a3e90f6ec9be10e201609d8d Mon Sep 17 00:00:00 2001 From: handynfts2 Date: Thu, 30 Jul 2026 12:05:36 +0100 Subject: [PATCH] Fix #920: De-duplicate conflicting formatNumber implementations - Rename visualizationUtils.formatNumber to formatNumberCompact for clarity - Keep formatNumber as deprecated alias for backward compatibility - Update chartUtils.formatDashboardMetric to use formatNumberCompact - Update all imports and usages in DataExplorationTools component - Update tests to use formatNumberCompact - Update documentation (QUICK_START.md and README.md) to use formatNumberCompact - Add documentation notes about locale-aware formatting via i18nUtils.formatNumber This consolidates the three different formatNumber implementations: - visualizationUtils.formatNumberCompact: For compact K/M/B suffixing - i18nUtils.formatNumber: For locale-aware formatting via Intl - chartUtils.formatDashboardMetric: Now uses formatNumberCompact internally --- .../visualization/DataExplorationTools.tsx | 16 ++++++++-------- src/components/visualization/QUICK_START.md | 10 +++++++--- src/components/visualization/README.md | 12 ++++++++---- src/utils/__tests__/visualizationUtils.test.ts | 18 +++++++++--------- src/utils/chartUtils.ts | 5 ++--- src/utils/visualizationUtils.ts | 10 +++++++++- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/components/visualization/DataExplorationTools.tsx b/src/components/visualization/DataExplorationTools.tsx index f7719f6a..0f79cdc0 100644 --- a/src/components/visualization/DataExplorationTools.tsx +++ b/src/components/visualization/DataExplorationTools.tsx @@ -15,7 +15,7 @@ import { calculateStatistics, exportToCSV, exportToJSON, - formatNumber, + formatNumberCompact, } from '@/utils/visualizationUtils'; import { Filter, @@ -190,7 +190,7 @@ export const DataExplorationTools: React.FC = ({ Mean
- {formatNumber(statistics.mean)} + {formatNumberCompact(statistics.mean)}
@@ -200,7 +200,7 @@ export const DataExplorationTools: React.FC = ({ Median
- {formatNumber(statistics.median)} + {formatNumberCompact(statistics.median)}
@@ -210,7 +210,7 @@ export const DataExplorationTools: React.FC = ({ Mode
- {formatNumber(statistics.mode)} + {formatNumberCompact(statistics.mode)}
@@ -220,7 +220,7 @@ export const DataExplorationTools: React.FC = ({ Max
- {formatNumber(statistics.max)} + {formatNumberCompact(statistics.max)}
@@ -230,7 +230,7 @@ export const DataExplorationTools: React.FC = ({ Min
- {formatNumber(statistics.min)} + {formatNumberCompact(statistics.min)}
@@ -240,7 +240,7 @@ export const DataExplorationTools: React.FC = ({ Std Dev
- {formatNumber(statistics.stdDev)} + {formatNumberCompact(statistics.stdDev)}
@@ -283,7 +283,7 @@ export const DataExplorationTools: React.FC = ({ key={datasetIndex} className="text-right py-2 px-4 text-gray-900 dark:text-white" > - {formatNumber(dataset.data[index])} + {formatNumberCompact(dataset.data[index])} ))} diff --git a/src/components/visualization/QUICK_START.md b/src/components/visualization/QUICK_START.md index 9179a43b..365fe86c 100644 --- a/src/components/visualization/QUICK_START.md +++ b/src/components/visualization/QUICK_START.md @@ -170,11 +170,15 @@ All components automatically support dark mode through Tailwind CSS. ### Format Numbers ```tsx -import { formatNumber, formatPercentage } from '@/utils/visualizationUtils'; +import { formatNumberCompact, formatPercentage } from '@/utils/visualizationUtils'; -formatNumber(1500); // "1.5K" -formatNumber(1500000); // "1.5M" +formatNumberCompact(1500); // "1.5K" +formatNumberCompact(1500000); // "1.5M" formatPercentage(45.67); // "45.7%" + +// For locale-aware formatting, use i18nUtils.formatNumber +import { formatNumber } from '@/utils/i18nUtils'; +formatNumber(1500, 'en-US'); // "1,500" ``` ### Calculate Statistics diff --git a/src/components/visualization/README.md b/src/components/visualization/README.md index bda64d59..2ee41887 100644 --- a/src/components/visualization/README.md +++ b/src/components/visualization/README.md @@ -228,7 +228,7 @@ Helper functions for data transformation and formatting. ```tsx import { - formatNumber, + formatNumberCompact, formatPercentage, generateDateLabels, aggregateByTimePeriod, @@ -241,9 +241,13 @@ import { generateSampleData, } from '@/utils/visualizationUtils'; -// Format numbers -formatNumber(1500); // "1.5K" -formatNumber(1500000); // "1.5M" +// Format numbers with compact suffix (K, M, B) +formatNumberCompact(1500); // "1.5K" +formatNumberCompact(1500000); // "1.5M" + +// For locale-aware formatting, use i18nUtils.formatNumber +import { formatNumber } from '@/utils/i18nUtils'; +formatNumber(1500, 'en-US'); // "1,500" // Format percentages formatPercentage(45.678); // "45.7%" diff --git a/src/utils/__tests__/visualizationUtils.test.ts b/src/utils/__tests__/visualizationUtils.test.ts index 16988d92..47f8841a 100644 --- a/src/utils/__tests__/visualizationUtils.test.ts +++ b/src/utils/__tests__/visualizationUtils.test.ts @@ -4,7 +4,7 @@ import { describe, it, expect } from 'vitest'; import { - formatNumber, + formatNumberCompact, formatPercentage, generateDateLabels, calculateMovingAverage, @@ -15,24 +15,24 @@ import { } from '../visualizationUtils'; describe('visualizationUtils', () => { - describe('formatNumber', () => { + describe('formatNumberCompact', () => { it('should format numbers with K suffix', () => { - expect(formatNumber(1500)).toBe('1.5K'); - expect(formatNumber(999)).toBe('999'); + expect(formatNumberCompact(1500)).toBe('1.5K'); + expect(formatNumberCompact(999)).toBe('999'); }); it('should format numbers with M suffix', () => { - expect(formatNumber(1500000)).toBe('1.5M'); - expect(formatNumber(2300000)).toBe('2.3M'); + expect(formatNumberCompact(1500000)).toBe('1.5M'); + expect(formatNumberCompact(2300000)).toBe('2.3M'); }); it('should format numbers with B suffix', () => { - expect(formatNumber(1500000000)).toBe('1.5B'); - expect(formatNumber(3200000000)).toBe('3.2B'); + expect(formatNumberCompact(1500000000)).toBe('1.5B'); + expect(formatNumberCompact(3200000000)).toBe('3.2B'); }); it('should handle zero', () => { - expect(formatNumber(0)).toBe('0'); + expect(formatNumberCompact(0)).toBe('0'); }); }); diff --git a/src/utils/chartUtils.ts b/src/utils/chartUtils.ts index f4ea1525..634cb451 100644 --- a/src/utils/chartUtils.ts +++ b/src/utils/chartUtils.ts @@ -10,6 +10,7 @@ import { AggregationType, generateDateLabels, generateSampleData, + formatNumberCompact, } from '@/utils/visualizationUtils'; import { getNumberFormat } from './intlCache'; @@ -118,9 +119,7 @@ export const formatDashboardMetric = ( return `${value.toFixed(1)}%`; case 'count': default: - if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`; - if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`; - return String(Math.round(value)); + return formatNumberCompact(value); } }; diff --git a/src/utils/visualizationUtils.ts b/src/utils/visualizationUtils.ts index 74dfa17d..001c8076 100644 --- a/src/utils/visualizationUtils.ts +++ b/src/utils/visualizationUtils.ts @@ -67,9 +67,17 @@ export const CHART_COLOR_PALETTE = [ ]; /** - * Format number with appropriate suffix (K, M, B) + * Format number with appropriate suffix (K, M, B) for compact display + * @deprecated Use formatNumberCompact for clarity, or i18nUtils.formatNumber for locale-aware formatting */ export const formatNumber = (num: number): string => { + return formatNumberCompact(num); +}; + +/** + * Format number with appropriate suffix (K, M, B) for compact display + */ +export const formatNumberCompact = (num: number): string => { if (num >= 1000000000) { return (num / 1000000000).toFixed(1) + 'B'; }