🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@iamjr15/react-currency-localizer

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install
Package was removed
Sorry, it seems this package was removed from the registry

@iamjr15/react-currency-localizer

A React hook to display prices in a user's local currency using HTTPS-compatible IP geolocation with robust validation and error handling

latest
Source
npmnpm
Version
1.1.2
Version published
Maintainers
1
Created
Source

React Currency Localizer

npm version TypeScript License: MIT

A React hook for automatically displaying prices in a user's local currency using IP geolocation. Built with a robust two-API architecture using specialized services for maximum accuracy and reliability. Perfect for e-commerce sites, pricing pages, and international applications.

🚀 Features

Core Architecture

  • Two-API Strategy: Decoupled architecture using specialized services for maximum accuracy
    • Geolocation: ipapi.co for HTTPS-compatible currency detection (no API key required)
    • Exchange Rates: exchangerate-api.com for real-time conversion rates
  • Intelligent Caching: Multi-tier caching strategy optimized for each data type
    • Persistent Geolocation: 24-hour localStorage caching (location rarely changes)
    • In-Memory Exchange Rates: 1-hour memory caching (balances freshness vs performance)
  • TanStack Query Integration: Advanced state management with automatic deduplication and background updates

Enhanced Developer Experience

  • Robust Input Validation: Case-insensitive currency codes and pre-emptive API key validation
  • Graceful Error Handling: Intelligent fallbacks and specific error messages
  • TypeScript Support: Fully typed with comprehensive type definitions
  • Multiple Usage Patterns: Hook-based API and declarative component wrapper
  • Automatic Currency Detection: Uses IP geolocation to detect user's local currency
  • Manual Override Support: Bypass geolocation with explicit currency selection

Production Ready

  • Lightweight: Only ~21kB (gzipped: ~6.8kB) with minimal runtime dependencies
  • Framework Agnostic: Works with any React application
  • HTTPS Compatible: Uses HTTPS-only APIs safe for production deployments
  • Free APIs: Uses only free-tier APIs (no credit card required)
  • Comprehensive Testing: Extensive suite including real API integration validation

📦 Installation

# npm
npm install @iamjr15/react-currency-localizer @tanstack/react-query

# yarn
yarn add @iamjr15/react-currency-localizer @tanstack/react-query

# pnpm
pnpm add @iamjr15/react-currency-localizer @tanstack/react-query

Note: @tanstack/react-query is a peer dependency required for caching and data fetching.

🏁 Quick Start

1. Wrap Your App with the Provider

import { CurrencyConverterProvider } from '@iamjr15/react-currency-localizer'

function App() {
  return (
    <CurrencyConverterProvider>
      <YourAppContent />
    </CurrencyConverterProvider>
  )
}

2. Use the Hook

import { useCurrencyConverter } from '@iamjr15/react-currency-localizer'

function ProductPrice({ price }: { price: number }) {
  const { 
    convertedPrice, 
    localCurrency, 
    isLoading, 
    error 
  } = useCurrencyConverter({
    basePrice: price,
    baseCurrency: 'USD',
    apiKey: 'your-exchangerate-api-key' // Get free key from exchangerate-api.com
  })

  if (isLoading) return <span>Loading price...</span>
  if (error) return <span>${price}</span> // Fallback to original price

  return (
    <span>
      {new Intl.NumberFormat(undefined, {
        style: 'currency',
        currency: localCurrency || 'USD'
      }).format(convertedPrice || price)}
    </span>
  )
}

3. Or Use the Component

import { LocalizedPrice } from '@iamjr15/react-currency-localizer'

function ProductCard() {
  return (
    <div>
      <h3>Premium Plan</h3>
      <LocalizedPrice 
        basePrice={99.99}
        baseCurrency="USD"
        apiKey="your-api-key"
      />
    </div>
  )
}

📚 API Reference

useCurrencyConverter(options)

The main hook for currency conversion.

Parameters

ParameterTypeRequiredDescription
basePricenumberThe price in the base currency
baseCurrencystringISO 4217 currency code (case-insensitive, e.g., 'USD' or 'usd')
apiKeystringAPI key from exchangerate-api.com (validated for helpful error messages)
manualCurrencystringOverride detected currency (case-insensitive)
onSuccessfunctionCallback on successful conversion
onErrorfunctionCallback on error

