diff --git a/src/components/Componentes/currency-sheet.test.tsx b/src/components/Componentes/currency-sheet.test.tsx new file mode 100644 index 0000000..705489a --- /dev/null +++ b/src/components/Componentes/currency-sheet.test.tsx @@ -0,0 +1,68 @@ +import { render, screen, fireEvent, cleanup } from "@testing-library/react"; +import { describe, expect, it, vi, afterEach } from "vitest"; +import { CurrencySheet } from "./currency-sheet"; + +describe("CurrencySheet", () => { + afterEach(() => { + cleanup(); + }); + + it("should render currency sheet when isOpen is true", () => { + const handleClose = vi.fn(); + const handleSelect = vi.fn(); + + render( + , + ); + + expect(screen.getByText("انتخاب ارز")).toBeDefined(); + expect(screen.getByText("TOMAN")).toBeDefined(); + expect(screen.getAllByText("USD").length).toBeGreaterThan(0); + }); + + it("should filter currencies when typing in search input", () => { + const handleClose = vi.fn(); + const handleSelect = vi.fn(); + + render( + , + ); + + const searchInput = screen.getByPlaceholderText("Search currency or country..."); + fireEvent.change(searchInput, { target: { value: "EUR" } }); + + expect(screen.getByText("EUR")).toBeDefined(); + expect(screen.queryByText("TOMAN")).toBeNull(); + }); + + it("should call onSelectCurrency when a currency item is clicked", () => { + const handleClose = vi.fn(); + const handleSelect = vi.fn(); + + render( + , + ); + + const eurButton = screen.getByText("Euro").closest("button"); + expect(eurButton).not.toBeNull(); + fireEvent.click(eurButton!); + + expect(handleSelect).toHaveBeenCalledWith("EUR"); + }); +}); diff --git a/src/components/Componentes/currency-sheet.tsx b/src/components/Componentes/currency-sheet.tsx new file mode 100644 index 0000000..0815350 --- /dev/null +++ b/src/components/Componentes/currency-sheet.tsx @@ -0,0 +1,274 @@ +"use client"; + +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { createPortal } from "react-dom"; +import { CURRENCIES, type CurrencyItem } from "@/data/currencies"; +import { useI18n } from "@/translations/provider"; +import { useSheetScrollLock } from "./use-sheet-scroll-lock"; + +const EXIT_ANIMATION_MS = 300; + +export type CurrencySheetProps = { + isOpen: boolean; + onClose: () => void; + selectedCurrency: string; + onSelectCurrency: (code: string) => void; + title?: string; +}; + +export function CurrencySheet({ + isOpen, + onClose, + selectedCurrency, + onSelectCurrency, + title, +}: CurrencySheetProps) { + const { dictionary: t, locale } = useI18n(); + const [isClosing, setIsClosing] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); + const listRef = useRef(null); + const sheetRef = useRef(null); + + const isRtl = locale === "fa" || locale === "ar" || locale === "ur"; + const defaultTitle = isRtl ? "انتخاب ارز" : "Select Currency"; + const sheetTitle = title || defaultTitle; + + const closeSheet = useCallback(() => { + setIsClosing(true); + window.setTimeout(() => { + onClose(); + setIsClosing(false); + setSearchQuery(""); + }, EXIT_ANIMATION_MS); + }, [onClose]); + + useSheetScrollLock(isOpen && !isClosing, { onBack: closeSheet }); + + // Escape key handler + useEffect(() => { + if (!isOpen) return; + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") { + closeSheet(); + } + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [isOpen, closeSheet]); + + const filteredCurrencies = useMemo(() => { + const q = searchQuery.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) || + (c.symbol && c.symbol.toLowerCase().includes(q)), + ); + }, [searchQuery]); + + const handleSelect = (code: string) => { + onSelectCurrency(code); + closeSheet(); + }; + + const searchPlaceholder = + locale === "fa" + ? "جستجوی ارز یا کشور..." + : locale === "ar" + ? "بحث عن العملة..." + : "Search currency or country..."; + + const noResultsText = + locale === "fa" + ? "ارزی یافت نشد" + : locale === "ar" + ? "لم يتم العثور على عملات" + : "No currencies found"; + + if (!isOpen && !isClosing) return null; + + return createPortal( +
{ + if (e.key === "Escape") closeSheet(); + }} + onClick={(event) => { + if (event.target === event.currentTarget) closeSheet(); + }} + > +
+ {/* Header */} +
+

