aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorChi Kei Chan <chikeichan@gmail.com>2019-02-06 23:14:17 +0800
committerWhymarrh Whitby <whymarrh.whitby@gmail.com>2019-02-06 23:14:17 +0800
commit798930afbaa01d691059db1cec4caf12414493b9 (patch)
treee39377ef7ddcac23afe6698996f8bcbff79b79e8 /ui
parent83109c3dc7fbb3e89c047363ec3baeac4df99f77 (diff)
downloadtangerine-wallet-browser-798930afbaa01d691059db1cec4caf12414493b9.tar
tangerine-wallet-browser-798930afbaa01d691059db1cec4caf12414493b9.tar.gz
tangerine-wallet-browser-798930afbaa01d691059db1cec4caf12414493b9.tar.bz2
tangerine-wallet-browser-798930afbaa01d691059db1cec4caf12414493b9.tar.lz
tangerine-wallet-browser-798930afbaa01d691059db1cec4caf12414493b9.tar.xz
tangerine-wallet-browser-798930afbaa01d691059db1cec4caf12414493b9.tar.zst
tangerine-wallet-browser-798930afbaa01d691059db1cec4caf12414493b9.zip
Add Swap feature to CurrencyInput (#6091)
* Add Swap feature to CurrencyInput * Fix linter error * Fix and Add unit tests
Diffstat (limited to 'ui')
-rw-r--r--ui/app/components/currency-input/currency-input.component.js55
-rw-r--r--ui/app/components/currency-input/currency-input.container.js5
-rw-r--r--ui/app/components/currency-input/index.scss19
-rw-r--r--ui/app/components/currency-input/tests/currency-input.component.test.js60
-rw-r--r--ui/app/components/currency-input/tests/currency-input.container.test.js6
-rw-r--r--ui/app/components/unit-input/index.scss7
-rw-r--r--ui/app/components/unit-input/unit-input.component.js44
7 files changed, 151 insertions, 45 deletions
diff --git a/ui/app/components/currency-input/currency-input.component.js b/ui/app/components/currency-input/currency-input.component.js
index 0761a75c5..8fa3131ae 100644
--- a/ui/app/components/currency-input/currency-input.component.js
+++ b/ui/app/components/currency-input/currency-input.component.js
@@ -17,9 +17,10 @@ export default class CurrencyInput extends PureComponent {
nativeCurrency: PropTypes.string,
onChange: PropTypes.func,
onBlur: PropTypes.func,
- suffix: PropTypes.string,
useFiat: PropTypes.bool,
value: PropTypes.string,
+ fiatSuffix: PropTypes.string,
+ nativeSuffix: PropTypes.string,
}
constructor (props) {
@@ -31,6 +32,7 @@ export default class CurrencyInput extends PureComponent {
this.state = {
decimalValue,
hexValue,
+ isSwapped: false,
}
}
@@ -46,8 +48,8 @@ export default class CurrencyInput extends PureComponent {
}
getDecimalValue (props) {
- const { value: hexValue, useFiat, currentCurrency, conversionRate } = props
- const decimalValueString = useFiat
+ const { value: hexValue, currentCurrency, conversionRate } = props
+ const decimalValueString = this.shouldUseFiat()
? getValueFromWeiHex({
value: hexValue, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2,
})
@@ -58,10 +60,23 @@ export default class CurrencyInput extends PureComponent {
return Number(decimalValueString) || 0
}
+ shouldUseFiat = () => {
+ const { useFiat } = this.props
+ const { isSwapped } = this.state || {}
+ return isSwapped ? !useFiat : useFiat
+ }
+
+ swap = () => {
+ const { isSwapped, decimalValue } = this.state
+ this.setState({isSwapped: !isSwapped}, () => {
+ this.handleChange(decimalValue)
+ })
+ }
+
handleChange = decimalValue => {
- const { useFiat, currentCurrency: fromCurrency, conversionRate, onChange } = this.props
+ const { currentCurrency: fromCurrency, conversionRate, onChange } = this.props
- const hexValue = useFiat
+ const hexValue = this.shouldUseFiat()
? getWeiHexFromDecimalValue({
value: decimalValue, fromCurrency, conversionRate, invertConversionRate: true,
})
@@ -78,11 +93,11 @@ export default class CurrencyInput extends PureComponent {
}
renderConversionComponent () {
- const { useFiat, currentCurrency, nativeCurrency } = this.props
+ const { currentCurrency, nativeCurrency } = this.props
const { hexValue } = this.state
let currency, numberOfDecimals
- if (useFiat) {
+ if (this.shouldUseFiat()) {
// Display ETH
currency = nativeCurrency || ETH
numberOfDecimals = 6
@@ -103,19 +118,25 @@ export default class CurrencyInput extends PureComponent {
}
render () {
- const { suffix, ...restProps } = this.props
+ const { fiatSuffix, nativeSuffix, ...restProps } = this.props
const { decimalValue } = this.state
return (
- <UnitInput
- {...restProps}
- suffix={suffix}
- onChange={this.handleChange}
- onBlur={this.handleBlur}
- value={decimalValue}
- >
- { this.renderConversionComponent() }
- </UnitInput>
+ <UnitInput
+ {...restProps}
+ suffix={this.shouldUseFiat() ? fiatSuffix : nativeSuffix}
+ onChange={this.handleChange}
+ onBlur={this.handleBlur}
+ value={decimalValue}
+ actionComponent={(
+ <div
+ className="currency-input__swap-component"
+ onClick={this.swap}
+ />
+ )}
+ >
+ { this.renderConversionComponent() }
+ </UnitInput>
)
}
}
diff --git a/ui/app/components/currency-input/currency-input.container.js b/ui/app/components/currency-input/currency-input.container.js
index 1d1ed7b41..4c89d6c1d 100644
--- a/ui/app/components/currency-input/currency-input.container.js
+++ b/ui/app/components/currency-input/currency-input.container.js
@@ -14,14 +14,13 @@ const mapStateToProps = state => {
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { nativeCurrency, currentCurrency } = stateProps
- const { useFiat } = ownProps
- const suffix = useFiat ? currentCurrency.toUpperCase() : nativeCurrency || ETH
return {
...stateProps,
...dispatchProps,
...ownProps,
- suffix,
+ nativeSuffix: nativeCurrency || ETH,
+ fiatSuffix: currentCurrency.toUpperCase(),
}
}
diff --git a/ui/app/components/currency-input/index.scss b/ui/app/components/currency-input/index.scss
index fcb2db461..f659f5b35 100644
--- a/ui/app/components/currency-input/index.scss
+++ b/ui/app/components/currency-input/index.scss
@@ -4,4 +4,23 @@
line-height: 12px;
padding-left: 1px;
}
+
+ &__swap-component {
+ flex: 0 0 auto;
+ height: 24px;
+ width: 24px;
+ background-image: url("images/icons/swap.svg");
+ background-size: contain;
+ background-repeat: no-repeat;
+ cursor: pointer;
+ opacity: .4;
+
+ &:hover {
+ opacity: .3;
+ }
+
+ &:active {
+ opacity: .5;
+ }
+ }
}
diff --git a/ui/app/components/currency-input/tests/currency-input.component.test.js b/ui/app/components/currency-input/tests/currency-input.component.test.js
index a33889f94..e1ab29187 100644
--- a/ui/app/components/currency-input/tests/currency-input.component.test.js
+++ b/ui/app/components/currency-input/tests/currency-input.component.test.js
@@ -32,7 +32,8 @@ describe('CurrencyInput Component', () => {
const wrapper = mount(
<Provider store={store}>
<CurrencyInput
- suffix="ETH"
+ nativeSuffix="ETH"
+ fiatSuffix="USD"
nativeCurrency="ETH"
/>
</Provider>
@@ -58,7 +59,8 @@ describe('CurrencyInput Component', () => {
<Provider store={store}>
<CurrencyInput
value="de0b6b3a7640000"
- suffix="ETH"
+ fiatSuffix="USD"
+ nativeSuffix="ETH"
nativeCurrency="ETH"
currentCurrency="usd"
conversionRate={231.06}
@@ -90,7 +92,8 @@ describe('CurrencyInput Component', () => {
<Provider store={store}>
<CurrencyInput
value="f602f2234d0ea"
- suffix="USD"
+ fiatSuffix="USD"
+ nativeSuffix="ETH"
useFiat
nativeCurrency="ETH"
currentCurrency="usd"
@@ -247,5 +250,56 @@ describe('CurrencyInput Component', () => {
assert.equal(currencyInputInstance.state('hexValue'), '1ec05e43e72400')
assert.equal(currencyInputInstance.find(UnitInput).props().value, 2)
})
+
+ it('should swap selected currency when swap icon is clicked', () => {
+ const mockStore = {
+ metamask: {
+ nativeCurrency: 'ETH',
+ currentCurrency: 'usd',
+ conversionRate: 231.06,
+ },
+ }
+ const store = configureMockStore()(mockStore)
+ const wrapper = mount(
+ <Provider store={store}>
+ <CurrencyInput
+ onChange={handleChangeSpy}
+ onBlur={handleBlurSpy}
+ nativeSuffix="ETH"
+ fiatSuffix="USD"
+ nativeCurrency="ETH"
+ currentCurrency="usd"
+ conversionRate={231.06}
+ />
+ </Provider>
+ )
+
+ assert.ok(wrapper)
+ assert.equal(handleChangeSpy.callCount, 0)
+ assert.equal(handleBlurSpy.callCount, 0)
+
+ const currencyInputInstance = wrapper.find(CurrencyInput).at(0).instance()
+ assert.equal(currencyInputInstance.state.decimalValue, 0)
+ assert.equal(currencyInputInstance.state.hexValue, undefined)
+ assert.equal(wrapper.find('.currency-display-component').text(), '$0.00USD')
+ const input = wrapper.find('input')
+ assert.equal(input.props().value, 0)
+
+ input.simulate('change', { target: { value: 1 } })
+ assert.equal(handleChangeSpy.callCount, 1)
+ assert.ok(handleChangeSpy.calledWith('de0b6b3a7640000'))
+ assert.equal(wrapper.find('.currency-display-component').text(), '$231.06USD')
+ assert.equal(currencyInputInstance.state.decimalValue, 1)
+ assert.equal(currencyInputInstance.state.hexValue, 'de0b6b3a7640000')
+
+ assert.equal(handleBlurSpy.callCount, 0)
+ input.simulate('blur')
+ assert.equal(handleBlurSpy.callCount, 1)
+ assert.ok(handleBlurSpy.calledWith('de0b6b3a7640000'))
+
+ const swap = wrapper.find('.currency-input__swap-component')
+ swap.simulate('click')
+ assert.equal(wrapper.find('.currency-display-component').text(), '0.004328ETH')
+ })
})
})
diff --git a/ui/app/components/currency-input/tests/currency-input.container.test.js b/ui/app/components/currency-input/tests/currency-input.container.test.js
index 5d72958e6..10f530eff 100644
--- a/ui/app/components/currency-input/tests/currency-input.container.test.js
+++ b/ui/app/components/currency-input/tests/currency-input.container.test.js
@@ -46,14 +46,16 @@ describe('CurrencyInput container', () => {
currentCurrency: 'usd',
nativeCurrency: 'ETH',
useFiat: true,
- suffix: 'USD',
+ nativeSuffix: 'ETH',
+ fiatSuffix: 'USD',
})
assert.deepEqual(mergeProps(mockStateProps, mockDispatchProps, {}), {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
- suffix: 'ETH',
+ nativeSuffix: 'ETH',
+ fiatSuffix: 'USD',
})
})
})
diff --git a/ui/app/components/unit-input/index.scss b/ui/app/components/unit-input/index.scss
index 7995696aa..e4075d225 100644
--- a/ui/app/components/unit-input/index.scss
+++ b/ui/app/components/unit-input/index.scss
@@ -1,4 +1,7 @@
.unit-input {
+ display: flex;
+ flex-flow: row nowrap;
+ align-items: center;
min-height: 54px;
border: 1px solid #dedede;
border-radius: 4px;
@@ -24,6 +27,10 @@
display: none;
}
+ &__inputs {
+ flex: 1 0 auto;
+ }
+
&__input {
color: #4d4d4d;
font-size: 1rem;
diff --git a/ui/app/components/unit-input/unit-input.component.js b/ui/app/components/unit-input/unit-input.component.js
index 0c6b21797..230eecfe6 100644
--- a/ui/app/components/unit-input/unit-input.component.js
+++ b/ui/app/components/unit-input/unit-input.component.js
@@ -11,6 +11,7 @@ import { removeLeadingZeroes } from '../send/send.utils'
export default class UnitInput extends PureComponent {
static propTypes = {
children: PropTypes.node,
+ actionComponent: PropTypes.node,
error: PropTypes.bool,
onBlur: PropTypes.func,
onChange: PropTypes.func,
@@ -70,7 +71,7 @@ export default class UnitInput extends PureComponent {
}
render () {
- const { error, placeholder, suffix, children } = this.props
+ const { error, placeholder, suffix, actionComponent, children } = this.props
const { value } = this.state
return (
@@ -78,26 +79,29 @@ export default class UnitInput extends PureComponent {
className={classnames('unit-input', { 'unit-input--error': error })}
onClick={this.handleFocus}
>
- <div className="unit-input__input-container">
- <input
- type="number"
- className="unit-input__input"
- value={value}
- placeholder={placeholder}
- onChange={this.handleChange}
- onBlur={this.handleBlur}
- style={{ width: this.getInputWidth(value) }}
- ref={ref => { this.unitInput = ref }}
- />
- {
- suffix && (
- <div className="unit-input__suffix">
- { suffix }
- </div>
- )
- }
+ <div className="unit-input__inputs">
+ <div className="unit-input__input-container">
+ <input
+ type="number"
+ className="unit-input__input"
+ value={value}
+ placeholder={placeholder}
+ onChange={this.handleChange}
+ onBlur={this.handleBlur}
+ style={{ width: this.getInputWidth(value) }}
+ ref={ref => { this.unitInput = ref }}
+ />
+ {
+ suffix && (
+ <div className="unit-input__suffix">
+ { suffix }
+ </div>
+ )
+ }
+ </div>
+ { children }
</div>
- { children }
+ {actionComponent}
</div>
)
}