feat(projects): add per-project rate overrides to access modal
This commit is contained in:
76
src/lib/money.ts
Normal file
76
src/lib/money.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
const PERSIAN_DIGITS = "۰۱۲۳۴۵۶۷۸۹";
|
||||
|
||||
export const localizeDigits = (value: string, lang: "en" | "fa") =>
|
||||
lang === "fa" ? value.replace(/\d/g, (digit) => PERSIAN_DIGITS[Number(digit)] || digit) : value;
|
||||
|
||||
export 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
|
||||
);
|
||||
};
|
||||
|
||||
export const shouldTrimCurrencyDecimals = (currency?: string | null) => {
|
||||
const normalized = (currency || "").toUpperCase();
|
||||
return normalized === "IRR" || normalized === "IRT";
|
||||
};
|
||||
|
||||
export const formatAmountForCurrency = (
|
||||
value: string,
|
||||
currency: string | null | undefined,
|
||||
lang: "en" | "fa",
|
||||
) => {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return trimmed;
|
||||
const normalizedValue = trimmed.replace(/,/g, "");
|
||||
const numeric = Number(normalizedValue);
|
||||
if (Number.isNaN(numeric)) return localizeDigits(trimmed, lang);
|
||||
|
||||
const [integerPart, fractionalPart] = normalizedValue.split(".");
|
||||
const grouped = Math.abs(Number(integerPart)).toLocaleString("en-US");
|
||||
const signed = normalizedValue.startsWith("-") ? `-${grouped}` : grouped;
|
||||
let formatted = signed;
|
||||
|
||||
if (fractionalPart) {
|
||||
const nextFraction = shouldTrimCurrencyDecimals(currency)
|
||||
? ""
|
||||
: fractionalPart.replace(/0+$/, "");
|
||||
if (nextFraction) {
|
||||
formatted = `${formatted}.${nextFraction}`;
|
||||
}
|
||||
}
|
||||
|
||||
return localizeDigits(formatted, lang);
|
||||
};
|
||||
|
||||
export const formatMoneyTotals = (
|
||||
totals: { currency: string; amount: string }[],
|
||||
lang: "en" | "fa",
|
||||
) => {
|
||||
if (!totals.length) return "-";
|
||||
return totals
|
||||
.map((item) => `${formatAmountForCurrency(item.amount, item.currency, lang)} ${currencyLabel(item.currency, lang)}`)
|
||||
.join(" | ");
|
||||
};
|
||||
|
||||
export const formatRateDisplay = (
|
||||
rate: { amount?: string | null; hourly_rate?: string | null; currency: string; price_unit?: { code?: string; local_name?: string; name?: string } | null } | null,
|
||||
lang: "en" | "fa",
|
||||
) => {
|
||||
if (!rate) return "-";
|
||||
const amount = rate.amount ?? rate.hourly_rate ?? "";
|
||||
const unitLabel =
|
||||
lang === "fa"
|
||||
? rate.price_unit?.local_name || rate.price_unit?.code || currencyLabel(rate.currency, lang)
|
||||
: rate.price_unit?.code || rate.currency;
|
||||
return `${formatAmountForCurrency(amount, rate.currency, lang)} ${unitLabel}`;
|
||||
};
|
||||
Reference in New Issue
Block a user