Returns

PropertyTypeDescription
convertedPricenumber | nullPrice in local currency
localCurrencystring | nullDetected/manual currency code
baseCurrencystringOriginal currency code
exchangeRatenumber | nullExchange rate used
isLoadingbooleanLoading state
errorError | nullError object if any

<LocalizedPrice />

React component for displaying localized prices.

Props

PropTypeRequiredDescription
basePricenumberThe price in base currency
baseCurrencystringISO 4217 currency code (case-insensitive)
apiKeystringExchangeRate API key (validated automatically)
manualCurrencystringOverride detected currency (case-insensitive)
loadingComponentReactNodeCustom loading component
errorComponentfunctionCustom error component (if not provided, shows original price as fallback)
formatPricefunctionCustom price formatter

💡 Usage Examples

E-commerce Product Pricing

function ProductGrid() {
  const products = [
    { id: 1, name: 'T-Shirt', price: 29.99 },
    { id: 2, name: 'Jeans', price: 79.99 },
    { id: 3, name: 'Sneakers', price: 129.99 }
  ]

  return (
    <div className="grid">
      {products.map(product => (
        <div key={product.id} className="product-card">
          <h3>{product.name}</h3>
          <LocalizedPrice 
            basePrice={product.price}
            baseCurrency="USD"
            // Vite: import.meta.env.VITE_EXCHANGE_API_KEY
            // CRA: process.env.REACT_APP_EXCHANGE_API_KEY
            // Next.js: process.env.NEXT_PUBLIC_EXCHANGE_API_KEY
            apiKey={process.env.REACT_APP_EXCHANGE_API_KEY}
          />
        </div>
      ))}
    </div>
  )
}

Subscription Pricing Table

function PricingTable() {
  const plans = [
    { name: 'Basic', price: 9.99 },
    { name: 'Pro', price: 19.99 },
    { name: 'Enterprise', price: 49.99 }
  ]

  return (
    <div className="pricing-table">
      {plans.map(plan => (
        <div key={plan.name} className="plan">
          <h3>{plan.name}</h3>
          <LocalizedPrice 
            basePrice={plan.price}
            baseCurrency="USD"
            // Vite: import.meta.env.VITE_EXCHANGE_API_KEY
            // CRA: process.env.REACT_APP_EXCHANGE_API_KEY
            // Next.js: process.env.NEXT_PUBLIC_EXCHANGE_API_KEY
            apiKey={process.env.REACT_APP_EXCHANGE_API_KEY}
            formatPrice={(price, currency) => 
              `${currency} ${price.toFixed(2)}/month`
            }
          />
        </div>
      ))}
    </div>
  )
}

Manual Currency Override

function CurrencySelector() {
  const [selectedCurrency, setSelectedCurrency] = useState('')
  
  return (
    <div>
      <select 
        value={selectedCurrency} 
        onChange={(e) => setSelectedCurrency(e.target.value)}
      >
        <option value="">Auto-detect</option>
        <option value="USD">USD</option>
        <option value="EUR">EUR</option>
        <option value="GBP">GBP</option>
        <option value="JPY">JPY</option>
      </select>
      
      <LocalizedPrice 
        basePrice={99.99}
        baseCurrency="USD"
        // Vite: import.meta.env.VITE_EXCHANGE_API_KEY
        // CRA: process.env.REACT_APP_EXCHANGE_API_KEY
        // Next.js: process.env.NEXT_PUBLIC_EXCHANGE_API_KEY
        apiKey={process.env.REACT_APP_EXCHANGE_API_KEY}
        manualCurrency={selectedCurrency || undefined}
      />
    </div>
  )
}

Error Handling and Loading States

