diff --git a/README.md b/README.md index 4a560d7..5419368 100755 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ $ yarn add react-currency-hooks import { useCurrency } from 'react-currency-hooks'; ``` + + #### Params | Name | Type | Default | Description | diff --git a/__tests__/useCurrency.test.ts b/__tests__/useCurrency.test.ts index bca070f..8ea48de 100644 --- a/__tests__/useCurrency.test.ts +++ b/__tests__/useCurrency.test.ts @@ -2,6 +2,8 @@ import { renderHook } from '@testing-library/react-hooks'; import { useCurrency } from '../src'; +// TODO test different amount +// TODO test root options describe('useCurrency', () => { const rates = { GBP: 0.92, @@ -18,9 +20,9 @@ describe('useCurrency', () => { rates, }; - const { result } = renderHook(() => useCurrency(200, options)); + const { result } = renderHook(() => useCurrency()); - expect(result.current).toBe(192.85714285714286); + expect(result.current(200, options)).toBe(192.85714285714286); }); it('should return 2 `to` values', () => { @@ -31,9 +33,9 @@ describe('useCurrency', () => { rates, }; - const { result } = renderHook(() => useCurrency(200, options)); + const { result } = renderHook(() => useCurrency()); - expect(result.current).toMatchObject({ + expect(result.current(200, options)).toMatchObject({ chf: 192.85714285714286, gbp: 164.28571428571428, }); @@ -48,9 +50,9 @@ describe('useCurrency', () => { keepPrecision: false, }; - const { result } = renderHook(() => useCurrency(200, options)); + const { result } = renderHook(() => useCurrency()); - expect(result.current).toBe(192.86); + expect(result.current(200, options)).toBe(192.86); }); it('should return single `to` value from hook with the same `base` and `from` rates', () => { @@ -61,9 +63,9 @@ describe('useCurrency', () => { rates, }; - const { result } = renderHook(() => useCurrency(200, options)); + const { result } = renderHook(() => useCurrency()); - expect(result.current).toBe(216); + expect(result.current(200, options)).toBe(216); }); it('should return single `to` value from hook with the same `base` and `to` rates', () => { @@ -74,9 +76,9 @@ describe('useCurrency', () => { rates, }; - const { result } = renderHook(() => useCurrency(200, options)); + const { result } = renderHook(() => useCurrency()); - expect(result.current).toBe(178.57142857142856); + expect(result.current(200, options)).toBe(178.57142857142856); }); it('should return single `to` value from hook without `base` rate', () => { @@ -87,9 +89,9 @@ describe('useCurrency', () => { rates, }; - const { result } = renderHook(() => useCurrency(200, options)); + const { result } = renderHook(() => useCurrency()); - expect(result.current).toBe(192.85714285714286); + expect(result.current(200, options)).toBe(192.85714285714286); }); it('should return an error', () => { @@ -101,7 +103,9 @@ describe('useCurrency', () => { rates, }; - renderHook(() => useCurrency(200, options)); + const { result } = renderHook(() => useCurrency()); + + result.current(200, options); } catch (err) { expect(err.message).toBe( '`rates` object does not contain either `from` or `to` currency!' diff --git a/rollup.config.js b/rollup.config.js index 0d80503..a86e78f 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -19,5 +19,5 @@ export default { }, ], plugins: [resolve(), typescript(), terser()], - external: Object.keys(pkg.peerDependencies), + external: Object.keys(pkg.peerDependencies || {}), // TODO add fallback for dependencies }; diff --git a/src/useCurrency.ts b/src/useCurrency.ts index dab07c6..2ac7700 100644 --- a/src/useCurrency.ts +++ b/src/useCurrency.ts @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react'; +import { useCallback } from 'react'; import { hasKey } from './helpers/hasKey'; @@ -6,58 +6,61 @@ import { Options } from './interfaces/Options'; import type { Rates } from './types/rates'; -export const useCurrency = (amount: number, options: Options) => { - const { from, to, base, rates, keepPrecision = true } = options; +type ConvertCurrencyCallback = ( + amount: number, + options?: Options +) => number | Record | undefined; - const [conversion, setConversion] = useState( - to instanceof Array ? {} : undefined - ); +export const useCurrency = (rootOptions?: Options) => { + return useCallback( + (amount, options) => { + const { from, to, base, rates, keepPrecision = true } = { + ...rootOptions, + ...options, + }; - const getRate = useCallback( - (to: string) => { - if (from === base && hasKey(rates, to)) { - return rates[to]; - } + const getRate = (to: string) => { + if (from === base && hasKey(rates, to)) { + return rates[to]; + } - if (to === base && hasKey(rates, from)) { - return 1 / rates[from]; - } + if (to === base && hasKey(rates, from)) { + return 1 / rates[from]; + } - if (hasKey(rates, from) && hasKey(rates, to)) { - return rates[to] * (1 / rates[from]); - } + if (hasKey(rates, from) && hasKey(rates, to)) { + return rates[to] * (1 / rates[from]); + } - throw new Error( - '`rates` object does not contain either `from` or `to` currency!' - ); - }, - [base, from, rates] - ); + throw new Error( + '`rates` object does not contain either `from` or `to` currency!' + ); + }; - const convert = useCallback( - (to: string) => { - const convertedValue = amount * 100 * getRate(to); + // TODO rename function + const convert = (to: string) => { + const convertedValue = amount * 100 * getRate(to); - return ( - (keepPrecision ? convertedValue : Math.round(convertedValue)) / 100 - ); - }, - [amount, getRate, keepPrecision] - ); + return ( + (keepPrecision ? convertedValue : Math.round(convertedValue)) / 100 + ); + }; - useEffect(() => { - if (to instanceof Array) { - const converted: Rates = {}; + // TODO refactor + if (to instanceof Array) { + const converted: Rates = {}; - to.map((currency) => { - converted[currency.toLowerCase()] = convert(currency); - }); + to.map((currency) => { + converted[currency.toLowerCase()] = convert(currency); + }); - setConversion(converted); - } else if (typeof to === 'string') { - setConversion(convert(to)); - } - }, [convert, to]); + return converted; + } else if (typeof to === 'string') { + return convert(to); + } - return conversion; + return undefined; + }, + [rootOptions] + ); };