feat(reports): enrich all-user report details
This commit is contained in:
@@ -25,7 +25,12 @@ type ChartRow = {
|
||||
const localizeDigits = (value: string, lang: "en" | "fa") =>
|
||||
lang === "fa" ? value.replace(/\d/g, (digit) => PERSIAN_DIGITS[Number(digit)] || digit) : value
|
||||
|
||||
const formatAmount = (value: string, lang: "en" | "fa") => {
|
||||
const shouldTrimCurrencyDecimals = (currency?: string | null) => {
|
||||
const normalized = (currency || "").toUpperCase()
|
||||
return normalized === "IRR" || normalized === "IRT"
|
||||
}
|
||||
|
||||
const formatAmount = (value: string, lang: "en" | "fa", currency?: string | null) => {
|
||||
const numeric = Number(value.replace(/,/g, ""))
|
||||
if (Number.isNaN(numeric)) {
|
||||
return localizeDigits(value, lang)
|
||||
@@ -34,7 +39,9 @@ const formatAmount = (value: string, lang: "en" | "fa") => {
|
||||
const [integerPart, fractionalPart] = value.replace(/,/g, "").split(".")
|
||||
const grouped = Math.abs(Number(integerPart)).toLocaleString("en-US")
|
||||
const signed = value.startsWith("-") ? `-${grouped}` : grouped
|
||||
const formatted = fractionalPart ? `${signed}.${fractionalPart}` : signed
|
||||
const normalizedFraction =
|
||||
fractionalPart && !shouldTrimCurrencyDecimals(currency) ? fractionalPart.replace(/0+$/, "") : ""
|
||||
const formatted = normalizedFraction ? `${signed}.${normalizedFraction}` : signed
|
||||
return localizeDigits(formatted, lang)
|
||||
}
|
||||
|
||||
@@ -61,7 +68,7 @@ const formatMoneyTotals = (totals: CurrencyTotal[], lang: "en" | "fa") => {
|
||||
return "-"
|
||||
}
|
||||
|
||||
return totals.map((item) => `${formatAmount(item.amount, lang)} ${currencyLabel(item.currency, lang)}`).join(" | ")
|
||||
return totals.map((item) => `${formatAmount(item.amount, lang, item.currency)} ${currencyLabel(item.currency, lang)}`).join(" | ")
|
||||
}
|
||||
|
||||
const formatSecondsTick = (value: number, lang: "en" | "fa") => {
|
||||
@@ -260,12 +267,39 @@ function ChartTooltip({
|
||||
export function ReportsChartPanel({
|
||||
data,
|
||||
labels,
|
||||
isLoading,
|
||||
}: {
|
||||
data: ChartReportResponse | null
|
||||
labels: Record<string, string>
|
||||
isLoading: boolean
|
||||
}) {
|
||||
const { lang } = useTranslation()
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-3 xl:grid-cols-4">
|
||||
{Array.from({ length: 4 }).map((_, index) => (
|
||||
<div key={index} className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900">
|
||||
<div className="mb-3 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500 dark:text-slate-400">
|
||||
{labels.loading}
|
||||
</div>
|
||||
<div className="h-8 animate-pulse rounded-xl bg-slate-200/80 dark:bg-slate-800/80" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="rounded-3xl border border-slate-200 bg-white p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900 sm:p-5">
|
||||
<div className="mb-4 flex items-center justify-between gap-3">
|
||||
<div className="text-sm font-semibold text-slate-900 dark:text-white">{labels.chart}</div>
|
||||
<div className="text-xs text-slate-500 dark:text-slate-400">{labels.loading}</div>
|
||||
</div>
|
||||
<div className="h-[320px] animate-pulse rounded-2xl bg-slate-200/80 dark:bg-slate-800/80 sm:h-[360px]" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!data || data.series.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user