function PriceWithStates() {
  const { convertedPrice, localCurrency, isLoading, error } = useCurrencyConverter({
    basePrice: 59.99,
    baseCurrency: 'usd', // Case-insensitive! Will be converted to 'USD'
    // Vite: import.meta.env.VITE_EXCHANGE_API_KEY
    // CRA: process.env.REACT_APP_EXCHANGE_API_KEY
    // Next.js: process.env.NEXT_PUBLIC_EXCHANGE_API_KEY
    apiKey: process.env.REACT_APP_EXCHANGE_API_KEY,
    onSuccess: (result) => {
      console.log('Conversion successful:', result)
    },
    onError: (error) => {
      console.error('Conversion failed:', error.message)
      // You'll get helpful error messages like:
      // "API key is missing. Please provide a valid key from exchangerate-api.com."
      // "Currency 'XYZ' was detected from your location but is not supported by the exchange rate provider."
    }
  })

  if (isLoading) {
    return (
      <div className="price-loading">
        <div className="spinner" />
        <span>Converting price...</span>
      </div>
    )
  }

  if (error) {
    return (
      <div className="price-error">
        <span>$59.99 USD</span>
        <small>Unable to convert: {error.message}</small>
      </div>
    )
  }

  return (
    <div className="price-success">
      {new Intl.NumberFormat(undefined, {
        style: 'currency',
        currency: localCurrency || 'USD'
      }).format(convertedPrice || 59.99)}
    </div>
  )
}

Graceful Fallback Behavior

// LocalizedPrice automatically shows original price if conversion fails
function AutoFallbackPrice() {
  return (
    <LocalizedPrice 
      basePrice={99.99}
      baseCurrency="usd" // Case doesn't matter
      apiKey="" // Empty key will show helpful error, then fallback to original price
    />
    // If API fails: Shows "$99.99" with tooltip "Conversion failed, showing original price in USD"
  )
}

// Or provide custom error component for full control
function CustomErrorPrice() {
  return (
    <LocalizedPrice 
      basePrice={99.99}
      baseCurrency="USD"
      // Vite: import.meta.env.VITE_EXCHANGE_API_KEY
      // CRA: process.env.REACT_APP_EXCHANGE_API_KEY
      // Next.js: process.env.NEXT_PUBLIC_EXCHANGE_API_KEY
      apiKey={process.env.REACT_APP_EXCHANGE_API_KEY}
      errorComponent={(error) => (
        <div className="price-error">
          <span className="price">$99.99</span>
          <span className="error-badge">Conversion Error</span>
          <small>{error.message}</small>
        </div>
      )}
    />
  )
}

🏗️ Architecture Overview

This package uses a carefully designed architecture for maximum reliability and performance:

Two-API Strategy

We use a decoupled, two-API approach for maximum accuracy and flexibility:

  • Specialized Geolocation Service: ipapi.co

    • Why: Dedicated to IP-based location data with HTTPS support for optimal accuracy
    • Advantage: No API key required, HTTPS-compatible, robust rate limiting
    • Philosophy: Use specialized services for what they do best—identifying location-based data
  • Specialized Financial Data Service: exchangerate-api.com

    • Why: Dedicated to currency exchange rates for real-time accuracy
    • Advantage: Supports any base currency (not just USD), 1,500 requests/month
    • Philosophy: Use specialized services for what they do best—providing currency exchange rates

Advanced State Management

We use TanStack Query (not basic useEffect/useState) for robust data management:

  • Automatic caching, request deduplication, and background updates
  • Eliminates race conditions and boilerplate code
  • Declarative API for managing asynchronous operations

Intelligent Caching Strategy

We implement data-type-specific caching optimized for each type of data:

Persistent Geolocation Caching

  • Duration: 24+ hours in localStorage
  • Rationale: User location rarely changes
  • Benefit: Zero API calls on subsequent visits

In-Memory Exchange Rate Caching

  • Duration: 1 hour in memory
  • Rationale: Balance between data freshness and performance
  • Benefit: Prevents excessive API calls while maintaining accuracy

🔧 Configuration

Getting API Keys

  • ExchangeRate-API (Required):

    • Visit exchangerate-api.com
    • Sign up for a free account
    • Get your API key (1,500 requests/month free)
  • IP Geolocation (Automatic):

    • Uses ipapi.co (no key required)
    • HTTPS-compatible for secure deployments
    • Falls back gracefully on rate limits

Environment Variables

# .env
VITE_EXCHANGE_API_KEY=your_exchangerate_api_key_here

