diff --git a/blue_modules/debounce.ts b/blue_modules/debounce.ts index 99742cec2..9e04dbe7b 100644 --- a/blue_modules/debounce.ts +++ b/blue_modules/debounce.ts @@ -1,7 +1,13 @@ // https://levelup.gitconnected.com/debounce-in-javascript-improve-your-applications-performance-5b01855e086 -const debounce = void>(func: T, wait: number) => { +// blue_modules/debounce.ts +type DebouncedFunction void> = { + (this: ThisParameterType, ...args: Parameters): void; + cancel(): void; +}; + +const debounce = void>(func: T, wait: number): DebouncedFunction => { let timeout: NodeJS.Timeout | null; - return function executedFunction(this: ThisParameterType, ...args: Parameters) { + const debouncedFunction = function (this: ThisParameterType, ...args: Parameters) { const later = () => { timeout = null; func.apply(this, args); @@ -11,6 +17,15 @@ const debounce = void>(func: T, wait: number) => } timeout = setTimeout(later, wait); }; + + debouncedFunction.cancel = () => { + if (timeout) { + clearTimeout(timeout); + } + timeout = null; + }; + + return debouncedFunction as DebouncedFunction; }; export default debounce; diff --git a/hooks/useDebounce.ts b/hooks/useDebounce.ts new file mode 100644 index 000000000..614649c87 --- /dev/null +++ b/hooks/useDebounce.ts @@ -0,0 +1,23 @@ +import { useState, useEffect } from 'react'; +import debounce from '../blue_modules/debounce'; + +const useDebounce = (value: T, delay: number): T => { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const handler = debounce((val: T) => { + setDebouncedValue(val); + }, delay); + + handler(value); + + + return () => { + handler.cancel(); + }; + }, [value, delay]); + + return debouncedValue; +}; + +export default useDebounce; diff --git a/models/fiatUnit.ts b/models/fiatUnit.ts index 5be4985db..aa0b03d2e 100644 --- a/models/fiatUnit.ts +++ b/models/fiatUnit.ts @@ -186,6 +186,7 @@ export type TFiatUnit = { endPointKey: string; symbol: string; locale: string; + country: string; source: 'CoinDesk' | 'Yadio' | 'Exir' | 'wazirx' | 'Bitstamp' | 'Kraken'; }; @@ -199,6 +200,7 @@ export type FiatUnitType = { endPointKey: string; symbol: string; locale: string; + country: string; source: keyof typeof FiatUnitSource; }; diff --git a/models/fiatUnits.json b/models/fiatUnits.json index 9c8ea7917..332035aa0 100644 --- a/models/fiatUnits.json +++ b/models/fiatUnits.json @@ -3,336 +3,392 @@ "endPointKey": "USD", "locale": "en-US", "source": "Kraken", - "symbol": "$" + "symbol": "$", + "country": "United States (US Dollar)" }, "AED": { "endPointKey": "AED", "locale": "ar-AE", "source": "CoinGecko", - "symbol": "د.إ." + "symbol": "د.إ.", + "country": "United Arab Emirates (UAE Dirham)" }, "ANG": { "endPointKey": "ANG", "locale": "en-SX", "source": "CoinDesk", - "symbol": "ƒ" + "symbol": "ƒ", + "country": "Sint Maarten (Netherlands Antillean Guilder)" }, "ARS": { "endPointKey": "ARS", "locale": "es-AR", "source": "Yadio", - "symbol": "$" + "symbol": "$", + "country": "Argentina (Argentine Peso)" }, "AUD": { "endPointKey": "AUD", "locale": "en-AU", "source": "CoinGecko", - "symbol": "$" + "symbol": "$", + "country": "Australia (Australian Dollar)" }, "AWG": { "endPointKey": "AWG", "locale": "nl-AW", "source": "CoinDesk", - "symbol": "ƒ" + "symbol": "ƒ", + "country": "Aruba (Aruban Florin)" }, "BHD": { "endPointKey": "BHD", "locale": "ar-BH", "source": "CoinGecko", - "symbol": "د.ب." + "symbol": "د.ب.", + "country": "Bahrain (Bahraini Dinar)" }, "BRL": { "endPointKey": "BRL", "locale": "pt-BR", "source": "CoinGecko", - "symbol": "R$" + "symbol": "R$", + "country": "Brazil (Brazilian Real)" }, "CAD": { "endPointKey": "CAD", "locale": "en-CA", "source": "CoinGecko", - "symbol": "$" + "symbol": "$", + "country": "Canada (Canadian Dollar)" }, "CHF": { "endPointKey": "CHF", "locale": "de-CH", "source": "CoinGecko", - "symbol": "CHF" + "symbol": "CHF", + "country": "Switzerland (Swiss Franc)" }, "CLP": { "endPointKey": "CLP", "locale": "es-CL", "source": "Yadio", - "symbol": "$" + "symbol": "$", + "country": "Chile (Chilean Peso)" }, "CNY": { "endPointKey": "CNY", "locale": "zh-CN", "source": "Coinbase", - "symbol": "¥" + "symbol": "¥", + "country": "China (Chinese Yuan)" }, "COP": { "endPointKey": "COP", "locale": "es-CO", "source": "CoinDesk", - "symbol": "$" + "symbol": "$", + "country": "Colombia (Colombian Peso)" }, "CZK": { "endPointKey": "CZK", "locale": "cs-CZ", "source": "CoinGecko", - "symbol": "Kč" + "symbol": "Kč", + "country": "Czech Republic (Czech Koruna)" }, "DKK": { "endPointKey": "DKK", "locale": "da-DK", "source": "CoinGecko", - "symbol": "kr" + "symbol": "kr", + "country": "Denmark (Danish Krone)" }, "EUR": { "endPointKey": "EUR", "locale": "en-IE", "source": "Kraken", - "symbol": "€" + "symbol": "€", + "country": "European Union (Euro)" }, "GBP": { "endPointKey": "GBP", "locale": "en-GB", "source": "Kraken", - "symbol": "£" + "symbol": "£", + "country": "United Kingdom (British Pound)" }, "HRK": { "endPointKey": "HRK", "locale": "hr-HR", "source": "CoinDesk", - "symbol": "HRK" + "symbol": "HRK", + "country": "Croatia (Croatian Kuna)" }, "HUF": { "endPointKey": "HUF", "locale": "hu-HU", "source": "CoinGecko", - "symbol": "Ft" + "symbol": "Ft", + "country": "Hungary (Hungarian Forint)" }, "IDR": { "endPointKey": "IDR", "locale": "id-ID", "source": "CoinGecko", - "symbol": "Rp" + "symbol": "Rp", + "country": "Indonesia (Indonesian Rupiah)" }, "ILS": { "endPointKey": "ILS", "locale": "he-IL", "source": "CoinGecko", - "symbol": "₪" + "symbol": "₪", + "country": "Israel (Israeli New Shekel)" }, "INR": { "endPointKey": "INR", - "locale": "hi-HN", + "locale": "hi-IN", "source": "wazirx", - "symbol": "₹" + "symbol": "₹", + "country": "India (Indian Rupee)" }, "IRR": { "endPointKey": "IRR", "locale": "fa-IR", "source": "Exir", - "symbol": "﷼" + "symbol": "﷼", + "country": "Iran (Iranian Rial)" }, "IRT": { "endPointKey": "IRT", "locale": "fa-IR", "source": "Exir", - "symbol": "تومان" + "symbol": "تومان", + "country": "Iran (Iranian Toman)" }, "ISK": { "endPointKey": "ISK", "locale": "is-IS", "source": "CoinDesk", - "symbol": "kr" + "symbol": "kr", + "country": "Iceland (Icelandic Króna)" }, "JPY": { "endPointKey": "JPY", "locale": "ja-JP", "source": "CoinGecko", - "symbol": "¥" + "symbol": "¥", + "country": "Japan (Japanese Yen)" }, "KES": { "endPointKey": "KES", "locale": "en-KE", "source": "CoinDesk", - "symbol": "Ksh" + "symbol": "Ksh", + "country": "Kenya (Kenyan Shilling)" }, "KRW": { "endPointKey": "KRW", "locale": "ko-KR", "source": "CoinGecko", - "symbol": "₩" + "symbol": "₩", + "country": "South Korea (South Korean Won)" }, "KWD": { "endPointKey": "KWD", "locale": "ar-KW", "source": "CoinGecko", - "symbol": "د.ك." + "symbol": "د.ك.", + "country": "Kuwait (Kuwaiti Dinar)" }, "LBP": { "endPointKey": "LBP", "locale": "ar-LB", "source": "YadioConvert", - "symbol": "ل.ل." + "symbol": "ل.ل.", + "country": "Lebanon (Lebanese Pound)" }, "LKR": { "endPointKey": "LKR", "locale": "si-LK", "source": "CoinGecko", - "symbol": "රු." + "symbol": "රු.", + "country": "Sri Lanka (Sri Lankan Rupee)" }, "MXN": { "endPointKey": "MXN", "locale": "es-MX", "source": "CoinGecko", - "symbol": "$" + "symbol": "$", + "country": "Mexico (Mexican Peso)" }, "MYR": { "endPointKey": "MYR", "locale": "ms-MY", "source": "CoinGecko", - "symbol": "RM" + "symbol": "RM", + "country": "Malaysia (Malaysian Ringgit)" }, "MZN": { "endPointKey": "MZN", "locale": "seh-MZ", "source": "CoinDesk", - "symbol": "MTn" + "symbol": "MTn", + "country": "Mozambique (Mozambican Metical)" }, "NGN": { "endPointKey": "NGN", "locale": "en-NG", "source": "CoinGecko", - "symbol": "₦" + "symbol": "₦", + "country": "Nigeria (Nigerian Naira)" }, "NOK": { "endPointKey": "NOK", "locale": "nb-NO", "source": "CoinGecko", - "symbol": "kr" + "symbol": "kr", + "country": "Norway (Norwegian Krone)" }, "NZD": { "endPointKey": "NZD", "locale": "en-NZ", "source": "CoinGecko", - "symbol": "$" + "symbol": "$", + "country": "New Zealand (New Zealand Dollar)" }, "OMR": { "endPointKey": "OMR", "locale": "ar-OM", "source": "CoinDesk", - "symbol": "ر.ع." + "symbol": "ر.ع.", + "country": "Oman (Omani Rial)" }, "PHP": { "endPointKey": "PHP", "locale": "en-PH", "source": "CoinGecko", - "symbol": "₱" + "symbol": "₱", + "country": "Philippines (Philippine Peso)" }, "PLN": { "endPointKey": "PLN", "locale": "pl-PL", "source": "CoinGecko", - "symbol": "zł" + "symbol": "zł", + "country": "Poland (Polish Zloty)" }, "QAR": { "endPointKey": "QAR", "locale": "ar-QA", "source": "CoinDesk", - "symbol": "ر.ق." + "symbol": "ر.ق.", + "country": "Qatar (Qatari Riyal)" }, "RON": { "endPointKey": "RON", "locale": "ro-RO", "source": "BNR", - "symbol": "lei" + "symbol": "lei", + "country": "Romania (Romanian Leu)" }, "RUB": { "endPointKey": "RUB", "locale": "ru-RU", "source": "CoinGecko", - "symbol": "₽" + "symbol": "₽", + "country": "Russia (Russian Ruble)" }, "SAR": { "endPointKey": "SAR", "locale": "ar-SA", "source": "CoinGecko", - "symbol": "ر.س." + "symbol": "ر.س.", + "country": "Saudi Arabia (Saudi Riyal)" }, "SEK": { "endPointKey": "SEK", "locale": "sv-SE", "source": "CoinGecko", - "symbol": "kr" + "symbol": "kr", + "country": "Sweden (Swedish Krona)" }, "SGD": { "endPointKey": "SGD", "locale": "zh-SG", "source": "CoinGecko", - "symbol": "S$" + "symbol": "S$", + "country": "Singapore (Singapore Dollar)" }, "THB": { "endPointKey": "THB", "locale": "th-TH", "source": "CoinGecko", - "symbol": "฿" + "symbol": "฿", + "country": "Thailand (Thai Baht)" }, "TRY": { "endPointKey": "TRY", "locale": "tr-TR", "source": "CoinGecko", - "symbol": "₺" + "symbol": "₺", + "country": "Turkey (Turkish Lira)" }, "TWD": { "endPointKey": "TWD", "locale": "zh-Hant-TW", "source": "CoinGecko", - "symbol": "NT$" + "symbol": "NT$", + "country": "Taiwan (New Taiwan Dollar)" }, "TZS": { "endPointKey": "TZS", "locale": "en-TZ", "source": "CoinDesk", - "symbol": "TSh" + "symbol": "TSh", + "country": "Tanzania (Tanzanian Shilling)" }, "UAH": { "endPointKey": "UAH", "locale": "uk-UA", "source": "CoinGecko", - "symbol": "₴" + "symbol": "₴", + "country": "Ukraine (Ukrainian Hryvnia)" }, "UGX": { "endPointKey": "UGX", "locale": "en-UG", "source": "CoinDesk", - "symbol": "USh" + "symbol": "USh", + "country": "Uganda (Ugandan Shilling)" }, "UYU": { "endPointKey": "UYU", "locale": "es-UY", "source": "CoinDesk", - "symbol": "$" + "symbol": "$", + "country": "Uruguay (Uruguayan Peso)" }, "VEF": { "endPointKey": "VEF", "locale": "es-VE", "source": "CoinGecko", - "symbol": "Bs." + "symbol": "Bs.", + "country": "Venezuela (Venezuelan Bolívar Fuerte)" }, "VES": { "endPointKey": "VES", "locale": "es-VE", "source": "Yadio", - "symbol": "Bs." + "symbol": "Bs.", + "country": "Venezuela (Venezuelan Bolívar Soberano)" }, "ZAR": { "endPointKey": "ZAR", "locale": "en-ZA", "source": "CoinGecko", - "symbol": "R" + "symbol": "R", + "country": "South Africa (South African Rand)" } } diff --git a/screen/settings/Currency.tsx b/screen/settings/Currency.tsx index 07bbdebe8..1461642ea 100644 --- a/screen/settings/Currency.tsx +++ b/screen/settings/Currency.tsx @@ -18,6 +18,7 @@ import { useTheme } from '../../components/themes'; import { useExtendedNavigation } from '../../hooks/useExtendedNavigation'; import loc from '../../loc'; import { FiatUnit, FiatUnitSource, FiatUnitType, getFiatRate } from '../../models/fiatUnit'; +import useDebounce from '../../hooks/useDebounce'; dayjs.extend(calendar); @@ -26,13 +27,20 @@ const Currency: React.FC = () => { const [isSavingNewPreferredCurrency, setIsSavingNewPreferredCurrency] = useState(false); const [selectedCurrency, setSelectedCurrency] = useState(FiatUnit.USD); const [currencyRate, setCurrencyRate] = useState({ LastUpdated: null, Rate: null }); + const [isSearchFocused, setIsSearchFocused] = useState(false); const { colors } = useTheme(); const { setOptions } = useExtendedNavigation(); const [search, setSearch] = useState(''); + const debouncedSearch = useDebounce(search, 300); const data = useMemo( - () => Object.values(FiatUnit).filter(item => item.endPointKey.toLowerCase().includes(search.toLowerCase())), - [search], + () => + Object.values(FiatUnit).filter( + item => + item.endPointKey.toLowerCase().includes(debouncedSearch.toLowerCase()) || + item.country.toLowerCase().includes(debouncedSearch.toLowerCase()), + ), + [debouncedSearch], ); const stylesHook = StyleSheet.create({ @@ -64,6 +72,8 @@ const Currency: React.FC = () => { setOptions({ headerSearchBarOptions: { onChangeText: (event: NativeSyntheticEvent<{ text: string }>) => setSearch(event.nativeEvent.text), + onFocus: () => setIsSearchFocused(true), + onBlur: () => setIsSearchFocused(false), }, }); }, [setOptions]); @@ -74,6 +84,7 @@ const Currency: React.FC = () => { title={`${item.endPointKey} (${item.symbol})`} containerStyle={StyleSheet.flatten([styles.flex, stylesHook.flex, { minHeight: 60 }])} checkmark={selectedCurrency.endPointKey === item.endPointKey} + subtitle={item.country} onPress={async () => { setIsSavingNewPreferredCurrency(true); try { @@ -86,7 +97,7 @@ const Currency: React.FC = () => { } catch (error: any) { console.log(error); presentAlert({ - message: error.message ? `${loc.settings.currency_fetch_error}: ${error.message}}` : loc.settings.currency_fetch_error, + message: error.message ? `${loc.settings.currency_fetch_error}: ${error.message}` : loc.settings.currency_fetch_error, }); } finally { setIsSavingNewPreferredCurrency(false); @@ -95,6 +106,11 @@ const Currency: React.FC = () => { /> ); + const selectedCurrencyVisible = useMemo( + () => data.some(item => item.endPointKey === selectedCurrency.endPointKey), + [data, selectedCurrency], + ); + return ( { initialNumToRender={30} renderItem={renderItem} /> - - - {loc.settings.currency_source} {selectedCurrency?.source ?? FiatUnitSource.CoinDesk} - - - - {loc.settings.rate}: {currencyRate.Rate ?? loc._.never} - - - - {loc.settings.last_updated}: {dayjs(currencyRate.LastUpdated).calendar() ?? loc._.never} - - + {!isSearchFocused || selectedCurrencyVisible ? ( + + + {loc.settings.currency_source} {selectedCurrency?.source ?? FiatUnitSource.CoinDesk} + + + + {loc.settings.rate}: {currencyRate.Rate ?? loc._.never} + + + + {loc.settings.last_updated}: {dayjs(currencyRate.LastUpdated).calendar() ?? loc._.never} + + + ) : null} ); };