diff --git a/package.json b/package.json
index e68a621af..a0e2fe745 100644
--- a/package.json
+++ b/package.json
@@ -196,6 +196,7 @@
"@storybook/core": "^5.3.14",
"@storybook/react": "^5.3.14",
"@storybook/storybook-deployer": "^2.8.1",
+ "@testing-library/react-hooks": "^3.2.1",
"addons-linter": "1.14.0",
"babel-eslint": "^10.0.2",
"babel-loader": "^8.0.6",
diff --git a/ui/app/components/app/user-preferenced-currency-display/index.js b/ui/app/components/app/user-preferenced-currency-display/index.js
index 0deddaecf..5bc2d4246 100644
--- a/ui/app/components/app/user-preferenced-currency-display/index.js
+++ b/ui/app/components/app/user-preferenced-currency-display/index.js
@@ -1 +1 @@
-export { default } from './user-preferenced-currency-display.container'
+export { default } from './user-preferenced-currency-display.component'
diff --git a/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js b/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js
index c8678e82b..d6145aae8 100644
--- a/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js
+++ b/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.component.test.js
@@ -3,9 +3,17 @@ import assert from 'assert'
import { shallow } from 'enzyme'
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display.component'
import CurrencyDisplay from '../../../ui/currency-display'
+import * as currencyHook from '../../../../hooks/useCurrencyDisplay'
+import * as currencyPrefHook from '../../../../hooks/useUserPreferencedCurrency'
+import sinon from 'sinon'
+
describe('UserPreferencedCurrencyDisplay Component', function () {
describe('rendering', function () {
+ beforeEach(function () {
+ sinon.stub(currencyHook, 'useCurrencyDisplay').returns(['1', {}])
+ sinon.stub(currencyPrefHook, 'useUserPreferencedCurrency').returns({ currency: 'ETH', decimals: 6 })
+ })
it('should render properly', function () {
const wrapper = shallow(
@@ -30,5 +38,8 @@ describe('UserPreferencedCurrencyDisplay Component', function () {
assert.equal(wrapper.find(CurrencyDisplay).props().prop2, 'test')
assert.equal(wrapper.find(CurrencyDisplay).props().prop3, 1)
})
+ afterEach(function () {
+ sinon.restore()
+ })
})
})
diff --git a/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js b/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js
deleted file mode 100644
index b0587e0b0..000000000
--- a/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js
+++ /dev/null
@@ -1,202 +0,0 @@
-import assert from 'assert'
-import proxyquire from 'proxyquire'
-
-let mapStateToProps, mergeProps
-
-proxyquire('../user-preferenced-currency-display.container.js', {
- 'react-redux': {
- connect: (ms, _, mp) => {
- mapStateToProps = ms
- mergeProps = mp
- return () => ({})
- },
- },
-})
-
-describe('UserPreferencedCurrencyDisplay container', function () {
- describe('mapStateToProps()', function () {
- it('should return the correct props', function () {
- const mockState = {
- metamask: {
- nativeCurrency: 'ETH',
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
- showFiatInTestnets: false,
- },
- provider: {
- type: 'mainnet',
- },
- },
- }
-
- assert.deepEqual(mapStateToProps(mockState), {
- nativeCurrency: 'ETH',
- useNativeCurrencyAsPrimaryCurrency: true,
- isMainnet: true,
- showFiatInTestnets: false,
- })
- })
-
- it('should return the correct props when not in mainnet and showFiatInTestnets is true', function () {
- const mockState = {
- metamask: {
- nativeCurrency: 'ETH',
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
- showFiatInTestnets: true,
- },
- provider: {
- type: 'rinkeby',
- },
- },
- }
-
- assert.deepEqual(mapStateToProps(mockState), {
- nativeCurrency: 'ETH',
- useNativeCurrencyAsPrimaryCurrency: true,
- isMainnet: false,
- showFiatInTestnets: true,
- })
- })
- })
-
- describe('mergeProps()', function () {
- it('should return the correct props', function () {
- const mockDispatchProps = {}
-
- const tests = [
- {
- stateProps: {
- useNativeCurrencyAsPrimaryCurrency: true,
- nativeCurrency: 'ETH',
- isMainnet: true,
- showFiatInTestnets: false,
- },
- ownProps: {
- type: 'PRIMARY',
- },
- result: {
- currency: 'ETH',
- nativeCurrency: 'ETH',
- numberOfDecimals: 6,
- prefix: undefined,
- },
- },
- {
- stateProps: {
- useNativeCurrencyAsPrimaryCurrency: false,
- nativeCurrency: 'ETH',
- isMainnet: true,
- showFiatInTestnets: false,
- },
- ownProps: {
- type: 'PRIMARY',
- },
- result: {
- currency: undefined,
- nativeCurrency: 'ETH',
- numberOfDecimals: 2,
- prefix: undefined,
- },
- },
- {
- stateProps: {
- useNativeCurrencyAsPrimaryCurrency: true,
- nativeCurrency: 'ETH',
- isMainnet: true,
- showFiatInTestnets: false,
- },
- ownProps: {
- type: 'SECONDARY',
- fiatNumberOfDecimals: 4,
- fiatPrefix: '-',
- },
- result: {
- nativeCurrency: 'ETH',
- currency: undefined,
- numberOfDecimals: 4,
- prefix: '-',
- },
- },
- {
- stateProps: {
- useNativeCurrencyAsPrimaryCurrency: false,
- nativeCurrency: 'ETH',
- isMainnet: true,
- showFiatInTestnets: false,
- },
- ownProps: {
- type: 'SECONDARY',
- fiatNumberOfDecimals: 4,
- numberOfDecimals: 3,
- fiatPrefix: 'a',
- prefix: 'b',
- },
- result: {
- currency: 'ETH',
- nativeCurrency: 'ETH',
- numberOfDecimals: 3,
- prefix: 'b',
- },
- },
- {
- stateProps: {
- useNativeCurrencyAsPrimaryCurrency: false,
- nativeCurrency: 'ETH',
- isMainnet: false,
- showFiatInTestnets: false,
- },
- ownProps: {
- type: 'PRIMARY',
- },
- result: {
- currency: 'ETH',
- nativeCurrency: 'ETH',
- numberOfDecimals: 6,
- prefix: undefined,
- },
- },
- {
- stateProps: {
- useNativeCurrencyAsPrimaryCurrency: false,
- nativeCurrency: 'ETH',
- isMainnet: false,
- showFiatInTestnets: true,
- },
- ownProps: {
- type: 'PRIMARY',
- },
- result: {
- currency: undefined,
- nativeCurrency: 'ETH',
- numberOfDecimals: 2,
- prefix: undefined,
- },
- },
- {
- stateProps: {
- useNativeCurrencyAsPrimaryCurrency: false,
- nativeCurrency: 'ETH',
- isMainnet: true,
- showFiatInTestnets: true,
- },
- ownProps: {
- type: 'PRIMARY',
- },
- result: {
- currency: undefined,
- nativeCurrency: 'ETH',
- numberOfDecimals: 2,
- prefix: undefined,
- },
- },
- ]
-
- tests.forEach(({ stateProps, ownProps, result }) => {
- assert.deepEqual(mergeProps({ ...stateProps }, mockDispatchProps, { ...ownProps }), {
- ...result,
- })
- })
- })
- })
-})
diff --git a/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js b/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js
index 4b64b26c0..b26f1eef4 100644
--- a/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js
+++ b/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js
@@ -1,47 +1,42 @@
-import React, { PureComponent } from 'react'
+import React, { useMemo } from 'react'
import PropTypes from 'prop-types'
import { PRIMARY, SECONDARY, ETH } from '../../../helpers/constants/common'
import CurrencyDisplay from '../../ui/currency-display'
+import { useUserPreferencedCurrency } from '../../../hooks/useUserPreferencedCurrency'
-export default class UserPreferencedCurrencyDisplay extends PureComponent {
- static propTypes = {
- className: PropTypes.string,
- prefix: PropTypes.string,
- value: PropTypes.string,
- numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- hideLabel: PropTypes.bool,
- hideTitle: PropTypes.bool,
- style: PropTypes.object,
- showEthLogo: PropTypes.bool,
- ethLogoHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- // Used in container
- type: PropTypes.oneOf([PRIMARY, SECONDARY]),
- ethNumberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- fiatNumberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- ethPrefix: PropTypes.string,
- fiatPrefix: PropTypes.string,
- // From container
- currency: PropTypes.string,
- nativeCurrency: PropTypes.string,
- }
-
- renderEthLogo () {
- const { currency, showEthLogo, ethLogoHeight = 12 } = this.props
+export default function UserPreferencedCurrencyDisplay ({ type, showEthLogo, ethLogoHeight = 12, ethNumberOfDecimals, fiatNumberOfDecimals, numberOfDecimals: propsNumberOfDecimals, ...restProps }) {
+ const { currency, numberOfDecimals } = useUserPreferencedCurrency(type, { ethNumberOfDecimals, fiatNumberOfDecimals, numberOfDecimals: propsNumberOfDecimals })
+ const prefixComponent = useMemo(() => {
return currency === ETH && showEthLogo && (
)
- }
+ }, [currency, showEthLogo, ethLogoHeight])
- render () {
- return (
-
- )
- }
+ return (
+
+ )
+}
+
+UserPreferencedCurrencyDisplay.propTypes = {
+ className: PropTypes.string,
+ prefix: PropTypes.string,
+ value: PropTypes.string,
+ numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ hideLabel: PropTypes.bool,
+ hideTitle: PropTypes.bool,
+ style: PropTypes.object,
+ showEthLogo: PropTypes.bool,
+ ethLogoHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ type: PropTypes.oneOf([PRIMARY, SECONDARY]),
+ ethNumberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ fiatNumberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
}
diff --git a/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.container.js b/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.container.js
deleted file mode 100644
index b94bec6d1..000000000
--- a/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.container.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { connect } from 'react-redux'
-import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display.component'
-import { preferencesSelector, getIsMainnet } from '../../../selectors'
-import { ETH, PRIMARY, SECONDARY } from '../../../helpers/constants/common'
-
-const mapStateToProps = (state) => {
- const {
- useNativeCurrencyAsPrimaryCurrency,
- showFiatInTestnets,
- } = preferencesSelector(state)
-
- const isMainnet = getIsMainnet(state)
-
- return {
- useNativeCurrencyAsPrimaryCurrency,
- showFiatInTestnets,
- isMainnet,
- nativeCurrency: state.metamask.nativeCurrency,
- }
-}
-
-const mergeProps = (stateProps, dispatchProps, ownProps) => {
- const { useNativeCurrencyAsPrimaryCurrency, showFiatInTestnets, isMainnet, nativeCurrency, ...restStateProps } = stateProps
- const {
- type,
- numberOfDecimals: propsNumberOfDecimals,
- ethNumberOfDecimals,
- fiatNumberOfDecimals,
- ethPrefix,
- fiatPrefix,
- prefix: propsPrefix,
- ...restOwnProps
- } = ownProps
-
- let currency, numberOfDecimals, prefix
-
- if ((type === PRIMARY && useNativeCurrencyAsPrimaryCurrency) ||
- (type === SECONDARY && !useNativeCurrencyAsPrimaryCurrency)) {
- // Display ETH
- currency = nativeCurrency || ETH
- numberOfDecimals = propsNumberOfDecimals || ethNumberOfDecimals || 6
- prefix = propsPrefix || ethPrefix
- } else if ((type === SECONDARY && useNativeCurrencyAsPrimaryCurrency) ||
- (type === PRIMARY && !useNativeCurrencyAsPrimaryCurrency)) {
- // Display Fiat
- numberOfDecimals = propsNumberOfDecimals || fiatNumberOfDecimals || 2
- prefix = propsPrefix || fiatPrefix
- }
-
- if (!isMainnet && !showFiatInTestnets) {
- currency = nativeCurrency || ETH
- numberOfDecimals = propsNumberOfDecimals || ethNumberOfDecimals || 6
- prefix = propsPrefix || ethPrefix
- }
-
- return {
- ...restStateProps,
- ...dispatchProps,
- ...restOwnProps,
- nativeCurrency,
- currency,
- numberOfDecimals,
- prefix,
- }
-}
-
-export default connect(mapStateToProps, null, mergeProps)(UserPreferencedCurrencyDisplay)
diff --git a/ui/app/components/ui/currency-display/currency-display.component.js b/ui/app/components/ui/currency-display/currency-display.component.js
index da70191c1..5b6311b6a 100644
--- a/ui/app/components/ui/currency-display/currency-display.component.js
+++ b/ui/app/components/ui/currency-display/currency-display.component.js
@@ -1,40 +1,62 @@
-import React, { PureComponent } from 'react'
+import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
+import { GWEI } from '../../../helpers/constants/common'
+import { useCurrencyDisplay } from '../../../hooks/useCurrencyDisplay'
-
-export default class CurrencyDisplay extends PureComponent {
- static propTypes = {
- className: PropTypes.string,
- displayValue: PropTypes.string,
- prefix: PropTypes.string,
- prefixComponent: PropTypes.node,
- style: PropTypes.object,
- suffix: PropTypes.string,
- hideTitle: PropTypes.bool,
- }
-
- render () {
- const { className, displayValue, prefix, prefixComponent, style, suffix, hideTitle } = this.props
- const text = `${prefix || ''}${displayValue}`
- const title = suffix ? `${text} ${suffix}` : text
-
- return (
-
- { prefixComponent }
- { text }
- {
- suffix && (
-
- { suffix }
-
- )
- }
-
- )
- }
+export default function CurrencyDisplay ({
+ value,
+ displayValue,
+ style,
+ className,
+ prefix,
+ prefixComponent,
+ hideLabel,
+ hideTitle,
+ numberOfDecimals,
+ denomination,
+ currency,
+ suffix,
+}) {
+ const [title, parts] = useCurrencyDisplay(value, {
+ displayValue,
+ prefix,
+ numberOfDecimals,
+ hideLabel,
+ denomination,
+ currency,
+ suffix,
+ })
+ return (
+
+ { prefixComponent }
+ { parts.prefix }{ parts.value }
+ {
+ parts.suffix && (
+
+ { parts.suffix }
+
+ )
+ }
+
+ )
+}
+
+CurrencyDisplay.propTypes = {
+ className: PropTypes.string,
+ currency: PropTypes.string,
+ denomination: PropTypes.oneOf([GWEI]),
+ displayValue: PropTypes.string,
+ hideLabel: PropTypes.bool,
+ hideTitle: PropTypes.bool,
+ numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ prefix: PropTypes.string,
+ prefixComponent: PropTypes.node,
+ style: PropTypes.object,
+ suffix: PropTypes.string,
+ value: PropTypes.string,
}
diff --git a/ui/app/components/ui/currency-display/currency-display.container.js b/ui/app/components/ui/currency-display/currency-display.container.js
deleted file mode 100644
index 30055e31b..000000000
--- a/ui/app/components/ui/currency-display/currency-display.container.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import { connect } from 'react-redux'
-import PropTypes from 'prop-types'
-import CurrencyDisplay from './currency-display.component'
-import { getValueFromWeiHex, formatCurrency } from '../../../helpers/utils/confirm-tx.util'
-import { GWEI } from '../../../helpers/constants/common'
-
-const mapStateToProps = (state) => {
- const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state
-
- return {
- currentCurrency,
- conversionRate,
- nativeCurrency,
- }
-}
-
-const mergeProps = (stateProps, _, ownProps) => {
- const { nativeCurrency, currentCurrency, conversionRate } = stateProps
- const {
- value,
- numberOfDecimals = 2,
- currency,
- denomination,
- hideLabel,
- displayValue: propsDisplayValue,
- suffix: propsSuffix,
- ...restOwnProps
- } = ownProps
-
- const toCurrency = currency || currentCurrency
-
- const displayValue = propsDisplayValue || formatCurrency(
- getValueFromWeiHex({
- value,
- fromCurrency: nativeCurrency,
- toCurrency, conversionRate,
- numberOfDecimals,
- toDenomination: denomination,
- }),
- toCurrency
- )
- const suffix = propsSuffix || (hideLabel ? undefined : toCurrency.toUpperCase())
-
- return {
- ...restOwnProps,
- displayValue,
- suffix,
- }
-}
-
-const CurrencyDisplayContainer = connect(mapStateToProps, null, mergeProps)(CurrencyDisplay)
-
-CurrencyDisplayContainer.propTypes = {
- className: PropTypes.string,
- currency: PropTypes.string,
- denomination: PropTypes.oneOf([GWEI]),
- displayValue: PropTypes.string,
- hideLabel: PropTypes.bool,
- hideTitle: PropTypes.bool,
- numberOfDecimals: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- prefix: PropTypes.string,
- prefixComponent: PropTypes.node,
- style: PropTypes.object,
- suffix: PropTypes.string,
- value: PropTypes.string,
-}
-
-export default CurrencyDisplayContainer
diff --git a/ui/app/components/ui/currency-display/index.js b/ui/app/components/ui/currency-display/index.js
index 38f08765f..f861bb91a 100644
--- a/ui/app/components/ui/currency-display/index.js
+++ b/ui/app/components/ui/currency-display/index.js
@@ -1 +1 @@
-export { default } from './currency-display.container'
+export { default } from './currency-display.component'
diff --git a/ui/app/components/ui/currency-display/tests/currency-display.component.test.js b/ui/app/components/ui/currency-display/tests/currency-display.component.test.js
index fd16401d7..862c160f8 100644
--- a/ui/app/components/ui/currency-display/tests/currency-display.component.test.js
+++ b/ui/app/components/ui/currency-display/tests/currency-display.component.test.js
@@ -2,13 +2,24 @@ import React from 'react'
import assert from 'assert'
import { shallow } from 'enzyme'
import CurrencyDisplay from '../currency-display.component'
+import sinon from 'sinon'
+import * as reactRedux from 'react-redux'
describe('CurrencyDisplay Component', function () {
+ beforeEach(function () {
+ const stub = sinon.stub(reactRedux, 'useSelector')
+ stub.callsFake(() => ({
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ conversionRate: 280.45,
+ }))
+ })
it('should render text with a className', function () {
const wrapper = shallow((
))
@@ -22,10 +33,14 @@ describe('CurrencyDisplay Component', function () {
displayValue="$123.45"
className="currency-display"
prefix="-"
+ hideLabel
/>
))
assert.ok(wrapper.hasClass('currency-display'))
assert.equal(wrapper.text(), '-$123.45')
})
+ afterEach(function () {
+ sinon.restore()
+ })
})
diff --git a/ui/app/components/ui/currency-display/tests/currency-display.container.test.js b/ui/app/components/ui/currency-display/tests/currency-display.container.test.js
deleted file mode 100644
index 905f04108..000000000
--- a/ui/app/components/ui/currency-display/tests/currency-display.container.test.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import assert from 'assert'
-import proxyquire from 'proxyquire'
-
-let mapStateToProps, mergeProps
-
-proxyquire('../currency-display.container.js', {
- 'react-redux': {
- connect: (ms, _, mp) => {
- mapStateToProps = ms
- mergeProps = mp
- return () => ({})
- },
- },
-})
-
-describe('CurrencyDisplay container', function () {
- describe('mapStateToProps()', function () {
- it('should return the correct props', function () {
- const mockState = {
- metamask: {
- conversionRate: 280.45,
- currentCurrency: 'usd',
- nativeCurrency: 'ETH',
- },
- }
-
- assert.deepEqual(mapStateToProps(mockState), {
- conversionRate: 280.45,
- currentCurrency: 'usd',
- nativeCurrency: 'ETH',
- })
- })
- })
-
- describe('mergeProps()', function () {
- it('should return the correct props', function () {
- const mockStateProps = {
- conversionRate: 280.45,
- currentCurrency: 'usd',
- nativeCurrency: 'ETH',
- }
-
- const tests = [
- {
- props: {
- value: '0x2386f26fc10000',
- numberOfDecimals: 2,
- currency: 'usd',
- nativeCurrency: 'ETH',
- },
- result: {
- displayValue: '$2.80',
- suffix: 'USD',
- nativeCurrency: 'ETH',
- },
- },
- {
- props: {
- value: '0x2386f26fc10000',
- currency: 'usd',
- nativeCurrency: 'ETH',
- },
- result: {
- displayValue: '$2.80',
- suffix: 'USD',
- nativeCurrency: 'ETH',
- },
- },
- {
- props: {
- value: '0x1193461d01595930',
- currency: 'ETH',
- nativeCurrency: 'ETH',
- numberOfDecimals: 3,
- },
- result: {
- displayValue: '1.266',
- suffix: 'ETH',
- nativeCurrency: 'ETH',
- },
- },
- {
- props: {
- value: '0x1193461d01595930',
- currency: 'ETH',
- nativeCurrency: 'ETH',
- numberOfDecimals: 3,
- hideLabel: true,
- },
- result: {
- nativeCurrency: 'ETH',
- displayValue: '1.266',
- suffix: undefined,
- },
- },
- {
- props: {
- value: '0x3b9aca00',
- currency: 'ETH',
- nativeCurrency: 'ETH',
- denomination: 'GWEI',
- hideLabel: true,
- },
- result: {
- nativeCurrency: 'ETH',
- displayValue: '1',
- suffix: undefined,
- },
- },
- {
- props: {
- value: '0x3b9aca00',
- currency: 'ETH',
- nativeCurrency: 'ETH',
- denomination: 'WEI',
- hideLabel: true,
- },
- result: {
- nativeCurrency: 'ETH',
- displayValue: '1000000000',
- suffix: undefined,
- },
- },
- {
- props: {
- value: '0x3b9aca00',
- currency: 'ETH',
- nativeCurrency: 'ETH',
- numberOfDecimals: 100,
- hideLabel: true,
- },
- result: {
- nativeCurrency: 'ETH',
- displayValue: '0.000000001',
- suffix: undefined,
- },
- },
- ]
-
- tests.forEach(({ props, result }) => {
- assert.deepEqual(mergeProps(mockStateProps, {}, { ...props }), result)
- })
- })
- })
-})
diff --git a/ui/app/components/ui/token-currency-display/token-currency-display.component.js b/ui/app/components/ui/token-currency-display/token-currency-display.component.js
index 3c2722b36..b8e46614a 100644
--- a/ui/app/components/ui/token-currency-display/token-currency-display.component.js
+++ b/ui/app/components/ui/token-currency-display/token-currency-display.component.js
@@ -1,57 +1,24 @@
-import React, { PureComponent } from 'react'
+import React from 'react'
import PropTypes from 'prop-types'
import CurrencyDisplay from '../currency-display'
-import { getTokenData } from '../../../helpers/utils/transactions.util'
-import { getTokenValue, calcTokenAmount } from '../../../helpers/utils/token-util'
+import { useTokenDisplayValue } from '../../../hooks/useTokenDisplayValue'
-export default class TokenCurrencyDisplay extends PureComponent {
- static propTypes = {
- transactionData: PropTypes.string,
- token: PropTypes.object,
- }
+export default function TokenCurrencyDisplay ({ className, transactionData, token, prefix }) {
+ const displayValue = useTokenDisplayValue(transactionData, token)
- state = {
- displayValue: '',
- suffix: '',
- }
-
- componentDidMount () {
- this.setDisplayValue()
- }
-
- componentDidUpdate (prevProps) {
- const { transactionData } = this.props
- const { transactionData: prevTransactionData } = prevProps
-
- if (transactionData !== prevTransactionData) {
- this.setDisplayValue()
- }
- }
-
- setDisplayValue () {
- const { transactionData: data, token } = this.props
- const { decimals = '', symbol: suffix = '' } = token
- const tokenData = getTokenData(data)
-
- let displayValue
-
- if (tokenData && tokenData.params && tokenData.params.length) {
- const tokenValue = getTokenValue(tokenData.params)
- displayValue = calcTokenAmount(tokenValue, decimals).toString()
- }
-
- this.setState({ displayValue, suffix })
- }
-
- render () {
- const { displayValue, suffix } = this.state
-
- return (
-
- )
- }
+ return (
+
+ )
+}
+
+TokenCurrencyDisplay.propTypes = {
+ className: PropTypes.string,
+ transactionData: PropTypes.string,
+ token: PropTypes.object,
+ prefix: PropTypes.string,
}
diff --git a/ui/app/hooks/tests/useCurrencyDisplay.test.js b/ui/app/hooks/tests/useCurrencyDisplay.test.js
new file mode 100644
index 000000000..98116fa3d
--- /dev/null
+++ b/ui/app/hooks/tests/useCurrencyDisplay.test.js
@@ -0,0 +1,121 @@
+import assert from 'assert'
+import { renderHook } from '@testing-library/react-hooks'
+import * as reactRedux from 'react-redux'
+import { useCurrencyDisplay } from '../useCurrencyDisplay'
+import sinon from 'sinon'
+
+const tests = [
+ {
+ input: {
+ value: '0x2386f26fc10000',
+ numberOfDecimals: 2,
+ currency: 'usd',
+ },
+ result: {
+ value: '$2.80',
+ suffix: 'USD',
+ displayValue: '$2.80 USD',
+ },
+ },
+ {
+ input: {
+ value: '0x2386f26fc10000',
+ currency: 'usd',
+ },
+ result: {
+ value: '$2.80',
+ suffix: 'USD',
+ displayValue: '$2.80 USD',
+ },
+ },
+ {
+ input: {
+ value: '0x1193461d01595930',
+ currency: 'ETH',
+ numberOfDecimals: 3,
+ },
+ result: {
+ value: '1.266',
+ suffix: 'ETH',
+ displayValue: '1.266 ETH',
+ },
+ },
+ {
+ input: {
+ value: '0x1193461d01595930',
+ currency: 'ETH',
+ numberOfDecimals: 3,
+ hideLabel: true,
+ },
+ result: {
+ value: '1.266',
+ suffix: undefined,
+ displayValue: '1.266',
+ },
+ },
+ {
+ input: {
+ value: '0x3b9aca00',
+ currency: 'ETH',
+ denomination: 'GWEI',
+ hideLabel: true,
+ },
+ result: {
+ value: '1',
+ suffix: undefined,
+ displayValue: '1',
+ },
+ },
+ {
+ input: {
+ value: '0x3b9aca00',
+ currency: 'ETH',
+ denomination: 'WEI',
+ hideLabel: true,
+ },
+ result: {
+ value: '1000000000',
+ suffix: undefined,
+ displayValue: '1000000000',
+ },
+ },
+ {
+ input: {
+ value: '0x3b9aca00',
+ currency: 'ETH',
+ numberOfDecimals: 100,
+ hideLabel: true,
+ },
+ result: {
+ value: '0.000000001',
+ suffix: undefined,
+ displayValue: '0.000000001',
+ },
+ },
+]
+
+
+describe('useCurrencyDisplay', function () {
+ tests.forEach(({ input: { value, ...restProps }, result }) => {
+ describe(`when input is { value: ${value}, decimals: ${restProps.numberOfDecimals}, denomation: ${restProps.denomination} }`, function () {
+ const stub = sinon.stub(reactRedux, 'useSelector')
+ stub.callsFake(() => ({
+ currentCurrency: 'usd',
+ nativeCurrency: 'ETH',
+ conversionRate: 280.45,
+ }))
+ const hookReturn = renderHook(() => useCurrencyDisplay(value, restProps))
+ const [ displayValue, parts ] = hookReturn.result.current
+ stub.restore()
+ it(`should return ${result.displayValue} as displayValue`, function () {
+ assert.equal(displayValue, result.displayValue)
+ })
+ it(`should return ${result.value} as value`, function () {
+ assert.equal(parts.value, result.value)
+ })
+ it(`should return ${result.suffix} as suffix`, function () {
+ assert.equal(parts.suffix, result.suffix)
+ })
+ })
+ })
+})
diff --git a/ui/app/hooks/tests/useTokenDisplayValue.test.js b/ui/app/hooks/tests/useTokenDisplayValue.test.js
new file mode 100644
index 000000000..bb8464f8a
--- /dev/null
+++ b/ui/app/hooks/tests/useTokenDisplayValue.test.js
@@ -0,0 +1,136 @@
+import assert from 'assert'
+import { renderHook } from '@testing-library/react-hooks'
+import * as tokenUtil from '../../helpers/utils/token-util'
+import * as txUtil from '../../helpers/utils/transactions.util'
+import { useTokenDisplayValue } from '../useTokenDisplayValue'
+import sinon from 'sinon'
+
+const tests = [
+ {
+ token: {
+ symbol: 'DAI',
+ decimals: 18,
+ },
+ tokenData: {
+ params: 'decoded-params1',
+ },
+ tokenValue: '1000000000000000000',
+ displayValue: '1',
+ },
+ {
+ token: {
+ symbol: 'DAI',
+ decimals: 18,
+ },
+ tokenData: {
+ params: 'decoded-params2',
+ },
+ tokenValue: '10000000000000000000',
+ displayValue: '10',
+ },
+ {
+ token: {
+ symbol: 'DAI',
+ decimals: 18,
+ },
+ tokenData: {
+ params: 'decoded-params3',
+ },
+ tokenValue: '1500000000000000000',
+ displayValue: '1.5',
+ },
+ {
+ token: {
+ symbol: 'DAI',
+ decimals: 18,
+ },
+ tokenData: {
+ params: 'decoded-params4',
+ },
+ tokenValue: '1756000000000000000',
+ displayValue: '1.756',
+ },
+ {
+ token: {
+ symbol: 'DAI',
+ decimals: 18,
+ },
+ tokenData: {
+ params: 'decoded-params5',
+ },
+ tokenValue: '25500000000000000000',
+ displayValue: '25.5',
+ },
+ {
+ token: {
+ symbol: 'USDC',
+ decimals: 6,
+ },
+ tokenData: {
+ params: 'decoded-params6',
+ },
+ tokenValue: '1000000',
+ displayValue: '1',
+ },
+ {
+ token: {
+ symbol: 'USDC',
+ decimals: 6,
+ },
+ tokenData: {
+ params: 'decoded-params7',
+ },
+ tokenValue: '10000000',
+ displayValue: '10',
+ },
+ {
+ token: {
+ symbol: 'USDC',
+ decimals: 6,
+ },
+ tokenData: {
+ params: 'decoded-params8',
+ },
+ tokenValue: '1500000',
+ displayValue: '1.5',
+ },
+ {
+ token: {
+ symbol: 'USDC',
+ decimals: 6,
+ },
+ tokenData: {
+ params: 'decoded-params9',
+ },
+ tokenValue: '1756000',
+ displayValue: '1.756',
+ },
+ {
+ token: {
+ symbol: 'USDC',
+ decimals: 6,
+ },
+ tokenData: {
+ params: 'decoded-params10',
+ },
+ tokenValue: '25500000',
+ displayValue: '25.5',
+ },
+]
+
+
+describe('useTokenDisplayValue', function () {
+ tests.forEach((test, idx) => {
+ describe(`when input is decimals: ${test.token.decimals} and value: ${test.tokenValue}`, function () {
+ it(`should return ${test.displayValue} as displayValue`, function () {
+ const getTokenValueStub = sinon.stub(tokenUtil, 'getTokenValue')
+ const getTokenDataStub = sinon.stub(txUtil, 'getTokenData')
+ getTokenDataStub.callsFake(() => test.tokenData)
+ getTokenValueStub.callsFake(() => test.tokenValue)
+ const { result } = renderHook(() => useTokenDisplayValue(`${idx}-fakestring`, test.token))
+ sinon.restore()
+ assert.equal(result.current, test.displayValue)
+ })
+ })
+ })
+})
diff --git a/ui/app/hooks/tests/useUserPreferencedCurrency.test.js b/ui/app/hooks/tests/useUserPreferencedCurrency.test.js
new file mode 100644
index 000000000..c984fa0d8
--- /dev/null
+++ b/ui/app/hooks/tests/useUserPreferencedCurrency.test.js
@@ -0,0 +1,143 @@
+import assert from 'assert'
+import { renderHook } from '@testing-library/react-hooks'
+import { useUserPreferencedCurrency } from '../useUserPreferencedCurrency'
+import * as reactRedux from 'react-redux'
+import { preferencesSelector, getShouldShowFiat } from '../../selectors'
+import sinon from 'sinon'
+
+const tests = [
+ {
+ state: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ nativeCurrency: 'ETH',
+ showFiat: true,
+ },
+ params: {
+ type: 'PRIMARY',
+ },
+ result: {
+ currency: 'ETH',
+ numberOfDecimals: 6,
+ },
+ },
+ {
+ state: {
+ useNativeCurrencyAsPrimaryCurrency: false,
+ nativeCurrency: 'ETH',
+ showFiat: true,
+ },
+ params: {
+ type: 'PRIMARY',
+ },
+ result: {
+ currency: undefined,
+ numberOfDecimals: 2,
+ },
+ },
+ {
+ state: {
+ useNativeCurrencyAsPrimaryCurrency: true,
+ nativeCurrency: 'ETH',
+ showFiat: true,
+ },
+ params: {
+ type: 'SECONDARY',
+ fiatNumberOfDecimals: 4,
+ fiatPrefix: '-',
+ },
+ result: {
+ currency: undefined,
+ numberOfDecimals: 4,
+ },
+ },
+ {
+ state: {
+ useNativeCurrencyAsPrimaryCurrency: false,
+ nativeCurrency: 'ETH',
+ showFiat: true,
+ },
+ params: {
+ type: 'SECONDARY',
+ fiatNumberOfDecimals: 4,
+ numberOfDecimals: 3,
+ fiatPrefix: 'a',
+ },
+ result: {
+ currency: 'ETH',
+ numberOfDecimals: 3,
+ },
+ },
+ {
+ state: {
+ useNativeCurrencyAsPrimaryCurrency: false,
+ nativeCurrency: 'ETH',
+ showFiat: false,
+ },
+ params: {
+ type: 'PRIMARY',
+ },
+ result: {
+ currency: 'ETH',
+ numberOfDecimals: 6,
+ },
+ },
+ {
+ state: {
+ useNativeCurrencyAsPrimaryCurrency: false,
+ nativeCurrency: 'ETH',
+ showFiat: true,
+ },
+ params: {
+ type: 'PRIMARY',
+ },
+ result: {
+ currency: undefined,
+ numberOfDecimals: 2,
+ },
+ },
+ {
+ state: {
+ useNativeCurrencyAsPrimaryCurrency: false,
+ nativeCurrency: 'ETH',
+ showFiat: true,
+ },
+ params: {
+ type: 'PRIMARY',
+ },
+ result: {
+ currency: undefined,
+ numberOfDecimals: 2,
+ },
+ },
+]
+
+function getFakeUseSelector (state) {
+ return (selector) => {
+ if (selector === preferencesSelector) {
+ return state
+ } else if (selector === getShouldShowFiat) {
+ return state.showFiat
+ } else {
+ return state.nativeCurrency
+ }
+ }
+}
+
+
+describe('useUserPreferencedCurrency', function () {
+ tests.forEach(({ params: { type, ...otherParams }, state, result }) => {
+ describe(`when showFiat is ${state.showFiat}, useNativeCurrencyAsPrimary is ${state.useNativeCurrencyAsPrimaryCurrency} and type is ${type}`, function () {
+ const stub = sinon.stub(reactRedux, 'useSelector')
+ stub.callsFake(getFakeUseSelector(state))
+
+ const { result: hookResult } = renderHook(() => useUserPreferencedCurrency(type, otherParams))
+ stub.restore()
+ it(`should return currency as ${result.currency || 'not modified by user preferences'}`, function () {
+ assert.equal(hookResult.current.currency, result.currency)
+ })
+ it(`should return decimals as ${result.numberOfDecimals || 'not modified by user preferences'}`, function () {
+ assert.equal(hookResult.current.numberOfDecimals, result.numberOfDecimals)
+ })
+ })
+ })
+})
diff --git a/ui/app/hooks/useCurrencyDisplay.js b/ui/app/hooks/useCurrencyDisplay.js
new file mode 100644
index 000000000..e00d328a6
--- /dev/null
+++ b/ui/app/hooks/useCurrencyDisplay.js
@@ -0,0 +1,69 @@
+import { useMemo } from 'react'
+import { useSelector } from 'react-redux'
+import { formatCurrency, getValueFromWeiHex } from '../helpers/utils/confirm-tx.util'
+
+/**
+ * Defines the shape of the options parameter for useCurrencyDisplay
+ * @typedef {Object} UseCurrencyOptions
+ * @property {string} [displayValue] - When present is used in lieu of formatting the inputValue
+ * @property {string} [prefix] - String to prepend to the final result
+ * @property {number} [numberOfDecimals] - Number of significant decimals to display
+ * @property {string} [denomination] - Denomination (wei, gwei) to convert to for display
+ * @property {string} [currency] - Currency type to convert to. Will override nativeCurrency
+ */
+
+/**
+ * Defines the return shape of the second value in the tuple
+ * @typedef {Object} CurrencyDisplayParts
+ * @property {string} [prefix] - string to prepend to the value for display
+ * @property {string} value - string representing the value, formatted for display
+ * @property {string} [suffix] - string to append to the value for display
+ */
+
+/**
+ * useCurrencyDisplay hook
+ *
+ * Given a hexadecimal encoded value string and an object of parameters used for formatting the
+ * display, produce both a fully formed string and the pieces of that string used for displaying
+ * the currency to the user
+ * @param {string} inputValue - The value to format for display
+ * @param {UseCurrencyOptions} opts - An object for options to format the inputValue
+ * @return {[string, CurrencyDisplayParts]}
+ */
+export function useCurrencyDisplay (inputValue, { displayValue, prefix, numberOfDecimals, denomination, currency, ...opts }) {
+ const { currentCurrency, nativeCurrency, conversionRate } = useSelector(
+ ({ metamask: { currentCurrency, nativeCurrency, conversionRate } }) => ({
+ currentCurrency,
+ nativeCurrency,
+ conversionRate,
+ })
+ )
+
+ const toCurrency = currency || currentCurrency
+
+ const value = useMemo(() => {
+ if (displayValue) {
+ return displayValue
+ }
+ return formatCurrency(
+ getValueFromWeiHex({
+ value: inputValue,
+ fromCurrency: nativeCurrency,
+ toCurrency,
+ conversionRate,
+ numberOfDecimals: numberOfDecimals || 2,
+ toDenomination: denomination,
+ }),
+ toCurrency
+ )
+ }, [inputValue, nativeCurrency, conversionRate, displayValue, numberOfDecimals, denomination, toCurrency])
+
+ let suffix
+
+ if (!opts.hideLabel) {
+ suffix = opts.suffix || toCurrency.toUpperCase()
+ }
+
+
+ return [`${prefix || ''}${value}${suffix ? ' ' + suffix : ''}`, { prefix, value, suffix }]
+}
diff --git a/ui/app/hooks/useTokenDisplayValue.js b/ui/app/hooks/useTokenDisplayValue.js
new file mode 100644
index 000000000..eea71f68a
--- /dev/null
+++ b/ui/app/hooks/useTokenDisplayValue.js
@@ -0,0 +1,38 @@
+import { getTokenValue, calcTokenAmount } from '../helpers/utils/token-util'
+import { getTokenData } from '../helpers/utils/transactions.util'
+import { useMemo } from 'react'
+
+/**
+ * Defines the shape for the Token input parameter for useTokenDisplayValue
+ * @typedef {Object} Token
+ * @property {string} symbol - The string to use as a suffix for the token (eg. DAI)
+ * @property {number} decimals - The number of decimals to show when displaying this type of token
+ */
+
+/**
+ * useTokenDisplayValue
+ * Given the data string from txParams and a token object with symbol and decimals, return
+ * a displayValue that represents a string representing that token amount as a string. Also
+ * return a tokenData object for downstream usage and the suffix for the token to use as props
+ * for other hooks and/or components
+ * @param {string} transactionData
+ * @param {Token} token
+ * @return {string} - The computed displayValue of the provided transactionData and token
+ */
+export function useTokenDisplayValue (transactionData, token) {
+ if (!transactionData || !token) {
+ return null
+ }
+ const tokenData = useMemo(() => getTokenData(transactionData), [transactionData])
+ if (!tokenData?.params?.length) {
+ return null
+ }
+ const { decimals } = token
+
+ const displayValue = useMemo(() => {
+ const tokenValue = getTokenValue(tokenData.params)
+ return calcTokenAmount(tokenValue, decimals).toString()
+ }, [tokenData, decimals])
+
+ return displayValue
+}
diff --git a/ui/app/hooks/useUserPreferencedCurrency.js b/ui/app/hooks/useUserPreferencedCurrency.js
new file mode 100644
index 000000000..8bd7f0e46
--- /dev/null
+++ b/ui/app/hooks/useUserPreferencedCurrency.js
@@ -0,0 +1,52 @@
+import { preferencesSelector, getShouldShowFiat } from '../selectors'
+import { useSelector } from 'react-redux'
+import { PRIMARY, SECONDARY, ETH } from '../helpers/constants/common'
+
+/**
+ * Defines the shape of the options parameter for useUserPreferencedCurrency
+ * @typedef {Object} UseUserPreferencedCurrencyOptions
+ * @property {number} [numberOfDecimals] - Number of significant decimals to display
+ * @property {number} [ethNumberOfDecimals] - Number of significant decimals to display
+ * when using ETH
+ * @property {number} [fiatNumberOfDecimals] - Number of significant decimals to display
+ * when using fiat
+ */
+
+/**
+ * Defines the return shape of useUserPreferencedCurrency
+ * @typedef {Object} UserPreferredCurrency
+ * @property {string} currency - the currency type to use (eg: 'ETH', 'usd')
+ * @property {number} numberOfDecimals - Number of significant decimals to display
+ */
+
+/**
+ * useUserPreferencedCurrency
+ *
+ * returns an object that contains what currency to use for displaying values based
+ * on the user's preference settings, as well as the significant number of decimals
+ * to display based on the currency
+ * @param {"PRIMARY" | "SECONDARY"} type - what display type is being rendered
+ * @param {UseUserPreferencedCurrencyOptions} opts - options to override default values
+ * @return {UserPreferredCurrency}
+ */
+export function useUserPreferencedCurrency (type, opts = {}) {
+ const nativeCurrency = useSelector((state) => state.metamask.nativeCurrency)
+ const {
+ useNativeCurrencyAsPrimaryCurrency,
+ } = useSelector(preferencesSelector)
+ const showFiat = useSelector(getShouldShowFiat)
+
+ let currency, numberOfDecimals
+ if (!showFiat || (type === PRIMARY && useNativeCurrencyAsPrimaryCurrency) ||
+ (type === SECONDARY && !useNativeCurrencyAsPrimaryCurrency)) {
+ // Display ETH
+ currency = nativeCurrency || ETH
+ numberOfDecimals = opts.numberOfDecimals || opts.ethNumberOfDecimals || 6
+ } else if ((type === SECONDARY && useNativeCurrencyAsPrimaryCurrency) ||
+ (type === PRIMARY && !useNativeCurrencyAsPrimaryCurrency)) {
+ // Display Fiat
+ numberOfDecimals = opts.numberOfDecimals || opts.fiatNumberOfDecimals || 2
+ }
+
+ return { currency, numberOfDecimals }
+}
diff --git a/ui/app/pages/permissions-connect/choose-account/choose-account.component.js b/ui/app/pages/permissions-connect/choose-account/choose-account.component.js
index 3758d556b..515914304 100644
--- a/ui/app/pages/permissions-connect/choose-account/choose-account.component.js
+++ b/ui/app/pages/permissions-connect/choose-account/choose-account.component.js
@@ -104,7 +104,6 @@ export default class ChooseAccount extends Component {
value={balance}
style={{ color: '#6A737D' }}
suffix={nativeCurrency}
- hideLabel
/>
diff --git a/ui/app/selectors/selectors.js b/ui/app/selectors/selectors.js
index 952a5a94b..891414e46 100644
--- a/ui/app/selectors/selectors.js
+++ b/ui/app/selectors/selectors.js
@@ -285,6 +285,12 @@ export function preferencesSelector ({ metamask }) {
return metamask.preferences
}
+export function getShouldShowFiat (state) {
+ const isMainNet = getIsMainnet(state)
+ const { showFiatInTestnets } = preferencesSelector(state)
+ return isMainNet || showFiatInTestnets
+}
+
export function getAdvancedInlineGasShown (state) {
return Boolean(state.metamask.featureFlags.advancedInlineGas)
}
diff --git a/yarn.lock b/yarn.lock
index 262c67bcc..14249d9a1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1088,6 +1088,13 @@
dependencies:
regenerator-runtime "^0.13.2"
+"@babel/runtime@^7.5.4":
+ version "7.9.6"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f"
+ integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
"@babel/runtime@^7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
@@ -2653,6 +2660,14 @@
dependencies:
defer-to-connect "^1.0.1"
+"@testing-library/react-hooks@^3.2.1":
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-3.2.1.tgz#19b6caa048ef15faa69d439c469033873ea01294"
+ integrity sha512-1OB6Ksvlk6BCJA1xpj8/WWz0XVd1qRcgqdaFAq+xeC6l61Ucj0P6QpA5u+Db/x9gU4DCX8ziR5b66Mlfg0M2RA==
+ dependencies:
+ "@babel/runtime" "^7.5.4"
+ "@types/testing-library__react-hooks" "^3.0.0"
+
"@types/babel__core@^7.1.0":
version "7.1.3"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30"
@@ -2839,6 +2854,13 @@
dependencies:
"@types/react" "*"
+"@types/react-test-renderer@*":
+ version "16.9.2"
+ resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.2.tgz#e1c408831e8183e5ad748fdece02214a7c2ab6c5"
+ integrity sha512-4eJr1JFLIAlWhzDkBCkhrOIWOvOxcCAfQh+jiKg7l/nNZcCIL2MHl2dZhogIFKyHzedVWHaVP1Yydq/Ruu4agw==
+ dependencies:
+ "@types/react" "*"
+
"@types/react-textarea-autosize@^4.3.3":
version "4.3.5"
resolved "https://registry.yarnpkg.com/@types/react-textarea-autosize/-/react-textarea-autosize-4.3.5.tgz#6c4d2753fa1864c98c0b2b517f67bb1f6e4c46de"
@@ -2872,6 +2894,14 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
+"@types/testing-library__react-hooks@^3.0.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@types/testing-library__react-hooks/-/testing-library__react-hooks-3.2.0.tgz#52f3a109bef06080e3b1e3ae7ea1c014ce859897"
+ integrity sha512-dE8iMTuR5lzB+MqnxlzORlXzXyCL0EKfzH0w/lau20OpkHD37EaWjZDz0iNG8b71iEtxT4XKGmSKAGVEqk46mw==
+ dependencies:
+ "@types/react" "*"
+ "@types/react-test-renderer" "*"
+
"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
@@ -23991,6 +24021,11 @@ regenerator-runtime@^0.13.2:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
+regenerator-runtime@^0.13.4:
+ version "0.13.5"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
+ integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
+
regenerator-transform@^0.10.0:
version "0.10.1"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"