# Optional: Enable integration tests with real APIs
VITE_RUN_INTEGRATION_TESTS=true

For different frameworks:

# Vite (browser-exposed)
VITE_EXCHANGE_API_KEY=your_exchangerate_api_key_here

# Create React App (browser-exposed)
REACT_APP_EXCHANGE_API_KEY=your_exchangerate_api_key_here

# Next.js (browser-exposed)
NEXT_PUBLIC_EXCHANGE_API_KEY=your_exchangerate_api_key_here

Custom QueryClient Configuration

The package uses TanStack Query for robust state management with optimal caching:

import { QueryClient } from '@tanstack/react-query'
import { CurrencyConverterProvider } from '@iamjr15/react-currency-localizer'

// Custom QueryClient with optimized caching strategy
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // Geolocation queries: 24+ hour stale time (location rarely changes)
      staleTime: 1000 * 60 * 60 * 24, // 24 hours
      // Exchange rate queries: 1 hour stale time (balance freshness vs performance)  
      gcTime: 1000 * 60 * 60 * 2, // 2 hours cache time
      retry: 1, // Conservative retry to respect API limits
    },
  },
})

function App() {
  return (
    <CurrencyConverterProvider queryClient={queryClient}>
      <YourApp />
    </CurrencyConverterProvider>
  )
}

Note: The default configuration already implements the optimal caching strategy. Custom configuration is optional.

⚠️ Important Considerations

Server-Side Rendering (SSR) Caveats

When using this library with SSR frameworks (Next.js, Nuxt, SvelteKit), be aware that:

  • IP Geolocation runs on the server: The detected location reflects the server's IP, not the user's
  • Hydration mismatches possible: Server-rendered currency may differ from client-side detection
  • Recommended approach: Pass manualCurrency prop or perform geolocation client-side only
// For SSR: Disable geolocation on server, enable on client
const [isClient, setIsClient] = useState(false)

useEffect(() => {
  setIsClient(true)
}, [])

return (
  <LocalizedPrice 
    basePrice={99.99}
    baseCurrency="USD"
    apiKey={process.env.NEXT_PUBLIC_EXCHANGE_API_KEY}
    manualCurrency={!isClient ? 'USD' : undefined} // Use USD on server, auto-detect on client
  />
)

HTTPS Requirements

This library uses HTTPS-only APIs (ipapi.co, exchangerate-api.com) to ensure compatibility with secure deployments. Mixed content (HTTP requests from HTTPS sites) is automatically blocked by modern browsers.

Runtime Dependencies

While the library has minimal dependencies, it does include:

  • @tanstack/react-query (peer dependency for state management)
  • @tanstack/query-sync-storage-persister (for localStorage caching)
  • @tanstack/react-query-persist-client (for persistence integration)

Total bundle impact: ~20kB minified, ~6.5kB gzipped.

🌍 Supported Currencies

The package supports 161 commonly circulating world currencies via ExchangeRate-API, covering 99% of all UN recognized states and territories.

✅ Complete Currency Support (161 Currencies)

All ISO 4217 three-letter currency codes are supported, including:

Major Global Currencies

  • USD - United States Dollar
  • EUR - Euro (European Union)
  • GBP - Pound Sterling (United Kingdom)
  • JPY - Japanese Yen
  • CAD - Canadian Dollar
  • AUD - Australian Dollar
  • CHF - Swiss Franc
  • CNY - Chinese Renminbi
  • INR - Indian Rupee
  • BRL - Brazilian Real
  • RUB - Russian Ruble
  • KRW - South Korean Won
  • SGD - Singapore Dollar
  • HKD - Hong Kong Dollar
  • NOK - Norwegian Krone
  • SEK - Swedish Krona
  • MXN - Mexican Peso
  • ZAR - South African Rand
  • TRY - Turkish Lira

All Supported Currencies