+ {sheetTitle} +

+ +
+ + {/* Search Bar */} +
+
+ + setSearchQuery(e.target.value)} + placeholder={searchPlaceholder} + className="flex-1 bg-transparent text-[14px] font-medium text-[#181818] outline-none placeholder:text-[#98A2B3]" + /> + {searchQuery ? ( + + ) : null} +
+
+ + {/* Currencies List */} +
event.stopPropagation()} + onTouchMove={(event) => event.stopPropagation()} + onTouchEnd={(event) => event.stopPropagation()} + className="flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto overscroll-contain px-5 py-3" + > + {filteredCurrencies.length > 0 ? ( + filteredCurrencies.map((item: CurrencyItem) => { + const isSelected = item.code === selectedCurrency; + const displayName = + locale === "fa" || locale === "fa-ir" + ? item.nameFa + : item.nameEn; + + return ( + + ); + }) + ) : ( +
+ {noResultsText} +
+ )} +
+
+
, + document.body, + ); +} + +export default CurrencySheet; diff --git a/src/components/Componentes/question-number.tsx b/src/components/Componentes/question-number.tsx index 86e7b0a..5baf1bf 100644 --- a/src/components/Componentes/question-number.tsx +++ b/src/components/Componentes/question-number.tsx @@ -1,12 +1,15 @@ "use client"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import type { QuestionField } from "@/lib/schema-adapter"; import { useI18n } from "@/translations/provider"; import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; import { Input } from "@/components/ui/input"; import { isKnownCountry } from "@/data/countries"; +import { resolveDefaultCurrency } from "@/data/currencies"; +import { getStoredUserGeoRegion } from "@/lib/geo-region"; +import { CurrencySheet } from "./currency-sheet"; type QuestionNumberProps = { question: QuestionField; @@ -78,7 +81,8 @@ export default function QuestionNumber({ : ""; const isMonthlyIncome = question.ui_config?.currency_enabled === true; - const currencyStorageKey = question.ui_config?.currency_storage_key || "marriage:income:currency"; + const currencyStorageKey = + question.ui_config?.currency_storage_key || "marriage:income:currency"; const countryName = useMemo(() => getCountryFromStorage(), []); @@ -87,13 +91,15 @@ export default function QuestionNumber({ const stored = window.localStorage.getItem(currencyStorageKey); if (stored) return stored; } - return getCurrencyForCountry(countryName); + const geo = getStoredUserGeoRegion(); + return resolveDefaultCurrency({ + countryCode: geo?.countryCode, + countryName: countryName || geo?.country, + fallbackLocale: locale, + }); }); - const [isCurrencyDropdownOpen, setIsCurrencyDropdownOpen] = useState(false); - const [currencySearchQuery, setCurrencySearchQuery] = useState(""); - const currencyContainerRef = useRef(null); - const currencySearchInputRef = useRef(null); + const [isCurrencySheetOpen, setIsCurrencySheetOpen] = useState(false); useEffect(() => { if (typeof window !== "undefined") { @@ -103,47 +109,18 @@ export default function QuestionNumber({ return; } } - const derived = getCurrencyForCountry(countryName); + const geo = getStoredUserGeoRegion(); + const derived = resolveDefaultCurrency({ + countryCode: geo?.countryCode, + countryName: countryName || geo?.country, + fallbackLocale: locale, + }); 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]); + }, [countryName, currencyStorageKey, locale]); const placeholderCurrency = useMemo(() => { if (currencyCode === "TOMAN") { - return locale === "fa" ? "تومان" : "TOMAN"; + return locale === "fa" || locale === "fa-ir" ? "تومان" : "TOMAN"; } return currencyCode; }, [currencyCode, locale]); @@ -152,7 +129,7 @@ export default function QuestionNumber({ if (!isMonthlyIncome) { return question.extras.placeHolder; } - return locale === "fa" + return locale === "fa" || locale === "fa-ir" ? `مثال: ۴۰۰۰ ${placeholderCurrency}` : `e.g. 4000 ${placeholderCurrency}`; }, [ @@ -186,7 +163,7 @@ export default function QuestionNumber({ ].join(" ")} > -
+
setIsCurrencyDropdownOpen(!isCurrencyDropdownOpen)} + onClick={() => setIsCurrencySheetOpen(true)} className={[ "flex h-[54px] w-full items-center justify-between rounded-[16px] border bg-white px-3.5 text-start transition-all cursor-pointer outline-none", - isCurrencyDropdownOpen + isCurrencySheetOpen ? "border-[#6F6F6F] ring-1 ring-[#6F6F6F]" : "border-[#D0D5DD] hover:border-[#98A2B3]", ].join(" ")} @@ -253,7 +231,7 @@ export default function QuestionNumber({ aria-label="Dropdown chevron" className={[ "shrink-0 transition-transform duration-200 text-[#344054] ml-1", - isCurrencyDropdownOpen ? "rotate-180" : "", + isCurrencySheetOpen ? "rotate-180" : "", ].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"} - - )} -
-
- )}
+ + setIsCurrencySheetOpen(false)} + selectedCurrency={currencyCode} + onSelectCurrency={(code) => { + setCurrencyCode(code); + if (typeof window !== "undefined") { + window.localStorage.setItem(currencyStorageKey, code); + } + }} + /> + {isOutOfRange ? ( {t[ @@ -408,7 +297,8 @@ export default function QuestionNumber({ } else { const parsed = parseFloat(nextValue); setAnswerValue( - question, Number.isNaN(parsed) ? nextValue : parsed, + question, + Number.isNaN(parsed) ? nextValue : parsed, ); } }} @@ -487,252 +377,9 @@ function getCountryFromStorage(): string { 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("."); +function formatNumberWithCommas(val: string): string { + if (!val) return ""; + const parts = val.split("."); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); return parts.join("."); } diff --git a/src/data/currencies.test.ts b/src/data/currencies.test.ts new file mode 100644 index 0000000..c0db105 --- /dev/null +++ b/src/data/currencies.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, it } from "vitest"; +import { + COUNTRY_CODE_TO_CURRENCY, + resolveDefaultCurrency, + CURRENCIES, +} from "./currencies"; + +describe("currencies", () => { + it("should map country code IR to TOMAN", () => { + expect(COUNTRY_CODE_TO_CURRENCY["IR"]).toBe("TOMAN"); + expect(resolveDefaultCurrency({ countryCode: "IR" })).toBe("TOMAN"); + expect(resolveDefaultCurrency({ countryCode: "ir" })).toBe("TOMAN"); + }); + + it("should map country codes correctly for other countries", () => { + expect(resolveDefaultCurrency({ countryCode: "US" })).toBe("USD"); + expect(resolveDefaultCurrency({ countryCode: "GB" })).toBe("GBP"); + expect(resolveDefaultCurrency({ countryCode: "DE" })).toBe("EUR"); + expect(resolveDefaultCurrency({ countryCode: "AE" })).toBe("AED"); + expect(resolveDefaultCurrency({ countryCode: "TR" })).toBe("TRY"); + expect(resolveDefaultCurrency({ countryCode: "IQ" })).toBe("IQD"); + expect(resolveDefaultCurrency({ countryCode: "AF" })).toBe("AFN"); + expect(resolveDefaultCurrency({ countryCode: "CA" })).toBe("CAD"); + expect(resolveDefaultCurrency({ countryCode: "TJ" })).toBe("TJS"); + }); + + it("should map country names in English and Persian correctly", () => { + expect(resolveDefaultCurrency({ countryName: "Iran" })).toBe("TOMAN"); + expect(resolveDefaultCurrency({ countryName: "ایران" })).toBe("TOMAN"); + expect(resolveDefaultCurrency({ countryName: "Iraq" })).toBe("IQD"); + expect(resolveDefaultCurrency({ countryName: "عراق" })).toBe("IQD"); + expect(resolveDefaultCurrency({ countryName: "Turkey" })).toBe("TRY"); + expect(resolveDefaultCurrency({ countryName: "ترکیه" })).toBe("TRY"); + expect(resolveDefaultCurrency({ countryName: "United Arab Emirates" })).toBe("AED"); + expect(resolveDefaultCurrency({ countryName: "امارات" })).toBe("AED"); + }); + + it("should fallback to TOMAN for Persian locale if no country is detected", () => { + expect(resolveDefaultCurrency({ fallbackLocale: "fa" })).toBe("TOMAN"); + expect(resolveDefaultCurrency({ fallbackLocale: "fa-ir" })).toBe("TOMAN"); + }); + + it("should fallback to USD for other locales if no country is detected", () => { + expect(resolveDefaultCurrency({ fallbackLocale: "en" })).toBe("USD"); + expect(resolveDefaultCurrency({})).toBe("USD"); + }); + + it("should have valid currency items in CURRENCIES list", () => { + expect(CURRENCIES.length).toBeGreaterThan(50); + const toman = CURRENCIES.find((c) => c.code === "TOMAN"); + expect(toman).toBeDefined(); + expect(toman?.nameFa).toBe("تومان ایران"); + + const usd = CURRENCIES.find((c) => c.code === "USD"); + expect(usd).toBeDefined(); + expect(usd?.nameEn).toBe("US Dollar"); + }); +}); diff --git a/src/data/currencies.ts b/src/data/currencies.ts new file mode 100644 index 0000000..e0c5298 --- /dev/null +++ b/src/data/currencies.ts @@ -0,0 +1,381 @@ +export type CurrencyItem = { + code: string; + nameEn: string; + nameFa: string; + symbol?: string; +}; + +export const COUNTRY_CODE_TO_CURRENCY: Record = { + IR: "TOMAN", + US: "USD", + GB: "GBP", + UK: "GBP", + DE: "EUR", + FR: "EUR", + IT: "EUR", + ES: "EUR", + NL: "EUR", + BE: "EUR", + AT: "EUR", + PT: "EUR", + GR: "EUR", + FI: "EUR", + IE: "EUR", + SK: "EUR", + SI: "EUR", + LT: "EUR", + LV: "EUR", + EE: "EUR", + CY: "EUR", + MT: "EUR", + LU: "EUR", + MC: "EUR", + SM: "EUR", + VA: "EUR", + AD: "EUR", + ME: "EUR", + XK: "EUR", + AE: "AED", + TR: "TRY", + IQ: "IQD", + AF: "AFN", + PK: "PKR", + SA: "SAR", + QA: "QAR", + KW: "KWD", + OM: "OMR", + BH: "BHD", + CA: "CAD", + AU: "AUD", + SE: "SEK", + NO: "NOK", + DK: "DKK", + CH: "CHF", + RU: "RUB", + CN: "CNY", + JP: "JPY", + KR: "KRW", + IN: "INR", + MY: "MYR", + ID: "IDR", + TH: "THB", + SG: "SGD", + NZ: "NZD", + ZA: "ZAR", + BR: "BRL", + MX: "MXN", + AR: "ARS", + AZ: "AZN", + TJ: "TJS", + UZ: "UZS", + TM: "TMT", + KZ: "KZT", + KG: "KGS", + GE: "GEL", + AM: "AMD", + LB: "LBP", + SY: "SYP", + JO: "JOD", + EG: "EGP", + YE: "YER", + MA: "MAD", + DZ: "DZD", + TN: "TND", + LY: "LYD", + SD: "SDG", + BD: "BDT", + LK: "LKR", + NP: "NPR", + PH: "PHP", + VN: "VND", + PL: "PLN", + CZ: "CZK", + HU: "HUF", + RO: "RON", + BG: "BGN", + HR: "EUR", + RS: "RSD", + BA: "BAM", + AL: "ALL", + MD: "MDL", + UA: "UAH", + BY: "BYN", + IS: "ISK", + CL: "CLP", + CO: "COP", + PE: "PEN", + VE: "VES", + EC: "USD", + PA: "USD", + CR: "CRC", + DO: "DOP", + GT: "GTQ", + NG: "NGN", + KES: "KES", + GH: "GHS", + ET: "ETB", + TZ: "TZS", + UG: "UGX", +}; + +export const COUNTRY_NAME_TO_CURRENCY: Record = { + // English + Iran: "TOMAN", + "United States": "USD", + "United States of America": "USD", + USA: "USD", + "United Kingdom": "GBP", + UK: "GBP", + Britain: "GBP", + Canada: "CAD", + Germany: "EUR", + France: "EUR", + Italy: "EUR", + Spain: "EUR", + Netherlands: "EUR", + Belgium: "EUR", + Austria: "EUR", + Portugal: "EUR", + Greece: "EUR", + Finland: "EUR", + Ireland: "EUR", + "United Arab Emirates": "AED", + UAE: "AED", + Turkey: "TRY", + Iraq: "IQD", + Afghanistan: "AFN", + Pakistan: "PKR", + "Saudi Arabia": "SAR", + Qatar: "QAR", + Kuwait: "KWD", + Oman: "OMR", + Bahrain: "BHD", + Sweden: "SEK", + Norway: "NOK", + Denmark: "DKK", + Switzerland: "CHF", + Australia: "AUD", + "New Zealand": "NZD", + Russia: "RUB", + China: "CNY", + Japan: "JPY", + "South Korea": "KRW", + India: "INR", + Malaysia: "MYR", + Indonesia: "IDR", + Singapore: "SGD", + Thailand: "THB", + Tajikistan: "TJS", + Azerbaijan: "AZN", + Uzbekistan: "UZS", + Turkmenistan: "TMT", + Kazakhstan: "KZT", + Kyrgyzstan: "KGS", + Georgia: "GEL", + Armenia: "AMD", + Lebanon: "LBP", + Syria: "SYP", + Jordan: "JOD", + Egypt: "EGP", + Yemen: "YER", + Morocco: "MAD", + Algeria: "DZD", + Tunisia: "TND", + Libya: "LYD", + Sudan: "SDG", + Brazil: "BRL", + Mexico: "MXN", + Argentina: "ARS", + Bulgaria: "BGN", + Poland: "PLN", + "Czech Republic": "CZK", + Hungary: "HUF", + Romania: "RON", + Serbia: "RSD", + Ukraine: "UAH", + Belarus: "BYN", + + // Persian + ایران: "TOMAN", + "ایالات متحده": "USD", + "ایالات متحده آمریکا": "USD", + آمریکا: "USD", + بریتانیا: "GBP", + انگلیس: "GBP", + کانادا: "CAD", + آلمان: "EUR", + فرانسه: "EUR", + ایتالیا: "EUR", + اسپانیا: "EUR", + هلند: "EUR", + بلژیک: "EUR", + اتریش: "EUR", + پرتغال: "EUR", + یونان: "EUR", + فنلاند: "EUR", + ایرلند: "EUR", + "امارات متحده عربی": "AED", + امارات: "AED", + ترکیه: "TRY", + عراق: "IQD", + افغانستان: "AFN", + پاکستان: "PKR", + "عربستان سعودی": "SAR", + عربستان: "SAR", + قطر: "QAR", + کویت: "KWD", + عمان: "OMR", + بحرین: "BHD", + سوئد: "SEK", + نروژ: "NOK", + دانمارک: "DKK", + سوئیس: "CHF", + استرالیا: "AUD", + نیوزیلند: "NZD", + روسیه: "RUB", + چین: "CNY", + ژاپن: "JPY", + "کره جنوبی": "KRW", + هند: "INR", + مالزی: "MYR", + اندونزی: "IDR", + سنگاپور: "SGD", + تایلند: "THB", + تاجیکستان: "TJS", + آذربایجان: "AZN", + ازبکستان: "UZS", + ترکمنستان: "TMT", + قزاقستان: "KZT", + قرقیزستان: "KGS", + گرجستان: "GEL", + ارمنستان: "AMD", + لبنان: "LBP", + سوریه: "SYP", + اردن: "JOD", + مصر: "EGP", + یمن: "YER", + مراکش: "MAD", + الجزایر: "DZD", + تونس: "TND", + لیبی: "LYD", + سودان: "SDG", + برزیل: "BRL", + مکزیک: "MXN", + آرژانتین: "ARS", + بلغارستان: "BGN", + لهستان: "PLN", + چک: "CZK", + مجارستان: "HUF", + رومانی: "RON", + صربستان: "RSD", + اوکراین: "UAH", + بلاروس: "BYN", +}; + +export const CURRENCIES: CurrencyItem[] = [ + { code: "TOMAN", nameEn: "Iranian Toman", nameFa: "تومان ایران", symbol: "تومان" }, + { code: "USD", nameEn: "US Dollar", nameFa: "دلار آمریکا", symbol: "$" }, + { code: "EUR", nameEn: "Euro", nameFa: "یورو", symbol: "€" }, + { code: "AED", nameEn: "UAE Dirham", nameFa: "درهم امارات", symbol: "د.إ" }, + { code: "TRY", nameEn: "Turkish Lira", nameFa: "لیر ترکیه", symbol: "₺" }, + { code: "GBP", nameEn: "British Pound", nameFa: "پوند بریتانیا", symbol: "£" }, + { code: "CAD", nameEn: "Canadian Dollar", nameFa: "دلار کانادا", symbol: "CA$" }, + { code: "AUD", nameEn: "Australian Dollar", nameFa: "دلار استرالیا", symbol: "AU$" }, + { code: "IQD", nameEn: "Iraqi Dinar", nameFa: "دینار عراق", symbol: "ع.د" }, + { code: "SAR", nameEn: "Saudi Riyal", nameFa: "ریال سعودی", symbol: "﷼" }, + { code: "QAR", nameEn: "Qatari Riyal", nameFa: "ریال قطر", symbol: "ر.ق" }, + { code: "KWD", nameEn: "Kuwaiti Dinar", nameFa: "دینار کویت", symbol: "د.ك" }, + { code: "OMR", nameEn: "Omani Rial", nameFa: "ریال عمان", symbol: "ر.ع." }, + { code: "BHD", nameEn: "Bahraini Dinar", nameFa: "دینار بحرین", symbol: ".د.ب" }, + { code: "AFN", nameEn: "Afghan Afghani", nameFa: "افغانی افغانستان", symbol: "؋" }, + { code: "PKR", nameEn: "Pakistani Rupee", nameFa: "روپیه پاکستان", symbol: "₨" }, + { code: "TJS", nameEn: "Tajikistani Somoni", nameFa: "سامانی تاجیکستان", symbol: "смн" }, + { code: "AZN", nameEn: "Azerbaijani Manat", nameFa: "منات آذربایجان", symbol: "₼" }, + { code: "RUB", nameEn: "Russian Ruble", nameFa: "روبل روسیه", symbol: "₽" }, + { code: "CNY", nameEn: "Chinese Yuan", nameFa: "یوان چین", symbol: "¥" }, + { code: "JPY", nameEn: "Japanese Yen", nameFa: "ین ژاپن", symbol: "¥" }, + { code: "CHF", nameEn: "Swiss Franc", nameFa: "فرانک سوئیس", symbol: "CHF" }, + { code: "SEK", nameEn: "Swedish Krona", nameFa: "کرون سوئد", symbol: "kr" }, + { code: "NOK", nameEn: "Norwegian Krone", nameFa: "کرون نروژ", symbol: "kr" }, + { code: "DKK", nameEn: "Danish Krone", nameFa: "کرون دانمارک", symbol: "kr" }, + { code: "INR", nameEn: "Indian Rupee", nameFa: "روپیه هند", symbol: "₹" }, + { code: "MYR", nameEn: "Malaysian Ringgit", nameFa: "رینگیت مالزی", symbol: "RM" }, + { code: "SGD", nameEn: "Singapore Dollar", nameFa: "دلار سنگاپور", symbol: "S$" }, + { code: "NZD", nameEn: "New Zealand Dollar", nameFa: "دلار نیوزیلند", symbol: "NZ$" }, + { code: "BRL", nameEn: "Brazilian Real", nameFa: "رئال برزیل", symbol: "R$" }, + { code: "MXN", nameEn: "Mexican Peso", nameFa: "پزو مکزیک", symbol: "Mex$" }, + { code: "ARS", nameEn: "Argentine Peso", nameFa: "پزو آرژانتین", symbol: "ARS$" }, + { code: "EGP", nameEn: "Egyptian Pound", nameFa: "پوند مصر", symbol: "E£" }, + { code: "ZAR", nameEn: "South African Rand", nameFa: "راند آفریقای جنوبی", symbol: "R" }, + { code: "IDR", nameEn: "Indonesian Rupiah", nameFa: "روپیه اندونزی", symbol: "Rp" }, + { code: "THB", nameEn: "Thai Baht", nameFa: "بات تایلند", symbol: "฿" }, + { code: "KRW", nameEn: "South Korean Won", nameFa: "وون کره جنوبی", symbol: "₩" }, + { code: "UZS", nameEn: "Uzbekistani Som", nameFa: "سوم ازبکستان", symbol: "so'm" }, + { code: "TMT", nameEn: "Turkmenistani Manat", nameFa: "منات ترکمنستان", symbol: "TMT" }, + { code: "KZT", nameEn: "Kazakhstani Tenge", nameFa: "تنگه قزاقستان", symbol: "₸" }, + { code: "KGS", nameEn: "Kyrgystani Som", nameFa: "سوم قرقیزستان", symbol: "сом" }, + { code: "GEL", nameEn: "Georgian Lari", nameFa: "لاری گرجستان", symbol: "₾" }, + { code: "AMD", nameEn: "Armenian Dram", nameFa: "درام ارمنستان", symbol: "֏" }, + { code: "LBP", nameEn: "Lebanese Pound", nameFa: "لیره لبنان", symbol: "ل.ل" }, + { code: "SYP", nameEn: "Syrian Pound", nameFa: "لیره سوریه", symbol: "ل.س" }, + { code: "JOD", nameEn: "Jordanian Dinar", nameFa: "دینار اردن", symbol: "د.ا" }, + { code: "YER", nameEn: "Yemeni Rial", nameFa: "ریال یمن", symbol: "﷼" }, + { code: "MAD", nameEn: "Moroccan Dirham", nameFa: "درهم مراکش", symbol: "د.م." }, + { code: "DZD", nameEn: "Algerian Dinar", nameFa: "دینار الجزایر", symbol: "د.ج" }, + { code: "TND", nameEn: "Tunisian Dinar", nameFa: "دینار تونس", symbol: "د.ت" }, + { code: "LYD", nameEn: "Libyan Dinar", nameFa: "دینار لیبی", symbol: "ل.د" }, + { code: "SDG", nameEn: "Sudanese Pound", nameFa: "پوند سودان", symbol: "ج.س." }, + { code: "BDT", nameEn: "Bangladeshi Taka", nameFa: "تاکای بنگلادش", symbol: "৳" }, + { code: "BGN", nameEn: "Bulgarian Lev", nameFa: "لو بلغارستان", symbol: "лв" }, + { code: "PLN", nameEn: "Polish Zloty", nameFa: "زلوتی لهستان", symbol: "zł" }, + { code: "CZK", nameEn: "Czech Koruna", nameFa: "کرون چک", symbol: "Kč" }, + { code: "HUF", nameEn: "Hungarian Forint", nameFa: "فورینت مجارستان", symbol: "Ft" }, + { code: "RON", nameEn: "Romanian Leu", nameFa: "لئو رومانی", symbol: "lei" }, + { code: "RSD", nameEn: "Serbian Dinar", nameFa: "دینار صربستان", symbol: "дин." }, + { code: "BAM", nameEn: "Bosnia Mark", nameFa: "مارک بوسنی", symbol: "KM" }, + { code: "ALL", nameEn: "Albanian Lek", nameFa: "لک آلبانی", symbol: "Lek" }, + { code: "UAH", nameEn: "Ukrainian Hryvnia", nameFa: "گریونا اوکراین", symbol: "₴" }, + { code: "BYN", nameEn: "Belarusian Ruble", nameFa: "روبل بلاروس", symbol: "Br" }, + { code: "ISK", nameEn: "Icelandic Króna", nameFa: "کرون ایسلند", symbol: "kr" }, + { code: "CLP", nameEn: "Chilean Peso", nameFa: "پزو شیلی", symbol: "CLP$" }, + { code: "COP", nameEn: "Colombian Peso", nameFa: "پزو کلمبیا", symbol: "COL$" }, + { code: "PEN", nameEn: "Peruvian Sol", nameFa: "سول پرو", symbol: "S/." }, + { code: "CRC", nameEn: "Costa Rican Colón", nameFa: "کولون کاستاریکا", symbol: "₡" }, + { code: "DOP", nameEn: "Dominican Peso", nameFa: "پزو دومینیکن", symbol: "RD$" }, + { code: "GTQ", nameEn: "Guatemalan Quetzal", nameFa: "کوتزال گواتمالا", symbol: "Q" }, + { code: "NGN", nameEn: "Nigerian Naira", nameFa: "نایرا نیجریه", symbol: "₦" }, + { code: "KES", nameEn: "Kenyan Shilling", nameFa: "شیلینگ کنیا", symbol: "KSh" }, + { code: "GHS", nameEn: "Ghanaian Cedi", nameFa: "سدی غنا", symbol: "GH₵" }, + { code: "ETB", nameEn: "Ethiopian Birr", nameFa: "بیر اتیوپی", symbol: "Br" }, + { code: "IRR", nameEn: "Iranian Rial", nameFa: "ریال ایران", symbol: "﷼" }, +]; + +export function resolveDefaultCurrency({ + countryCode, + countryName, + fallbackLocale, +}: { + countryCode?: string | null; + countryName?: string | null; + fallbackLocale?: string | null; +}): string { + if (countryCode && typeof countryCode === "string") { + const cleanCode = countryCode.trim().toUpperCase(); + if (COUNTRY_CODE_TO_CURRENCY[cleanCode]) { + return COUNTRY_CODE_TO_CURRENCY[cleanCode]; + } + } + + if (countryName && typeof countryName === "string") { + const cleanName = countryName.trim(); + if (COUNTRY_NAME_TO_CURRENCY[cleanName]) { + return COUNTRY_NAME_TO_CURRENCY[cleanName]; + } + } + + if (fallbackLocale === "fa" || fallbackLocale === "fa-ir") { + return "TOMAN"; + } + + return "USD"; +}