81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
/**
|
|
* Formatting lives here so a rupee looks the same in a KPI, an axis tick and a
|
|
* tooltip. Locale is pinned to en-IN — this is an Indian retail product, and
|
|
* lakh/crore grouping is what merchants read.
|
|
*
|
|
* Every formatter is pure and locale-explicit: relying on the runtime default
|
|
* would make the server and client disagree and produce hydration mismatches.
|
|
*/
|
|
|
|
const NUM = new Intl.NumberFormat('en-IN');
|
|
const INR = new Intl.NumberFormat('en-IN', {
|
|
style: 'currency',
|
|
currency: 'INR',
|
|
maximumFractionDigits: 0,
|
|
});
|
|
|
|
export function formatCount(v: number): string {
|
|
return NUM.format(Math.round(v));
|
|
}
|
|
|
|
export function formatInr(v: number): string {
|
|
return INR.format(Math.round(v));
|
|
}
|
|
|
|
/** Drops a trailing ".0" so axis ticks read ₹90k rather than ₹90.0k. */
|
|
function trim(n: number): string {
|
|
return n.toFixed(1).replace(/\.0$/, '');
|
|
}
|
|
|
|
/** Axis-scale currency: ₹1.2L rather than ₹1,20,000. */
|
|
export function formatInrCompact(v: number): string {
|
|
if (Math.abs(v) >= 10000000) return `₹${trim(v / 10000000)}Cr`;
|
|
if (Math.abs(v) >= 100000) return `₹${trim(v / 100000)}L`;
|
|
if (Math.abs(v) >= 1000) return `₹${trim(v / 1000)}k`;
|
|
return `₹${Math.round(v)}`;
|
|
}
|
|
|
|
export function formatCompact(v: number): string {
|
|
if (Math.abs(v) >= 10000000) return `${trim(v / 10000000)}Cr`;
|
|
if (Math.abs(v) >= 100000) return `${trim(v / 100000)}L`;
|
|
if (Math.abs(v) >= 1000) return `${trim(v / 1000)}k`;
|
|
return String(Math.round(v));
|
|
}
|
|
|
|
export function formatPct(v: number, digits = 1): string {
|
|
return `${v.toFixed(digits)}%`;
|
|
}
|
|
|
|
export function formatLyt(v: number): string {
|
|
return `${NUM.format(Math.round(v))} LYT`;
|
|
}
|
|
|
|
/** Signed delta for the KPI change chip. */
|
|
export function formatDelta(v: number): string {
|
|
return `${v > 0 ? '+' : ''}${v.toFixed(1)}%`;
|
|
}
|
|
|
|
/** "12 Aug" — short axis label for a yyyy-mm-dd key. */
|
|
export function formatDayLabel(iso: string | number): string {
|
|
const d = new Date(String(iso));
|
|
if (Number.isNaN(d.getTime())) return String(iso);
|
|
return new Intl.DateTimeFormat('en-IN', {
|
|
day: 'numeric',
|
|
month: 'short',
|
|
timeZone: 'UTC',
|
|
}).format(d);
|
|
}
|
|
|
|
export function formatByUnit(unit: 'count' | 'inr' | 'lyt' | 'pct') {
|
|
switch (unit) {
|
|
case 'inr':
|
|
return formatInr;
|
|
case 'lyt':
|
|
return formatLyt;
|
|
case 'pct':
|
|
return (v: number) => formatPct(v);
|
|
default:
|
|
return formatCount;
|
|
}
|
|
}
|