Click to view complete list of 161 supported currencies
CodeCurrency NameCountry/Region
AEDUAE DirhamUnited Arab Emirates
AFNAfghan AfghaniAfghanistan
ALLAlbanian LekAlbania
AMDArmenian DramArmenia
ANGNetherlands Antillian GuilderNetherlands Antilles
AOAAngolan KwanzaAngola
ARSArgentine PesoArgentina
AUDAustralian DollarAustralia
AWGAruban FlorinAruba
AZNAzerbaijani ManatAzerbaijan
BAMBosnia and Herzegovina MarkBosnia and Herzegovina
BBDBarbados DollarBarbados
BDTBangladeshi TakaBangladesh
BGNBulgarian LevBulgaria
BHDBahraini DinarBahrain
BIFBurundian FrancBurundi
BMDBermudian DollarBermuda
BNDBrunei DollarBrunei
BOBBolivian BolivianoBolivia
BRLBrazilian RealBrazil
BSDBahamian DollarBahamas
BTNBhutanese NgultrumBhutan
BWPBotswana PulaBotswana
BYNBelarusian RubleBelarus
BZDBelize DollarBelize
CADCanadian DollarCanada
CDFCongolese FrancDemocratic Republic of the Congo
CHFSwiss FrancSwitzerland
CLPChilean PesoChile
CNYChinese RenminbiChina
COPColombian PesoColombia
CRCCosta Rican ColonCosta Rica
CUPCuban PesoCuba
CVECape Verdean EscudoCape Verde
CZKCzech KorunaCzech Republic
DJFDjiboutian FrancDjibouti
DKKDanish KroneDenmark
DOPDominican PesoDominican Republic
DZDAlgerian DinarAlgeria
EGPEgyptian PoundEgypt
ERNEritrean NakfaEritrea
ETBEthiopian BirrEthiopia
EUREuroEuropean Union
FJDFiji DollarFiji
FKPFalkland Islands PoundFalkland Islands
FOKFaroese KrónaFaroe Islands
GBPPound SterlingUnited Kingdom
GELGeorgian LariGeorgia
GGPGuernsey PoundGuernsey
GHSGhanaian CediGhana
GIPGibraltar PoundGibraltar
GMDGambian DalasiThe Gambia
GNFGuinean FrancGuinea
GTQGuatemalan QuetzalGuatemala
GYDGuyanese DollarGuyana
HKDHong Kong DollarHong Kong
HNLHonduran LempiraHonduras
HRKCroatian KunaCroatia
HTGHaitian GourdeHaiti
HUFHungarian ForintHungary
IDRIndonesian RupiahIndonesia
ILSIsraeli New ShekelIsrael
IMPManx PoundIsle of Man
INRIndian RupeeIndia
IQDIraqi DinarIraq
IRRIranian RialIran
ISKIcelandic KrónaIceland
JEPJersey PoundJersey
JMDJamaican DollarJamaica
JODJordanian DinarJordan
JPYJapanese YenJapan
KESKenyan ShillingKenya
KGSKyrgyzstani SomKyrgyzstan
KHRCambodian RielCambodia
KIDKiribati DollarKiribati
KMFComorian FrancComoros
KRWSouth Korean WonSouth Korea
KWDKuwaiti DinarKuwait
KYDCayman Islands DollarCayman Islands
KZTKazakhstani TengeKazakhstan
LAKLao KipLaos
LBPLebanese PoundLebanon
LKRSri Lanka RupeeSri Lanka
LRDLiberian DollarLiberia
LSLLesotho LotiLesotho
LYDLibyan DinarLibya
MADMoroccan DirhamMorocco
MDLMoldovan LeuMoldova
MGAMalagasy AriaryMadagascar
MKDMacedonian DenarNorth Macedonia
MMKBurmese KyatMyanmar
MNTMongolian TögrögMongolia
MOPMacanese PatacaMacau
MRUMauritanian OuguiyaMauritania
MURMauritian RupeeMauritius
MVRMaldivian RufiyaaMaldives
MWKMalawian KwachaMalawi
MXNMexican PesoMexico
MYRMalaysian RinggitMalaysia
MZNMozambican MeticalMozambique
NADNamibian DollarNamibia
NGNNigerian NairaNigeria
NIONicaraguan CórdobaNicaragua
NOKNorwegian KroneNorway
NPRNepalese RupeeNepal
NZDNew Zealand DollarNew Zealand
OMROmani RialOman
PABPanamanian BalboaPanama
PENPeruvian SolPeru
PGKPapua New Guinean KinaPapua New Guinea
PHPPhilippine PesoPhilippines
PKRPakistani RupeePakistan
PLNPolish ZłotyPoland
PYGParaguayan GuaraníParaguay
QARQatari RiyalQatar
RONRomanian LeuRomania
RSDSerbian DinarSerbia
RUBRussian RubleRussia
RWFRwandan FrancRwanda
SARSaudi RiyalSaudi Arabia
SBDSolomon Islands DollarSolomon Islands
SCRSeychellois RupeeSeychelles
SDGSudanese PoundSudan
SEKSwedish KronaSweden
SGDSingapore DollarSingapore
SHPSaint Helena PoundSaint Helena
SLESierra Leonean LeoneSierra Leone
SOSSomali ShillingSomalia
SRDSurinamese DollarSuriname
SSPSouth Sudanese PoundSouth Sudan
STNSão Tomé and Príncipe DobraSão Tomé and Príncipe
SYPSyrian PoundSyria
SZLEswatini LilangeniEswatini
THBThai BahtThailand
TJSTajikistani SomoniTajikistan
TMTTurkmenistan ManatTurkmenistan
TNDTunisian DinarTunisia
TOPTongan PaʻangaTonga
TRYTurkish LiraTurkey
TTDTrinidad and Tobago DollarTrinidad and Tobago
TVDTuvaluan DollarTuvalu
TWDNew Taiwan DollarTaiwan
TZSTanzanian ShillingTanzania
UAHUkrainian HryvniaUkraine
UGXUgandan ShillingUganda
USDUnited States DollarUnited States
UYUUruguayan PesoUruguay
UZSUzbekistani So'mUzbekistan
VESVenezuelan Bolívar SoberanoVenezuela
VNDVietnamese ĐồngVietnam
VUVVanuatu VatuVanuatu
WSTSamoan TālāSamoa
XAFCentral African CFA FrancCEMAC
XCDEast Caribbean DollarOrganisation of Eastern Caribbean States
XDRSpecial Drawing RightsInternational Monetary Fund
XOFWest African CFA francCFA
XPFCFP FrancCollectivités d'Outre-Mer
YERYemeni RialYemen
ZARSouth African RandSouth Africa
ZMWZambian KwachaZambia
ZWLZimbabwean DollarZimbabwe

