/** * 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; } }