UNPKG

bigblocks

Version:

Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React

17 lines 6.41 kB
{ "name": "wallet-utils-currency", "type": "registry:component", "dependencies": [ "satoshi-token" ], "devDependencies": [], "registryDependencies": [], "files": [ { "path": "components/wallet/utils/currency.ts", "type": "registry:component", "content": "// Currency Utilities - Format amounts, convert between currencies\nimport { toBitcoin, toToken, toTokenSat } from \"satoshi-token\";\n\nexport type Currency = \"BSV\" | \"USD\" | \"EUR\" | \"GBP\" | \"JPY\";\n\nexport interface ExchangeRates {\n\tBSV: number;\n\tUSD: number;\n\tEUR: number;\n\tGBP: number;\n\tJPY: number;\n}\n\n/**\n * Format satoshis as BSV with appropriate decimal places\n */\nexport function formatBSV(satoshis: number, decimals = 8): string {\n\t// Handle null/undefined/NaN cases\n\tif (satoshis == null || Number.isNaN(satoshis)) {\n\t\treturn \"0\";\n\t}\n\n\tconst bsv = toBitcoin(satoshis);\n\treturn Number(bsv)\n\t\t.toFixed(decimals)\n\t\t.replace(/\\.?0+$/, \"\");\n}\n\n/**\n * Format satoshis as the specified currency\n */\nexport function formatCurrency(\n\tvalue: number,\n\tcurrency: Currency = \"USD\",\n\texchangeRate?: number,\n): string {\n\tlet amount = value;\n\n\t// If value is in satoshis and we want fiat currency, convert via BSV\n\tif (currency !== \"BSV\" && exchangeRate) {\n\t\tconst bsvAmount =\n\t\t\ttypeof value === \"number\" && value > 1000000 ? toBitcoin(value) : value;\n\t\tamount = bsvAmount * exchangeRate;\n\t}\n\n\tconst formatters: Record<Currency, Intl.NumberFormat> = {\n\t\tBSV: new Intl.NumberFormat(\"en-US\", {\n\t\t\tminimumFractionDigits: 0,\n\t\t\tmaximumFractionDigits: 8,\n\t\t}),\n\t\tUSD: new Intl.NumberFormat(\"en-US\", {\n\t\t\tstyle: \"currency\",\n\t\t\tcurrency: \"USD\",\n\t\t\tminimumFractionDigits: 2,\n\t\t\tmaximumFractionDigits: 2,\n\t\t}),\n\t\tEUR: new Intl.NumberFormat(\"en-EU\", {\n\t\t\tstyle: \"currency\",\n\t\t\tcurrency: \"EUR\",\n\t\t\tminimumFractionDigits: 2,\n\t\t\tmaximumFractionDigits: 2,\n\t\t}),\n\t\tGBP: new Intl.NumberFormat(\"en-GB\", {\n\t\t\tstyle: \"currency\",\n\t\t\tcurrency: \"GBP\",\n\t\t\tminimumFractionDigits: 2,\n\t\t\tmaximumFractionDigits: 2,\n\t\t}),\n\t\tJPY: new Intl.NumberFormat(\"ja-JP\", {\n\t\t\tstyle: \"currency\",\n\t\t\tcurrency: \"JPY\",\n\t\t\tminimumFractionDigits: 0,\n\t\t\tmaximumFractionDigits: 0,\n\t\t}),\n\t};\n\n\tconst formatted = formatters[currency].format(amount);\n\n\t// Add BSV suffix for BSV amounts\n\tif (currency === \"BSV\") {\n\t\treturn `${formatted} BSV`;\n\t}\n\n\treturn formatted;\n}\n\n/**\n * Format token amounts with proper decimal places\n */\nexport function formatTokenAmount(\n\tamount: string | number,\n\tdecimals = 0,\n): string {\n\tconst num = typeof amount === \"string\" ? Number.parseFloat(amount) : amount;\n\n\tif (Number.isNaN(num)) return \"0\";\n\n\t// Use satoshi-token library for conversion\n\tconst displayAmount = decimals > 0 ? toToken(num, decimals) : num;\n\n\t// Format with appropriate decimal places\n\tconst formatter = new Intl.NumberFormat(\"en-US\", {\n\t\tminimumFractionDigits: 0,\n\t\tmaximumFractionDigits: Math.min(decimals, 8),\n\t});\n\n\treturn formatter.format(Number(displayAmount));\n}\n\n/**\n * Parse token amount from display format to token units\n */\nexport function parseTokenAmount(amount: string, decimals = 0): string {\n\tconst num = Number.parseFloat(amount);\n\tif (Number.isNaN(num)) return \"0\";\n\n\t// Use satoshi-token library for conversion\n\tconst tokenAmount = decimals > 0 ? toTokenSat(num, decimals) : num;\n\n\t// Return as string for precise handling\n\treturn tokenAmount.toString();\n}\n\n/**\n * Convert between different currencies\n */\nexport function convertCurrency(\n\tamount: number,\n\tfromCurrency: Currency,\n\ttoCurrency: Currency,\n\texchangeRates: Partial<ExchangeRates>,\n): number {\n\tif (fromCurrency === toCurrency) return amount;\n\n\t// Convert to USD as base currency first\n\tlet usdAmount = amount;\n\tif (fromCurrency !== \"USD\") {\n\t\tconst fromRate = exchangeRates[fromCurrency];\n\t\tif (!fromRate)\n\t\t\tthrow new Error(`Exchange rate not available for ${fromCurrency}`);\n\t\tusdAmount = fromCurrency === \"BSV\" ? amount * fromRate : amount / fromRate;\n\t}\n\n\t// Convert from USD to target currency\n\tif (toCurrency === \"USD\") return usdAmount;\n\n\tconst toRate = exchangeRates[toCurrency];\n\tif (!toRate) throw new Error(`Exchange rate not available for ${toCurrency}`);\n\n\treturn toCurrency === \"BSV\" ? usdAmount / toRate : usdAmount * toRate;\n}\n\n/**\n * Calculate percentage change\n */\nexport function calculatePercentageChange(\n\toldValue: number,\n\tnewValue: number,\n): number {\n\tif (oldValue === 0) return newValue > 0 ? 100 : 0;\n\treturn ((newValue - oldValue) / oldValue) * 100;\n}\n\n/**\n * Format percentage with appropriate color coding\n */\nexport function formatPercentage(percentage: number): {\n\ttext: string;\n\tcolor: \"green\" | \"red\" | \"gray\";\n} {\n\tconst abs = Math.abs(percentage);\n\tconst sign = percentage > 0 ? \"+\" : percentage < 0 ? \"-\" : \"\";\n\n\treturn {\n\t\ttext: `${sign}${abs.toFixed(2)}%`,\n\t\tcolor: percentage > 0 ? \"green\" : percentage < 0 ? \"red\" : \"gray\",\n\t};\n}\n\n/**\n * Abbreviate large numbers (e.g., 1000 -> 1K, 1000000 -> 1M)\n */\nexport function abbreviateNumber(num: number): string {\n\t// Handle null/undefined/NaN cases\n\tif (num == null || Number.isNaN(num)) {\n\t\treturn \"0\";\n\t}\n\n\tconst billion = 1000000000;\n\tconst million = 1000000;\n\tconst thousand = 1000;\n\n\tif (num >= billion) {\n\t\treturn `${(num / billion).toFixed(1)}B`;\n\t}\n\tif (num >= million) {\n\t\treturn `${(num / million).toFixed(1)}M`;\n\t}\n\tif (num >= thousand) {\n\t\treturn `${(num / thousand).toFixed(1)}K`;\n\t}\n\n\treturn num.toString();\n}\n\n/**\n * Validate if a string is a valid numeric amount\n */\nexport function isValidAmount(amount: string): boolean {\n\tconst num = Number.parseFloat(amount);\n\treturn !Number.isNaN(num) && num >= 0 && Number.isFinite(num);\n}\n\n/**\n * Get currency symbol for display\n */\nexport function getCurrencySymbol(currency: Currency): string {\n\tconst symbols: Record<Currency, string> = {\n\t\tBSV: \"\",\n\t\tUSD: \"$\",\n\t\tEUR: \"\",\n\t\tGBP: \"£\",\n\t\tJPY: \"¥\",\n\t};\n\n\treturn symbols[currency];\n}\n", "target": "<%- config.aliases.components %>/currency.tsx" } ] }