❌ Unsupported Currency (1)

CodeCurrency NameCountryReason
KPWNorth Korean WonNorth KoreaDue to sanctions & lack of international trade

Note: For KPW data, the only reliable source is Daily NK, which reports actual jangmadang market rates via human sources inside DPRK.

⚠️ Volatile Currencies (Special Caution Required)

The following currencies experience heightened volatility and substantial differences between official and actual exchange rates. Extra caution is recommended:

CodeCurrency NameCountryNotes
ARSArgentine PesoArgentinaMultiple exchange rates in market
LYDLibyan DinarLibyaPolitical instability affects rates
SSPSouth Sudanese PoundSouth SudanHigh volatility
SYPSyrian PoundSyriaOngoing conflict impacts rates
VESVenezuelan Bolívar SoberanoVenezuelaHyperinflation environment
YERYemeni RialYemenRegional instability
ZWLZimbabwean DollarZimbabweHistorical hyperinflation legacy

Important: For volatile currencies, rates default to central bank published rates, which may differ significantly from actual market rates.

⚡ Performance

  • Bundle Size: ~20kB minified, ~6.5kB gzipped
  • First Load: 2 API calls (geolocation + exchange rates)
  • Subsequent Loads: 0-1 API calls (cached geolocation)
  • Cache Duration: 24 hours for geolocation, 1 hour for exchange rates
  • Rate Limits: Handled gracefully with automatic fallbacks
  • Validation: Zero-cost currency normalization and API key validation
  • Error Prevention: Pre-emptive validation prevents wasted API calls

🔍 Troubleshooting

Common Issues and Solutions

"API key is missing" Error

// ❌ This will show a helpful error message
useCurrencyConverter({
  basePrice: 99.99,
  baseCurrency: 'USD',
  apiKey: '' // Empty key
})

