frontend_nyla/src/utils/formatDataSize.ts
2026-03-29 12:18:56 +02:00

43 lines
1.6 KiB
TypeScript

/**
* Central binary (1024) data-size formatting for the UI.
*
* - Use formatBinaryDataSizeBytes for raw byte counts (files, RAG totals, …).
* - Use formatBinaryDataSizeFromMebibytes for API fields stored as MB (mebibytes), e.g. maxDataVolumeMB.
*/
const BINARY_BASE = 1024;
const BINARY_UNITS = ['B', 'KB', 'MB', 'GB', 'TB'] as const;
function _maxFractionDigits(value: number): number {
if (value >= 100 || Number.isInteger(value)) return 0;
if (value >= 10) return 1;
return 2;
}
/**
* Human-readable size from a byte count; picks B … TB automatically (1024-based).
*/
export function formatBinaryDataSizeBytes(bytes: number, localeId = 'de-CH'): string {
if (!Number.isFinite(bytes)) return '—';
if (bytes < 0) return '—';
if (bytes === 0) return `0 ${BINARY_UNITS[0]}`;
const rawExp = Math.floor(Math.log(bytes) / Math.log(BINARY_BASE));
const exp = Math.max(0, Math.min(BINARY_UNITS.length - 1, rawExp));
const value = bytes / BINARY_BASE ** exp;
const maxFrac = _maxFractionDigits(value);
const formatted = new Intl.NumberFormat(localeId, {
maximumFractionDigits: maxFrac,
minimumFractionDigits: 0,
}).format(value);
return `${formatted} ${BINARY_UNITS[exp]}`;
}
/**
* Same as formatBinaryDataSizeBytes, but input is mebibytes (API convention for plan limits).
*/
export function formatBinaryDataSizeFromMebibytes(mebibytes: number, localeId = 'de-CH'): string {
if (!Number.isFinite(mebibytes) || mebibytes < 0) return '—';
if (mebibytes === 0) return `0 ${BINARY_UNITS[0]}`;
return formatBinaryDataSizeBytes(mebibytes * BINARY_BASE * BINARY_BASE, localeId);
}