"use client"; import { useEffect, useMemo, useRef, useState } from "react"; import type { QuestionField } from "@/data/question-data"; import { useI18n } from "@/translations/provider"; import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; type QuestionNumberProps = { question: QuestionField; questionIndex: number; disabled?: boolean; derivedFromQuestion?: QuestionField; derivedFromQuestionIndex?: number; }; const NUMBER_INPUT_PATTERN = /^-?\d*\.?\d*$/; export default function QuestionNumber({ question, questionIndex, disabled, derivedFromQuestion, derivedFromQuestionIndex, }: QuestionNumberProps) { const { dictionary: t, locale } = useI18n(); const { getAnswerValue, setAnswerValue } = useQuestionAnswers(); const value = getAnswerValue(question, questionIndex); const derivedValue = derivedFromQuestion && derivedFromQuestionIndex !== undefined ? getAnswerValue(derivedFromQuestion, derivedFromQuestionIndex) : null; useEffect(() => { if (derivedFromQuestion && typeof derivedValue === "string") { const age = calculateAge(derivedValue); if (age !== String(value)) { setAnswerValue(question, questionIndex, age); } } }, [ derivedFromQuestion, derivedValue, question, questionIndex, setAnswerValue, value, ]); useEffect(() => { if ( typeof value === "string" && value.length > 0 && !NUMBER_INPUT_PATTERN.test(value) ) { setAnswerValue(question, questionIndex, null); } }, [question, questionIndex, setAnswerValue, value]); const [min, max] = question.extras.range; const numValue = typeof value === "number" ? value : typeof value === "string" ? parseFloat(value) : NaN; const isOutOfRange = useMemo(() => { if (Number.isNaN(numValue)) return false; if (min !== 0 && numValue < min) return true; if (max !== 0 && numValue > max) return true; return false; }, [numValue, min, max]); const rawInputValue = value == null ? "" : String(value); const inputValue = NUMBER_INPUT_PATTERN.test(rawInputValue) ? rawInputValue : ""; const isMonthlyIncome = question.title === "Monthly Income" || question.title === "میزان درآمد ماهانه"; const countryName = useMemo(() => getCountryFromStorage(), []); const [currencyCode, setCurrencyCode] = useState(() => { if (typeof window !== "undefined") { const stored = window.localStorage.getItem("marriage:income:currency"); if (stored) return stored; } return getCurrencyForCountry(countryName); }); const [isCurrencyDropdownOpen, setIsCurrencyDropdownOpen] = useState(false); const [currencySearchQuery, setCurrencySearchQuery] = useState(""); const currencyContainerRef = useRef(null); const currencySearchInputRef = useRef(null); useEffect(() => { if (typeof window !== "undefined") { const stored = window.localStorage.getItem("marriage:income:currency"); if (stored) { setCurrencyCode(stored); return; } } const derived = getCurrencyForCountry(countryName); setCurrencyCode(derived); }, [countryName]); useEffect(() => { function handleClickOutside(event: MouseEvent) { if ( currencyContainerRef.current && !currencyContainerRef.current.contains(event.target as Node) ) { setIsCurrencyDropdownOpen(false); } } document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, []); useEffect(() => { if (isCurrencyDropdownOpen) { setTimeout(() => { currencySearchInputRef.current?.focus(); }, 50); } }, [isCurrencyDropdownOpen]); const filteredCurrencies = useMemo(() => { const q = currencySearchQuery.toLowerCase().trim(); if (!q) return CURRENCIES; return CURRENCIES.filter( (c) => c.code.toLowerCase().includes(q) || c.nameEn.toLowerCase().includes(q) || c.nameFa.toLowerCase().includes(q), ); }, [currencySearchQuery]); const placeholderCurrency = useMemo(() => { if (currencyCode === "TOMAN") { return locale === "fa" ? "تومان" : "TOMAN"; } return currencyCode; }, [currencyCode, locale]); const dynamicPlaceholder = useMemo(() => { if (!isMonthlyIncome) { return question.extras.placeHolder; } return locale === "fa" ? `مثال: ۴۰۰۰ ${placeholderCurrency}` : `e.g. 4000 ${placeholderCurrency}`; }, [ isMonthlyIncome, question.extras.placeHolder, placeholderCurrency, locale, ]); const [localTextValue, setLocalTextValue] = useState(() => formatNumberWithCommas(inputValue), ); useEffect(() => { const formatted = formatNumberWithCommas( value == null ? "" : String(value), ); const cleanLocal = localTextValue.replace(/,/g, ""); const cleanFormatted = formatted.replace(/,/g, ""); if (cleanFormatted !== cleanLocal) { setLocalTextValue(formatted); } }, [value, localTextValue]); if (isMonthlyIncome) { return (
{ const nextValue = event.target.value; const cleanValue = nextValue.replace(/,/g, ""); if ( cleanValue !== "" && !NUMBER_INPUT_PATTERN.test(cleanValue) ) { return; } const formatted = formatNumberWithCommas(cleanValue); const finalFormatted = nextValue.endsWith(".") ? `${formatted}.` : formatted; setLocalTextValue(finalFormatted); if (cleanValue === "") { setAnswerValue(question, questionIndex, null); } else { const parsed = parseFloat(cleanValue); setAnswerValue( question, questionIndex, Number.isNaN(parsed) ? cleanValue : parsed, ); } }} className={[ "h-[54px] w-full rounded-[16px] border px-4.5 text-[15px] font-medium text-[#181818] outline-none transition-all placeholder:text-[#98A2B3] focus:border-[#6F6F6F] focus:ring-1 focus:ring-[#6F6F6F] disabled:bg-[#F5F2F1] disabled:text-[#7C7472]", isOutOfRange ? "border-[#F2465F] ring-1 ring-[#F2465F]" : "border-[#D0D5DD] hover:border-[#98A2B3] bg-white", ].join(" ")} />
{isCurrencyDropdownOpen && (
{/* Search bar */}
setCurrencySearchQuery(e.target.value)} placeholder={locale === "fa" ? "جستجو..." : "Search..."} className="flex-1 min-w-0 bg-transparent text-[13px] font-medium text-[#181818] outline-none placeholder:text-[#98A2B3]" /> {currencySearchQuery ? ( ) : null}
{/* Options list */}
{filteredCurrencies.length > 0 ? ( filteredCurrencies.map((c) => { const isSelected = c.code === currencyCode; return ( ); }) ) : ( {locale === "fa" ? "ارزی یافت نشد" : "No currencies found"} )}
)}
{isOutOfRange ? ( {t.common.rangeError || `Please enter a value between ${min} and ${max}`} ) : null}
); } return (
{ const nextValue = event.target.value; if (!NUMBER_INPUT_PATTERN.test(nextValue)) { event.currentTarget.value = inputValue; return; } if (nextValue === "") { setAnswerValue(question, questionIndex, null); } else { const parsed = parseFloat(nextValue); setAnswerValue( question, questionIndex, Number.isNaN(parsed) ? nextValue : parsed, ); } }} className={[ "h-[54px] w-full rounded-[16px] border px-4.5 text-[15px] font-medium text-[#181818] outline-none transition-all placeholder:text-[#98A2B3] focus:border-[#6F6F6F] focus:ring-1 focus:ring-[#6F6F6F] disabled:bg-[#F5F2F1] disabled:text-[#7C7472]", isOutOfRange ? "border-[#F2465F] ring-1 ring-[#F2465F]" : "border-[#D0D5DD] hover:border-[#98A2B3] bg-white", ].join(" ")} /> {isOutOfRange ? ( {t.common.rangeError || `Please enter a value between ${min} and ${max}`} ) : null}
); } function calculateAge(dateOfBirth: string) { const birthDate = new Date(dateOfBirth); if (Number.isNaN(birthDate.getTime())) { return ""; } const today = new Date(); let age = today.getFullYear() - birthDate.getFullYear(); const monthDifference = today.getMonth() - birthDate.getMonth(); if ( monthDifference < 0 || (monthDifference === 0 && today.getDate() < birthDate.getDate()) ) { age -= 1; } return String(Math.max(age, 0)); } function getCountryFromStorage(): string { if (typeof window === "undefined") return ""; try { const rawValue = window.localStorage.getItem( "marriage:sections:contact_residence_family_communication:answers", ); if (!rawValue) return ""; const storedValue = JSON.parse(rawValue); const field = storedValue.fields?.find( (f: { type?: string; key?: string; value?: unknown }) => f.type === "birthplace" || f.key?.includes("current_residence") || f.key?.includes("mhl_skwnt_fly"), ); const value = field?.value; if (typeof value === "string") { const parts = value.split(","); return parts[0]?.trim() || ""; } } catch { // Ignore } return ""; } function getCurrencyForCountry(countryName: string): string { const cleanCountry = countryName?.trim(); if (!cleanCountry) return "USD"; const countryMap: Record = { // English Iran: "TOMAN", "United States": "USD", "United Kingdom": "GBP", Canada: "CAD", Germany: "EUR", France: "EUR", "United Arab Emirates": "AED", Turkey: "TRY", Iraq: "IQD", Afghanistan: "AFN", Pakistan: "PKR", "Saudi Arabia": "SAR", Qatar: "QAR", Sweden: "SEK", Netherlands: "EUR", Norway: "NOK", Australia: "AUD", Bulgaria: "BGN", // Persian ایران: "TOMAN", "ایالات متحده": "USD", بریتانیا: "GBP", کانادا: "CAD", آلمان: "EUR", فرانسه: "EUR", "امارات متحده عربی": "AED", ترکیه: "TRY", عراق: "IQD", افغانستان: "AFN", پاکستان: "PKR", "عربستان سعودی": "SAR", قطر: "QAR", سوئد: "SEK", هلند: "EUR", نروژ: "NOK", استرالیا: "AUD", بلغارستان: "BGN", }; return countryMap[cleanCountry] || "USD"; } const CURRENCIES = [ { code: "AED", nameEn: "UAE Dirham", nameFa: "درهم امارات" }, { code: "AFN", nameEn: "Afghan Afghani", nameFa: "افغانی افغانستان" }, { code: "ALL", nameEn: "Albanian Lek", nameFa: "لک آلبانی" }, { code: "AMD", nameEn: "Armenian Dram", nameFa: "درام ارمنستان" }, { code: "ANG", nameEn: "Netherlands Antillean Guilder", nameFa: "گیلدر آنتیل هلند", }, { code: "AOA", nameEn: "Angolan Kwanza", nameFa: "کوانزای آنگولا" }, { code: "ARS", nameEn: "Argentine Peso", nameFa: "پزو آرژانتین" }, { code: "AUD", nameEn: "Australian Dollar", nameFa: "دلار استرالیا" }, { code: "AZN", nameEn: "Azerbaijani Manat", nameFa: "منات آذربایجان" }, { code: "BAM", nameEn: "Bosnia-Herzegovina Mark", nameFa: "مارک بوسنی و هرزگوین", }, { code: "BBD", nameEn: "Barbadian Dollar", nameFa: "دلار باربادوس" }, { code: "BDT", nameEn: "Bangladeshi Taka", nameFa: "تاکای بنگلادش" }, { code: "BGN", nameEn: "Bulgarian Lev", nameFa: "لو بلغارستان" }, { code: "BHD", nameEn: "Bahraini Dinar", nameFa: "دینار بحرین" }, { code: "BIF", nameEn: "Burundian Franc", nameFa: "فرانک بروندی" }, { code: "BMD", nameEn: "Bermudian Dollar", nameFa: "دلار برمودا" }, { code: "BND", nameEn: "Brunei Dollar", nameFa: "دلار برونئی" }, { code: "BOB", nameEn: "Bolivian Boliviano", nameFa: "بولیویانو بولیوی" }, { code: "BRL", nameEn: "Brazilian Real", nameFa: "رئال برزیل" }, { code: "BSD", nameEn: "Bahamian Dollar", nameFa: "دلار باهاما" }, { code: "BTN", nameEn: "Bhutanese Ngultrum", nameFa: "نگولتروم بوتان" }, { code: "BWP", nameEn: "Botswanan Pula", nameFa: "پولای بوتسوانا" }, { code: "BYN", nameEn: "Belarusian Ruble", nameFa: "روبل بلاروس" }, { code: "BZD", nameEn: "Belize Dollar", nameFa: "دلار بلیز" }, { code: "CAD", nameEn: "Canadian Dollar", nameFa: "دلار کانادا" }, { code: "CDF", nameEn: "Congolese Franc", nameFa: "فرانک کنگو" }, { code: "CHF", nameEn: "Swiss Franc", nameFa: "فرانک سوئیس" }, { code: "CLP", nameEn: "Chilean Peso", nameFa: "پزو شیلی" }, { code: "CNY", nameEn: "Chinese Yuan", nameFa: "یوان چین" }, { code: "COP", nameEn: "Colombian Peso", nameFa: "پزو کلمبیا" }, { code: "CRC", nameEn: "Costa Rican Colón", nameFa: "کولون کاستاریکا" }, { code: "CUP", nameEn: "Cuban Peso", nameFa: "پزو کوبا" }, { code: "CVE", nameEn: "Cape Verdean Escudo", nameFa: "اسکودو کیپ ورد" }, { code: "CZK", nameEn: "Czech Koruna", nameFa: "کرون چک" }, { code: "DJF", nameEn: "Djiboutian Franc", nameFa: "فرانک جیبوتی" }, { code: "DKK", nameEn: "Danish Krone", nameFa: "کرون دانمارک" }, { code: "DOP", nameEn: "Dominican Peso", nameFa: "پزو دومینیکن" }, { code: "DZD", nameEn: "Algerian Dinar", nameFa: "دینار الجزایر" }, { code: "EGP", nameEn: "Egyptian Pound", nameFa: "پوند مصر" }, { code: "ERN", nameEn: "Eritrean Nakfa", nameFa: "ناکفای اریتره" }, { code: "ETB", nameEn: "Ethiopian Birr", nameFa: "بیر اتیوپی" }, { code: "EUR", nameEn: "Euro", nameFa: "یورو" }, { code: "FJD", nameEn: "Fijian Dollar", nameFa: "دلار فیجی" }, { code: "FKP", nameEn: "Falkland Islands Pound", nameFa: "پوند جزایر فالکلند", }, { code: "GBP", nameEn: "British Pound", nameFa: "پوند بریتانیا" }, { code: "GEL", nameEn: "Georgian Lari", nameFa: "لاری گرجستان" }, { code: "GHS", nameEn: "Ghanaian Cedi", nameFa: "سدی غنا" }, { code: "GIP", nameEn: "Gibraltar Pound", nameFa: "پوند جبل الطارق" }, { code: "GMD", nameEn: "Gambian Dalasi", nameFa: "دالاسی گامبیا" }, { code: "GNF", nameEn: "Guinean Franc", nameFa: "فرانک گینه" }, { code: "GTQ", nameEn: "Guatemalan Quetzal", nameFa: "کوتزال گواتمالا" }, { code: "GYD", nameEn: "Guyanese Dollar", nameFa: "دلار گویان" }, { code: "HKD", nameEn: "Hong Kong Dollar", nameFa: "دلار هنگ کنگ" }, { code: "HNL", nameEn: "Honduran Lempira", nameFa: "لمپیرای هندوراس" }, { code: "HRK", nameEn: "Croatian Kuna", nameFa: "کونای کرواسی" }, { code: "HTG", nameEn: "Haitian Gourde", nameFa: "گورد هائیتی" }, { code: "HUF", nameEn: "Hungarian Forint", nameFa: "فورینت مجارستان" }, { code: "IDR", nameEn: "Indonesian Rupiah", nameFa: "روپیه اندونزی" }, { code: "ILS", nameEn: "Israeli Shekel", nameFa: "شکل اسرائیل" }, { code: "INR", nameEn: "Indian Rupee", nameFa: "روپیه هند" }, { code: "IQD", nameEn: "Iraqi Dinar", nameFa: "دینار عراق" }, { code: "IRR", nameEn: "Iranian Rial", nameFa: "ریال ایران" }, { code: "ISK", nameEn: "Icelandic Króna", nameFa: "کرون ایسلند" }, { code: "JMD", nameEn: "Jamaican Dollar", nameFa: "دلار جامائیکا" }, { code: "JOD", nameEn: "Jordanian Dinar", nameFa: "دینار اردن" }, { code: "JPY", nameEn: "Japanese Yen", nameFa: "ین ژاپن" }, { code: "KES", nameEn: "Kenyan Shilling", nameFa: "شیلینگ کنیا" }, { code: "KGS", nameEn: "Kyrgystani Som", nameFa: "سوم قرقیزستان" }, { code: "KHR", nameEn: "Cambodian Riel", nameFa: "ریال کامبوج" }, { code: "KMF", nameEn: "Comorian Franc", nameFa: "فرانک کومور" }, { code: "KPW", nameEn: "North Korean Won", nameFa: "وون کره شمالی" }, { code: "KRW", nameEn: "South Korean Won", nameFa: "وون کره جنوبی" }, { code: "KWD", nameEn: "Kuwaiti Dinar", nameFa: "دینار کویت" }, { code: "KYD", nameEn: "Cayman Islands Dollar", nameFa: "دلار جزایر کیمن" }, { code: "KZT", nameEn: "Kazakhstani Tenge", nameFa: "تنگه قزاقستان" }, { code: "LAK", nameEn: "Laotian Kip", nameFa: "کیپ لائوس" }, { code: "LBP", nameEn: "Lebanese Pound", nameFa: "پوند لبنان" }, { code: "LKR", nameEn: "Sri Lankan Rupee", nameFa: "روپیه سریلانکا" }, { code: "LRD", nameEn: "Liberian Dollar", nameFa: "دلار لیبریا" }, { code: "LSL", nameEn: "Lesotho Loti", nameFa: "لوتی لسوتو" }, { code: "LYD", nameEn: "Libyan Dinar", nameFa: "دینار لیبی" }, { code: "MAD", nameEn: "Moroccan Dirham", nameFa: "درهم مراکش" }, { code: "MDL", nameEn: "Moldovan Leu", nameFa: "لوی مولداوی" }, { code: "MGA", nameEn: "Malagasy Ariary", nameFa: "آریاری ماداگاسکار" }, { code: "MKD", nameEn: "Macedonian Denar", nameFa: "دینار مقدونیه" }, { code: "MMK", nameEn: "Myanmar Kyat", nameFa: "کیات میانمار" }, { code: "MNT", nameEn: "Mongolian Tugrik", nameFa: "توگریک مغولستان" }, { code: "MOP", nameEn: "Macanese Pataca", nameFa: "پاتاکای ماکائو" }, { code: "MRU", nameEn: "Mauritanian Ouguiya", nameFa: "اوگیای موریتانی" }, { code: "MUR", nameEn: "Mauritian Rupee", nameFa: "روپیه موریس" }, { code: "MVR", nameEn: "Maldivian Rufiyaa", nameFa: "روفیای مالدیو" }, { code: "MWK", nameEn: "Malawian Kwacha", nameFa: "کواچای مالاوی" }, { code: "MXN", nameEn: "Mexican Peso", nameFa: "پزو مکزیک" }, { code: "MYR", nameEn: "Malaysian Ringgit", nameFa: "رینگیت مالزی" }, { code: "MZN", nameEn: "Mozambican Metical", nameFa: "متیکال موزامبیک" }, { code: "NAD", nameEn: "Namibian Dollar", nameFa: "دلار نامیبیا" }, { code: "NGN", nameEn: "Nigerian Naira", nameFa: "نایرای نیجریه" }, { code: "NIO", nameEn: "Nicaraguan Córdoba", nameFa: "کوردوبای نیکاراگوئه" }, { code: "NOK", nameEn: "Norwegian Krone", nameFa: "کرون نروژ" }, { code: "NPR", nameEn: "Nepalese Rupee", nameFa: "روپیه نپال" }, { code: "NZD", nameEn: "New Zealand Dollar", nameFa: "دلار نیوزیلند" }, { code: "OMR", nameEn: "Omani Rial", nameFa: "ریال عمان" }, { code: "PAB", nameEn: "Panamanian Balboa", nameFa: "بالبوای پاناما" }, { code: "PEN", nameEn: "Peruvian Sol", nameFa: "سول پرو" }, { code: "PGK", nameEn: "Papua New Guinean Kina", nameFa: "کینای پاپوآ گینه نو", }, { code: "PHP", nameEn: "Philippine Peso", nameFa: "پزو فیلیپین" }, { code: "PKR", nameEn: "Pakistani Rupee", nameFa: "روپیه پاکستان" }, { code: "PLN", nameEn: "Polish Zloty", nameFa: "زلوتی لهستان" }, { code: "PYG", nameEn: "Paraguayan Guarani", nameFa: "گوارانی پاراگوئه" }, { code: "QAR", nameEn: "Qatari Rial", nameFa: "ریال قطر" }, { code: "RON", nameEn: "Romanian Leu", nameFa: "لوی رومانی" }, { code: "RSD", nameEn: "Serbian Dinar", nameFa: "دینار صربستان" }, { code: "RUB", nameEn: "Russian Ruble", nameFa: "روبل روسیه" }, { code: "RWF", nameEn: "Rwandan Franc", nameFa: "فرانک رواندا" }, { code: "SAR", nameEn: "Saudi Riyal", nameFa: "ریال عربستان" }, { code: "SBD", nameEn: "Solomon Islands Dollar", nameFa: "دلار جزایر سلیمان", }, { code: "SCR", nameEn: "Seychellois Rupee", nameFa: "روپیه سیشل" }, { code: "SDG", nameEn: "Sudanese Pound", nameFa: "پوند سودان" }, { code: "SEK", nameEn: "Swedish Krona", nameFa: "کرون سوئد" }, { code: "SGD", nameEn: "Singapore Dollar", nameFa: "دلار سنگاپور" }, { code: "SHP", nameEn: "St. Helena Pound", nameFa: "پوند سنت هلن" }, { code: "SLL", nameEn: "Sierra Leonean Leone", nameFa: "لئون سیرالئون" }, { code: "SOS", nameEn: "Somali Shilling", nameFa: "شیلینگ سومالی" }, { code: "SRD", nameEn: "Surinamese Dollar", nameFa: "دلار سورینام" }, { code: "SSP", nameEn: "South Sudanese Pound", nameFa: "پوند سودان جنوبی" }, { code: "STN", nameEn: "São Tomé Dobra", nameFa: "دوبرا سائوتومه" }, { code: "SVC", nameEn: "Salvadoran Colón", nameFa: "کولون السالوادور" }, { code: "SYP", nameEn: "Syrian Pound", nameFa: "پوند سوریه" }, { code: "SZL", nameEn: "Swazi Lilangeni", nameFa: "لیلانگنی سوازیلند" }, { code: "THB", nameEn: "Thai Baht", nameFa: "بات تایلند" }, { code: "TJS", nameEn: "Tajikistani Somoni", nameFa: "سامانی تاجیکستان" }, { code: "TMT", nameEn: "Turkmenistani Manat", nameFa: "منات ترکمنستان" }, { code: "TND", nameEn: "Tunisian Dinar", nameFa: "دینار تونس" }, { code: "TOMAN", nameEn: "Iranian Toman", nameFa: "تومان ایران" }, { code: "TOP", nameEn: "Tongan Paʻanga", nameFa: "پاآنگای تونگا" }, { code: "TRY", nameEn: "Turkish Lira", nameFa: "لیر ترکیه" }, { code: "TTD", nameEn: "Trinidad & Tobago Dollar", nameFa: "دلار ترینیداد و توباگر", }, { code: "TWD", nameEn: "New Taiwan Dollar", nameFa: "دلار جدید تایوان" }, { code: "TZS", nameEn: "Tanzanian Shilling", nameFa: "شیلینگ تانزانیا" }, { code: "UAH", nameEn: "Ukrainian Hryvnia", nameFa: "گریونا اوکراین" }, { code: "UGX", nameEn: "Ugandan Shilling", nameFa: "شیلینگ اوگاندا" }, { code: "USD", nameEn: "US Dollar", nameFa: "دلار آمریکا" }, { code: "UYU", nameEn: "Uruguayan Peso", nameFa: "پزو اروگوئه" }, { code: "UZS", nameEn: "Uzbekistani Som", nameFa: "سوم ازبکستان" }, { code: "VES", nameEn: "Venezuelan Bolívar", nameFa: "بولیوار ونزوئلا" }, { code: "VND", nameEn: "Vietnamese Dong", nameFa: "دانگ ویتنام" }, { code: "VUV", nameEn: "Vanuatu Vatu", nameFa: "واتو وانواتو" }, { code: "WST", nameEn: "Samoan Tālā", nameFa: "تالای ساموآ" }, { code: "XAF", nameEn: "Central African CFA Franc", nameFa: "فرانک سی‌اف‌آی آفریقای مرکزی", }, { code: "XCD", nameEn: "East Caribbean Dollar", nameFa: "دلار کارائیب شرقی" }, { code: "XOF", nameEn: "West African CFA Franc", nameFa: "فرانک سی‌اف‌آی آفریقای غربی", }, { code: "XPF", nameEn: "CFP Franc", nameFa: "فرانک اقیانوس آرام" }, { code: "YER", nameEn: "Yemeni Rial", nameFa: "ریال یمن" }, { code: "ZAR", nameEn: "South African Rand", nameFa: "راند آفریقای جنوبی" }, { code: "ZMW", nameEn: "Zambian Kwacha", nameFa: "کواچای زامبیا" }, { code: "ZWL", nameEn: "Zimbabwean Dollar", nameFa: "دلار زیمبابوه" }, ]; function formatNumberWithCommas( val: string | number | null | undefined, ): string { if (val === null || val === undefined || val === "") return ""; const cleanStr = String(val).replace(/,/g, ""); const parts = cleanStr.split("."); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); return parts.join("."); }