bigblocks
Version:
Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React
174 lines (173 loc) • 5.54 kB
JavaScript
// Currency Utilities - Format amounts, convert between currencies
import { toBitcoin, toToken, toTokenSat } from "satoshi-token";
/**
* Format satoshis as BSV with appropriate decimal places
*/
export function formatBSV(satoshis, decimals = 8) {
// Handle null/undefined/NaN cases
if (satoshis == null || Number.isNaN(satoshis)) {
return "0";
}
const bsv = toBitcoin(satoshis);
return Number(bsv)
.toFixed(decimals)
.replace(/\.?0+$/, "");
}
/**
* Format satoshis as the specified currency
*/
export function formatCurrency(value, currency = "USD", exchangeRate) {
let amount = value;
// If value is in satoshis and we want fiat currency, convert via BSV
if (currency !== "BSV" && exchangeRate) {
const bsvAmount = typeof value === "number" && value > 1000000 ? toBitcoin(value) : value;
amount = bsvAmount * exchangeRate;
}
const formatters = {
BSV: new Intl.NumberFormat("en-US", {
minimumFractionDigits: 0,
maximumFractionDigits: 8,
}),
USD: new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
EUR: new Intl.NumberFormat("en-EU", {
style: "currency",
currency: "EUR",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
GBP: new Intl.NumberFormat("en-GB", {
style: "currency",
currency: "GBP",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
JPY: new Intl.NumberFormat("ja-JP", {
style: "currency",
currency: "JPY",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}),
};
const formatted = formatters[currency].format(amount);
// Add BSV suffix for BSV amounts
if (currency === "BSV") {
return `${formatted} BSV`;
}
return formatted;
}
/**
* Format token amounts with proper decimal places
*/
export function formatTokenAmount(amount, decimals = 0) {
const num = typeof amount === "string" ? Number.parseFloat(amount) : amount;
if (Number.isNaN(num))
return "0";
// Use satoshi-token library for conversion
const displayAmount = decimals > 0 ? toToken(num, decimals) : num;
// Format with appropriate decimal places
const formatter = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 0,
maximumFractionDigits: Math.min(decimals, 8),
});
return formatter.format(Number(displayAmount));
}
/**
* Parse token amount from display format to token units
*/
export function parseTokenAmount(amount, decimals = 0) {
const num = Number.parseFloat(amount);
if (Number.isNaN(num))
return "0";
// Use satoshi-token library for conversion
const tokenAmount = decimals > 0 ? toTokenSat(num, decimals) : num;
// Return as string for precise handling
return tokenAmount.toString();
}
/**
* Convert between different currencies
*/
export function convertCurrency(amount, fromCurrency, toCurrency, exchangeRates) {
if (fromCurrency === toCurrency)
return amount;
// Convert to USD as base currency first
let usdAmount = amount;
if (fromCurrency !== "USD") {
const fromRate = exchangeRates[fromCurrency];
if (!fromRate)
throw new Error(`Exchange rate not available for ${fromCurrency}`);
usdAmount = fromCurrency === "BSV" ? amount * fromRate : amount / fromRate;
}
// Convert from USD to target currency
if (toCurrency === "USD")
return usdAmount;
const toRate = exchangeRates[toCurrency];
if (!toRate)
throw new Error(`Exchange rate not available for ${toCurrency}`);
return toCurrency === "BSV" ? usdAmount / toRate : usdAmount * toRate;
}
/**
* Calculate percentage change
*/
export function calculatePercentageChange(oldValue, newValue) {
if (oldValue === 0)
return newValue > 0 ? 100 : 0;
return ((newValue - oldValue) / oldValue) * 100;
}
/**
* Format percentage with appropriate color coding
*/
export function formatPercentage(percentage) {
const abs = Math.abs(percentage);
const sign = percentage > 0 ? "+" : percentage < 0 ? "-" : "";
return {
text: `${sign}${abs.toFixed(2)}%`,
color: percentage > 0 ? "green" : percentage < 0 ? "red" : "gray",
};
}
/**
* Abbreviate large numbers (e.g., 1000 -> 1K, 1000000 -> 1M)
*/
export function abbreviateNumber(num) {
// Handle null/undefined/NaN cases
if (num == null || Number.isNaN(num)) {
return "0";
}
const billion = 1000000000;
const million = 1000000;
const thousand = 1000;
if (num >= billion) {
return `${(num / billion).toFixed(1)}B`;
}
if (num >= million) {
return `${(num / million).toFixed(1)}M`;
}
if (num >= thousand) {
return `${(num / thousand).toFixed(1)}K`;
}
return num.toString();
}
/**
* Validate if a string is a valid numeric amount
*/
export function isValidAmount(amount) {
const num = Number.parseFloat(amount);
return !Number.isNaN(num) && num >= 0 && Number.isFinite(num);
}
/**
* Get currency symbol for display
*/
export function getCurrencySymbol(currency) {
const symbols = {
BSV: "₿",
USD: "$",
EUR: "€",
GBP: "£",
JPY: "¥",
};
return symbols[currency];
}