Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ module.exports = {
],
plugins: ['prettier', 'react-hooks'],
env: {
browser: true
browser: true,
jest: true
},
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
sourceType: 'module'
},
rules: {
'react-hooks/rules-of-hooks': 'error',
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
.DS_Store
yarn-error.log
.rpt2_cache
coverage
2 changes: 2 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
src
test
coverage

tsconfig.json
.travis.yml
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ cache:
directories:
- node_modules

script: yarn
script: yarn test
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# react-currency-hooks Changelog

## 1.2.0 (2020-02-23)
#### New Feature
- added option `keepPrecision`

## 1.1.0 / 1.1.1 / 1.1.2 / 1.1.3 (2020-02-09)
#### New Feature
- support for multiple `to` values
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Name | Type | Default | Description
**to** | string or string[] | ` ` | The currency to which it is converted
**base** | string | ` ` | Base currency
**rates** | Rates | `{}` | Currency rates
**keepPrecision** | boolean | `true` | `true` (return exact values), `false` (return values rounded to 2 places)

#### Returned Values
Type | Description
Expand All @@ -45,7 +46,7 @@ number or object with currencies passed in `to` | Converted value
## Example
```js
import React from 'react';
import { useCurrency } from 'react-viewport-hooks';
import { useCurrency } from 'react-currency-hooks';

const App = () => {
const rates = {
Expand Down
4 changes: 1 addition & 3 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
import { Options } from './interfaces/Options';
import { Rates } from './types/rates';
export declare const useCurrency: (amount: number, { from, to, base, rates }: Options) => number | Rates | undefined;
export { useCurrency } from './useCurrency';
1 change: 1 addition & 0 deletions lib/interfaces/Options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export interface Options {
readonly to: string | string[];
readonly base: string;
readonly rates: Readonly<Rates>;
readonly keepPrecision?: boolean;
}
2 changes: 1 addition & 1 deletion lib/react-currency-hooks.cjs.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/react-currency-hooks.esm.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions lib/useCurrency.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Options } from './interfaces/Options';
import { Rates } from './types/rates';
export declare const useCurrency: (amount: number, { from, to, base, rates, keepPrecision }: Options) => number | Rates | undefined;
30 changes: 22 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-currency-hooks",
"version": "1.1.3",
"version": "1.2.0",
"description": "Currency converter React hook",
"author": "Jakub Biesiada",
"license": "MIT",
Expand All @@ -10,7 +10,9 @@
"scripts": {
"release": "rimraf lib/* && npm run prettier && npm run lint && npm run build",
"build": "rollup -c",
"test": "jest --coverage",
"watch": "npm run build -- --watch",
"watch:test": "npm run test -- --watch",
"lint": "eslint 'src/**/*.ts' --fix",
"prettier": "prettier --write 'src/**/*.ts'"
},
Expand All @@ -30,31 +32,43 @@
"homepage": "https://github.com/JB1905/react-currency-hooks#readme",
"devDependencies": {
"@rollup/plugin-node-resolve": "^7.1.1",
"@types/react": "^16.9.19",
"@typescript-eslint/parser": "^2.19.0",
"@testing-library/react": "^9.4.1",
"@testing-library/react-hooks": "^3.2.1",
"@types/jest": "^25.1.3",
"@types/react": "^16.9.22",
"@typescript-eslint/parser": "^2.20.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-react-hooks": "^2.3.0",
"husky": "^4.2.1",
"eslint-plugin-react-hooks": "^2.4.0",
"husky": "^4.2.3",
"jest": "^25.1.0",
"lint-staged": "^10.0.7",
"prettier": "^1.19.1",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-test-renderer": "^16.12.0",
"rollup-plugin-terser": "^5.2.0",
"rollup-plugin-typescript2": "^0.25.3",
"typescript": "^3.7.5"
"rollup-plugin-typescript2": "^0.26.0",
"ts-jest": "^25.2.1",
"typescript": "^3.8.2"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"jest": {
"transform": {
"^.+\\.ts?$": "ts-jest"
}
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{ts}": [
"src/**/*.ts": [
"npm run prettier",
"npm run lint"
]
Expand Down
57 changes: 1 addition & 56 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1 @@
import { useState, useEffect } from 'react';

import { hasKey } from './helpers/hasKey';

import { Options } from './interfaces/Options';

import { Rates } from './types/rates';

export const useCurrency = (
amount: number,
{ from, to, base, rates }: Options
) => {
const [conversion, setConversion] = useState<number | Rates | undefined>(
to instanceof Array ? {} : undefined
);

useEffect(() => {
const convert = (to: string) => {
const getRate = () => {
if (from === base && hasKey(rates, to)) {
return rates[to];
}

if (to === base && hasKey(rates, from)) {
return 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!'
);
};

return (amount * 100 * getRate()) / 100;
};

if (to instanceof Array) {
const converted: Rates = {};

to.map(currency => {
converted[currency.toLowerCase()] = convert(currency);
});

setConversion(converted);
} else if (typeof to === 'string') {
setConversion(convert(to));
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return conversion;
};
export { useCurrency } from './useCurrency';
1 change: 1 addition & 0 deletions src/interfaces/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export interface Options {
readonly to: string | string[];
readonly base: string;
readonly rates: Readonly<Rates>;
readonly keepPrecision?: boolean;
}
60 changes: 60 additions & 0 deletions src/useCurrency.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useState, useEffect } from 'react';

import { hasKey } from './helpers/hasKey';

import { Options } from './interfaces/Options';

import { Rates } from './types/rates';

export const useCurrency = (
amount: number,
{ from, to, base, rates, keepPrecision = true }: Options
) => {
const [conversion, setConversion] = useState<number | Rates | undefined>(
to instanceof Array ? {} : undefined
);

useEffect(() => {
const convert = (to: string) => {
const getRate = () => {
if (from === base && hasKey(rates, to)) {
return rates[to];
}

if (to === base && hasKey(rates, from)) {
return 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!'
);
};

const convertedValue = amount * 100 * getRate();

return (
(keepPrecision ? convertedValue : Math.round(convertedValue)) / 100
);
};

if (to instanceof Array) {
const converted: Rates = {};

to.map(currency => {
converted[currency.toLowerCase()] = convert(currency);
});

setConversion(converted);
} else if (typeof to === 'string') {
setConversion(convert(to));
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return conversion;
};
94 changes: 94 additions & 0 deletions test/useCurrency.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { renderHook } from '@testing-library/react-hooks';

import { useCurrency } from '../src';

describe('useCurrency', () => {
const rates = {
GBP: 0.92,
EUR: 1.0,
CHF: 1.08,
USD: 1.12
};

it('should return single `to` value', () => {
const options = {
from: 'USD',
to: 'CHF',
base: 'EUR',
rates
};

const { result } = renderHook(() => useCurrency(200, options));

expect(result.current).toBe(192.85714285714286);
});

it('should return 2 `to` values', () => {
const options = {
from: 'USD',
to: ['CHF', 'GBP'],
base: 'EUR',
rates
};

const { result } = renderHook(() => useCurrency(200, options));

expect(result.current).toMatchObject({
chf: 192.85714285714286,
gbp: 164.28571428571428
});
});

it('should return value rounded to 2 places', () => {
const options = {
from: 'USD',
to: 'CHF',
base: 'EUR',
rates,
keepPrecision: false
};

const { result } = renderHook(() => useCurrency(200, options));

expect(result.current).toBe(192.86);
});

it('should return single `to` value from hook with the same `base` and `from` rates', () => {
const options = {
from: 'EUR',
to: 'CHF',
base: 'EUR',
rates
};

const { result } = renderHook(() => useCurrency(200, options));

expect(result.current).toBe(216);
});

it('should return single `to` value from hook with the same `base` and `to` rates', () => {
const options = {
from: 'USD',
to: 'CHF',
base: 'CHF',
rates
};

const { result } = renderHook(() => useCurrency(200, options));

expect(result.current).toBe(178.57142857142856);
});

it('should return single `to` value from hook without `base` rate', () => {
const options = {
from: 'USD',
to: 'CHF',
base: '',
rates
};

const { result } = renderHook(() => useCurrency(200, options));

expect(result.current).toBe(192.85714285714286);
});
});
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true
}
},
"exclude": ["test"]
}
Loading