From 02cd2d67a029750d266fd29f72e44e3c9a507932 Mon Sep 17 00:00:00 2001 From: Amirhossein Khalili Date: Mon, 27 Apr 2026 21:14:12 +0330 Subject: [PATCH] fix(reports): format localized income totals --- src/components/reports/ReportsChartPanel.tsx | 31 +++++++++++++++++++- src/components/reports/ReportsTablePanel.tsx | 31 +++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/components/reports/ReportsChartPanel.tsx b/src/components/reports/ReportsChartPanel.tsx index 1f7f228..55b8a23 100644 --- a/src/components/reports/ReportsChartPanel.tsx +++ b/src/components/reports/ReportsChartPanel.tsx @@ -37,9 +37,38 @@ const toPersianDigits = (value: string) => const localizeDigits = (value: string, lang: "en" | "fa") => (lang === "fa" ? toPersianDigits(value) : value); +const formatAmount = (value: string, lang: "en" | "fa") => { + const trimmed = value.trim(); + if (!trimmed) return trimmed; + const numeric = Number(trimmed.replace(/,/g, "")); + if (Number.isNaN(numeric)) return localizeDigits(trimmed, lang); + + const [integerPart, fractionalPart] = trimmed.replace(/,/g, "").split("."); + const grouped = Math.abs(Number(integerPart)).toLocaleString("en-US"); + const signed = trimmed.startsWith("-") ? `-${grouped}` : grouped; + const normalized = fractionalPart ? `${signed}.${fractionalPart}` : signed; + return localizeDigits(normalized, lang); +}; + +const currencyLabel = (currency: string, lang: "en" | "fa") => { + const normalized = currency.toUpperCase(); + if (lang !== "fa") return normalized; + return ( + { + USD: "دلار آمریکا", + EUR: "یورو", + GBP: "پوند", + IRR: "ریال", + IRT: "تومان", + AED: "درهم", + TRY: "لیر", + }[normalized] || normalized + ); +}; + const formatMoneyTotals = (totals: CurrencyTotal[], lang: "en" | "fa") => { if (!totals.length) return "-"; - return totals.map((item) => `${localizeDigits(item.amount, lang)} ${item.currency}`).join(" | "); + return totals.map((item) => `${formatAmount(item.amount, lang)} ${currencyLabel(item.currency, lang)}`).join(" | "); }; const formatSecondsTick = (value: number, lang: "en" | "fa") => { diff --git a/src/components/reports/ReportsTablePanel.tsx b/src/components/reports/ReportsTablePanel.tsx index 61f576a..17bbb4f 100644 --- a/src/components/reports/ReportsTablePanel.tsx +++ b/src/components/reports/ReportsTablePanel.tsx @@ -9,9 +9,38 @@ const toPersianDigits = (value: string) => const localizeDigits = (value: string, lang: "en" | "fa") => (lang === "fa" ? toPersianDigits(value) : value); +const formatAmount = (value: string, lang: "en" | "fa") => { + const trimmed = value.trim(); + if (!trimmed) return trimmed; + const numeric = Number(trimmed.replace(/,/g, "")); + if (Number.isNaN(numeric)) return localizeDigits(trimmed, lang); + + const [integerPart, fractionalPart] = trimmed.replace(/,/g, "").split("."); + const grouped = Math.abs(Number(integerPart)).toLocaleString("en-US"); + const signed = trimmed.startsWith("-") ? `-${grouped}` : grouped; + const normalized = fractionalPart ? `${signed}.${fractionalPart}` : signed; + return localizeDigits(normalized, lang); +}; + +const currencyLabel = (currency: string, lang: "en" | "fa") => { + const normalized = currency.toUpperCase(); + if (lang !== "fa") return normalized; + return ( + { + USD: "دلار آمریکا", + EUR: "یورو", + GBP: "پوند", + IRR: "ریال", + IRT: "تومان", + AED: "درهم", + TRY: "لیر", + }[normalized] || normalized + ); +}; + const formatMoneyTotals = (totals: { currency: string; amount: string }[], lang: "en" | "fa") => { if (!totals.length) return "-"; - return totals.map((item) => `${localizeDigits(item.amount, lang)} ${item.currency}`).join(" | "); + return totals.map((item) => `${formatAmount(item.amount, lang)} ${currencyLabel(item.currency, lang)}`).join(" | "); }; const formatDisplayDate = (value: string, lang: "en" | "fa") => {