/** * Toolkit - Currency Formatting * * Our product currently operates in Japanese Yen only, but we keep a single * helper so the portal and BFF share the same formatting behaviour. * * The function still accepts legacy signatures (`formatCurrency(amount, "JPY", "¥")`) * so existing call sites remain compatible. */ export type SupportedCurrency = "JPY"; type LegacyOptions = { /** * Optional locale override. Defaults to "ja-JP". */ locale?: string | undefined; /** * Set to false if you ever want to hide the symbol. Defaults to true. */ showSymbol?: boolean | undefined; /** * Optional custom symbol. Defaults to "¥". */ currencySymbol?: string | undefined; }; const DEFAULT_CURRENCY: SupportedCurrency = "JPY"; const DEFAULT_SYMBOL = "¥"; const DEFAULT_LOCALE = "ja-JP"; export const getCurrencyLocale = (_currency?: string): string => DEFAULT_LOCALE; const normalizeOptions = ( currencyOrOptions?: string | LegacyOptions, symbolOrOptions?: string | LegacyOptions ) => { const result: { currency: string; symbol: string; locale: string; showSymbol: boolean; } = { currency: DEFAULT_CURRENCY, symbol: DEFAULT_SYMBOL, locale: DEFAULT_LOCALE, showSymbol: true, }; const applyOptions = (opts?: LegacyOptions) => { if (!opts) return; if (opts.locale) result.locale = opts.locale; if (typeof opts.showSymbol === "boolean") result.showSymbol = opts.showSymbol; if (opts.currencySymbol) result.symbol = opts.currencySymbol; }; if (typeof currencyOrOptions === "string") { result.currency = currencyOrOptions; } else { applyOptions(currencyOrOptions); } if (typeof symbolOrOptions === "string") { result.symbol = symbolOrOptions; } else { applyOptions(symbolOrOptions); } // Even if a different currency code is provided, we treat it like JPY for now. const fractionDigits = result.currency.toUpperCase() === "JPY" ? 0 : 2; return { ...result, fractionDigits }; }; export function formatCurrency( amount: number, currencyOrOptions?: string | LegacyOptions, symbolOrOptions?: string | LegacyOptions ): string { const { locale, symbol, showSymbol, fractionDigits } = normalizeOptions( currencyOrOptions, symbolOrOptions ); const formatted = amount.toLocaleString(locale, { minimumFractionDigits: fractionDigits, maximumFractionDigits: fractionDigits, }); return showSymbol ? `${symbol}${formatted}` : formatted; } export function parseCurrency(value: string): number | null { const cleaned = value.replace(/[¥$€,\s]/g, ""); const parsed = Number.parseFloat(cleaned); return Number.isFinite(parsed) ? parsed : null; }