// ✅ Provide your API key
useCurrencyConverter({
  basePrice: 99.99,
  baseCurrency: 'USD',
  apiKey: process.env.REACT_APP_EXCHANGE_API_KEY
})

Currency Case Sensitivity

// ✅ All of these work the same way (case-insensitive)
useCurrencyConverter({ baseCurrency: 'USD', manualCurrency: 'EUR' })
useCurrencyConverter({ baseCurrency: 'usd', manualCurrency: 'eur' })  
useCurrencyConverter({ baseCurrency: 'Usd', manualCurrency: 'Eur' })

Currency Not Supported Error

// If you get: "Currency 'KPW' was detected from your location but is not supported"
// Solution: Use manual currency override (KPW is the only unsupported currency)
useCurrencyConverter({
  basePrice: 99.99,
  baseCurrency: 'USD',
  apiKey: 'your-key',
  manualCurrency: 'USD' // Override KPW with a supported currency
})

// For volatile currencies (ARS, VES, etc.), rates may differ from market reality
useCurrencyConverter({
  basePrice: 99.99,
  baseCurrency: 'USD',
  apiKey: 'your-key',
  manualCurrency: 'ARS', // Works, but be aware of potential rate discrepancies
  onSuccess: (result) => {
    console.log('Note: ARS rates may differ from actual market rates')
  }
})

Rate Limiting

// The package automatically handles rate limits, but you can also:
useCurrencyConverter({
  basePrice: 99.99,
  baseCurrency: 'USD', 
  apiKey: 'your-key',
  onError: (error) => {
    if (error.message.includes('429')) {
      // Handle rate limiting gracefully
      console.log('Rate limited, showing original price')
    }
  }
})

🧪 Testing

Unit Tests (with Mocks)

Run the standard test suite with mocked APIs:

npm test

Run with coverage:

npm run test:coverage

Integration Tests (with Real APIs)

To test with real API calls, first set up your environment:

# Create .env file with your real API key
echo "VITE_EXCHANGE_API_KEY=your_actual_api_key_here" > .env
echo "VITE_RUN_INTEGRATION_TESTS=true" >> .env

Then run integration tests:

# Run once with real APIs
npm run test:integration

# Watch mode with real APIs  
npm run test:integration:watch

⚠️ Note: Integration tests make real API calls and will:

  • Consume your API quota (free tier: 1,500 requests/month)
  • Require internet connection
  • Take longer to complete (5-15 seconds per test)
  • May fail due to network issues or rate limits

Test Coverage

The package includes comprehensive tests covering:

  • Unit Tests: Hook functionality, component rendering, error handling (39 tests)
  • Integration Tests: Real API calls, caching performance, rate limiting (8 tests)
  • Validation Tests: Currency normalization, API key validation (4 tests)
  • Edge Cases: Zero prices, error scenarios, network failures
  • TypeScript: Full type checking and IntelliSense
  • Total: 49 tests with 100% code coverage

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

# Clone the repository
git clone https://github.com/iamjr15/react-currency-localizer.git

# Install dependencies
npm install

# Run tests
npm test

# Build the package
npm run build

# Run linting
npm run lint

📜 License

MIT © Jigyansu Rout

✨ Key Design Decisions

This implementation is built on carefully considered architectural choices:

Two-API Architecture - Specialized services for maximum accuracy
TanStack Query Integration - Enterprise-grade state management
Intelligent Caching Strategy - Optimized for each data type
Hook-Based API - Modern React patterns
LocalizedPrice Component - Declarative wrapper component
TypeScript Support - Full type safety and IntelliSense
Free APIs Only - Zero cost barrier to entry
ipapi.co Selection - HTTPS-compatible geolocation service
ExchangeRate-API.com Selection - Reliable currency data provider

🙏 Acknowledgments

  • ExchangeRate-API for reliable exchange rate data
  • ipapi.co for free HTTPS-compatible IP geolocation services
  • TanStack Query for excellent caching and data fetching
  • The React community for inspiration and feedback

Made with ❤️ for the React community

Keywords

react

FAQs

Package last updated on 08 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts