mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-22 17:33:23 +01:00
[NewUI] SendV2-#8: Send container handles tokens; gas info dynamic from state (#2364)
* Adds memo field to send-v2. * Vertical align transaction with flexbox. * Customize Gas UI * Remove internal state from InputNumber and fix use in gastooltip. * Move customize-gas-modal to its own folder and minor cleanup * Create send container, get account info from state, and make currency display more reusable * Adjusts send-v2 and container for send-token. Dynamically getting suggested gas prices.
This commit is contained in:
parent
81f62a7443
commit
803eaaf968
@ -10,7 +10,7 @@ const NewKeyChainScreen = require('./new-keychain')
|
||||
// accounts
|
||||
const MainContainer = require('./main-container')
|
||||
const SendTransactionScreen = require('./send')
|
||||
const SendTransactionScreen2 = require('./send-v2.js')
|
||||
const SendTransactionScreen2 = require('./components/send/send-v2-container')
|
||||
const SendTokenScreen = require('./components/send-token')
|
||||
const ConfirmTxScreen = require('./conf-tx')
|
||||
// notice
|
||||
@ -356,7 +356,12 @@ App.prototype.renderPrimary = function () {
|
||||
|
||||
case 'sendToken':
|
||||
log.debug('rendering send token screen')
|
||||
return h(SendTokenScreen, {key: 'sendToken'})
|
||||
|
||||
const SendTokenComponentToRender = checkFeatureToggle('send-v2')
|
||||
? SendTransactionScreen2
|
||||
: SendTokenScreen
|
||||
|
||||
return h(SendTokenComponentToRender, {key: 'sendToken'})
|
||||
|
||||
case 'newKeychain':
|
||||
log.debug('rendering new keychain screen')
|
||||
|
55
ui/app/components/customize-gas-modal/gas-modal-card.js
Normal file
55
ui/app/components/customize-gas-modal/gas-modal-card.js
Normal file
@ -0,0 +1,55 @@
|
||||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const InputNumber = require('../input-number.js')
|
||||
const GasSlider = require('./gas-slider.js')
|
||||
|
||||
module.exports = GasModalCard
|
||||
|
||||
inherits(GasModalCard, Component)
|
||||
function GasModalCard () {
|
||||
Component.call(this)
|
||||
}
|
||||
|
||||
GasModalCard.prototype.render = function () {
|
||||
const {
|
||||
memo,
|
||||
identities,
|
||||
onChange,
|
||||
unitLabel,
|
||||
value,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
title,
|
||||
copy
|
||||
} = this.props
|
||||
|
||||
return h('div.send-v2__gas-modal-card', [
|
||||
|
||||
h('div.send-v2__gas-modal-card__title', {}, title),
|
||||
|
||||
h('div.send-v2__gas-modal-card__copy', {}, copy),
|
||||
|
||||
h(InputNumber, {
|
||||
unitLabel,
|
||||
step,
|
||||
max,
|
||||
min,
|
||||
placeholder: '0',
|
||||
value,
|
||||
onChange,
|
||||
}),
|
||||
|
||||
h(GasSlider, {
|
||||
value,
|
||||
step,
|
||||
max,
|
||||
min,
|
||||
onChange,
|
||||
}),
|
||||
|
||||
])
|
||||
|
||||
}
|
||||
|
50
ui/app/components/customize-gas-modal/gas-slider.js
Normal file
50
ui/app/components/customize-gas-modal/gas-slider.js
Normal file
@ -0,0 +1,50 @@
|
||||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
|
||||
module.exports = GasSlider
|
||||
|
||||
inherits(GasSlider, Component)
|
||||
function GasSlider () {
|
||||
Component.call(this)
|
||||
}
|
||||
|
||||
GasSlider.prototype.render = function () {
|
||||
const {
|
||||
memo,
|
||||
identities,
|
||||
onChange,
|
||||
unitLabel,
|
||||
value,
|
||||
id,
|
||||
step,
|
||||
max,
|
||||
min,
|
||||
} = this.props
|
||||
|
||||
return h('div.gas-slider', [
|
||||
|
||||
h('input.gas-slider__input', {
|
||||
type: 'range',
|
||||
step,
|
||||
max,
|
||||
min,
|
||||
value,
|
||||
id: 'gasSlider',
|
||||
onChange: event => onChange(event.target.value),
|
||||
}, []),
|
||||
|
||||
h('div.gas-slider__bar', [
|
||||
|
||||
h('div.gas-slider__low'),
|
||||
|
||||
h('div.gas-slider__mid'),
|
||||
|
||||
h('div.gas-slider__high'),
|
||||
|
||||
]),
|
||||
|
||||
])
|
||||
|
||||
}
|
||||
|
91
ui/app/components/customize-gas-modal/index.js
Normal file
91
ui/app/components/customize-gas-modal/index.js
Normal file
@ -0,0 +1,91 @@
|
||||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('../../actions')
|
||||
const GasModalCard = require('./gas-modal-card')
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
hideModal: () => dispatch(actions.hideModal()),
|
||||
}
|
||||
}
|
||||
|
||||
inherits(CustomizeGasModal, Component)
|
||||
function CustomizeGasModal () {
|
||||
Component.call(this)
|
||||
|
||||
this.state = {
|
||||
gasPrice: '0.23',
|
||||
gasLimit: '25000',
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(CustomizeGasModal)
|
||||
|
||||
CustomizeGasModal.prototype.render = function () {
|
||||
const { hideModal } = this.props
|
||||
const { gasPrice, gasLimit } = this.state
|
||||
|
||||
return h('div.send-v2__customize-gas', {}, [
|
||||
h('div', {
|
||||
}, [
|
||||
h('div.send-v2__customize-gas__header', {}, [
|
||||
|
||||
h('div.send-v2__customize-gas__title', 'Customize Gas'),
|
||||
|
||||
h('div.send-v2__customize-gas__close', {
|
||||
onClick: hideModal,
|
||||
}),
|
||||
|
||||
]),
|
||||
|
||||
h('div.send-v2__customize-gas__body', {}, [
|
||||
|
||||
h(GasModalCard, {
|
||||
value: gasPrice,
|
||||
min: 0.0,
|
||||
max: 5.0,
|
||||
step: 0.01,
|
||||
onChange: gasPrice => this.setState({ gasPrice }),
|
||||
title: 'Gas Price',
|
||||
copy: 'We calculate the suggested gas prices based on network success rates.',
|
||||
}),
|
||||
|
||||
h(GasModalCard, {
|
||||
value: gasLimit,
|
||||
min: 20000,
|
||||
max: 100000,
|
||||
step: 1,
|
||||
onChange: gasLimit => this.setState({ gasLimit }),
|
||||
title: 'Gas Limit',
|
||||
copy: 'We calculate the suggested gas limit based on network success rates.',
|
||||
}),
|
||||
|
||||
]),
|
||||
|
||||
h('div.send-v2__customize-gas__footer', {}, [
|
||||
|
||||
h('div.send-v2__customize-gas__revert', {
|
||||
onClick: () => console.log('Revert'),
|
||||
}, ['Revert']),
|
||||
|
||||
h('div.send-v2__customize-gas__buttons', [
|
||||
h('div.send-v2__customize-gas__cancel', {
|
||||
onClick: this.props.hideModal,
|
||||
}, ['CANCEL']),
|
||||
|
||||
h('div.send-v2__customize-gas__save', {
|
||||
onClick: () => console.log('Save'),
|
||||
}, ['SAVE']),
|
||||
])
|
||||
|
||||
]),
|
||||
|
||||
]),
|
||||
])
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const { addCurrencies } = require('../conversion-util')
|
||||
|
||||
module.exports = InputNumber
|
||||
|
||||
@ -8,49 +9,37 @@ inherits(InputNumber, Component)
|
||||
function InputNumber () {
|
||||
Component.call(this)
|
||||
|
||||
this.state = {
|
||||
value: 0,
|
||||
}
|
||||
|
||||
this.setValue = this.setValue.bind(this)
|
||||
}
|
||||
|
||||
InputNumber.prototype.componentWillMount = function () {
|
||||
const { initValue = 0 } = this.props
|
||||
|
||||
this.setState({ value: initValue })
|
||||
}
|
||||
|
||||
InputNumber.prototype.setValue = function (newValue) {
|
||||
const { fixed, min = -1, onChange } = this.props
|
||||
const { fixed, min = -1, max = Infinity, onChange } = this.props
|
||||
|
||||
if (fixed) newValue = Number(newValue.toFixed(4))
|
||||
newValue = Number(fixed ? newValue.toFixed(4) : newValue)
|
||||
|
||||
if (newValue >= min) {
|
||||
this.setState({ value: newValue })
|
||||
if (newValue >= min && newValue <= max) {
|
||||
onChange(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
InputNumber.prototype.render = function () {
|
||||
const { unitLabel, step = 1, placeholder } = this.props
|
||||
const { value } = this.state
|
||||
const { unitLabel, step = 1, placeholder, value = 0 } = this.props
|
||||
|
||||
return h('div.customize-gas-input-wrapper', {}, [
|
||||
h('input.customize-gas-input', {
|
||||
placeholder,
|
||||
type: 'number',
|
||||
value,
|
||||
onChange: (e) => this.setValue(Number(e.target.value)),
|
||||
value: value,
|
||||
onChange: (e) => this.setValue(e.target.value),
|
||||
}),
|
||||
h('span.gas-tooltip-input-detail', {}, [unitLabel]),
|
||||
h('div.gas-tooltip-input-arrows', {}, [
|
||||
h('i.fa.fa-angle-up', {
|
||||
onClick: () => this.setValue(value + step),
|
||||
onClick: () => this.setValue(addCurrencies(value, step)),
|
||||
}),
|
||||
h('i.fa.fa-angle-down', {
|
||||
style: { cursor: 'pointer' },
|
||||
onClick: () => this.setValue(value - step),
|
||||
onClick: () => this.setValue(addCurrencies(value, step * -1)),
|
||||
}),
|
||||
]),
|
||||
])
|
||||
|
@ -15,6 +15,7 @@ const ExportPrivateKeyModal = require('./export-private-key-modal')
|
||||
const NewAccountModal = require('./new-account-modal')
|
||||
const ShapeshiftDepositTxModal = require('./shapeshift-deposit-tx-modal.js')
|
||||
const HideTokenConfirmationModal = require('./hide-token-confirmation-modal')
|
||||
const CustomizeGasModal = require('../customize-gas-modal')
|
||||
|
||||
const accountModalStyle = {
|
||||
mobileModalStyle: {
|
||||
@ -156,6 +157,31 @@ const MODALS = {
|
||||
},
|
||||
},
|
||||
|
||||
CUSTOMIZE_GAS: {
|
||||
contents: [
|
||||
h(CustomizeGasModal, {}, []),
|
||||
],
|
||||
mobileModalStyle: {
|
||||
width: '355px',
|
||||
height: '598px',
|
||||
// top: isPopupOrNotification() === 'popup' ? '52vh' : '36.5vh',
|
||||
top: '5%',
|
||||
transform: 'none',
|
||||
left: '0',
|
||||
right: '0',
|
||||
margin: '0 auto',
|
||||
},
|
||||
laptopModalStyle: {
|
||||
width: '720px',
|
||||
height: '377px',
|
||||
top: '80px',
|
||||
transform: 'none',
|
||||
left: '0',
|
||||
right: '0',
|
||||
margin: '0 auto',
|
||||
},
|
||||
},
|
||||
|
||||
DEFAULT: {
|
||||
contents: [],
|
||||
mobileModalStyle: {},
|
||||
|
@ -3,27 +3,34 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const connect = require('react-redux').connect
|
||||
const Identicon = require('../identicon')
|
||||
const CurrencyDisplay = require('./currency-display')
|
||||
const { conversionRateSelector } = require('../../selectors')
|
||||
|
||||
inherits(AccountListItem, Component)
|
||||
function AccountListItem () {
|
||||
Component.call(this)
|
||||
}
|
||||
|
||||
module.exports = AccountListItem
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
conversionRate: conversionRateSelector(state)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps)(AccountListItem)
|
||||
|
||||
AccountListItem.prototype.render = function () {
|
||||
const {
|
||||
account,
|
||||
handleClick,
|
||||
icon = null,
|
||||
conversionRate,
|
||||
} = this.props
|
||||
|
||||
const { identity, balancesToRender } = account
|
||||
const { name, address } = identity
|
||||
const { primary, secondary } = balancesToRender
|
||||
const { name, address, balance } = account
|
||||
|
||||
return h('div.account-list-item', {
|
||||
onClick: () => handleClick(identity),
|
||||
onClick: () => handleClick({ name, address, balance }),
|
||||
}, [
|
||||
|
||||
h('div.account-list-item__top-row', {}, [
|
||||
@ -43,9 +50,17 @@ AccountListItem.prototype.render = function () {
|
||||
|
||||
]),
|
||||
|
||||
h('div.account-list-item__account-primary-balance', {}, primary),
|
||||
|
||||
h('div.account-list-item__account-secondary-balance', {}, secondary),
|
||||
h(CurrencyDisplay, {
|
||||
primaryCurrency: 'ETH',
|
||||
convertedCurrency: 'USD',
|
||||
value: balance,
|
||||
conversionRate,
|
||||
convertedPrefix: '$',
|
||||
readOnly: true,
|
||||
className: 'account-list-item__account-balances',
|
||||
primaryBalanceClassName: 'account-list-item__account-primary-balance',
|
||||
convertedBalanceClassName: 'account-list-item__account-secondary-balance',
|
||||
}, name),
|
||||
|
||||
])
|
||||
}
|
@ -11,8 +11,7 @@ function CurrencyDisplay () {
|
||||
Component.call(this)
|
||||
|
||||
this.state = {
|
||||
minWidth: null,
|
||||
currentScrollWidth: null,
|
||||
value: null,
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,28 +28,50 @@ function resetCaretIfPastEnd (value, event) {
|
||||
}
|
||||
}
|
||||
|
||||
CurrencyDisplay.prototype.handleChangeInHexWei = function (value) {
|
||||
const { handleChange } = this.props
|
||||
|
||||
const valueInHexWei = conversionUtil(value, {
|
||||
fromNumericBase: 'dec',
|
||||
toNumericBase: 'hex',
|
||||
toDenomination: 'WEI',
|
||||
})
|
||||
|
||||
handleChange(valueInHexWei)
|
||||
}
|
||||
|
||||
CurrencyDisplay.prototype.render = function () {
|
||||
const {
|
||||
className,
|
||||
className = 'currency-display',
|
||||
primaryBalanceClassName = 'currency-display__input',
|
||||
convertedBalanceClassName = 'currency-display__converted-value',
|
||||
conversionRate,
|
||||
primaryCurrency,
|
||||
convertedCurrency,
|
||||
value = '',
|
||||
placeholder = '0',
|
||||
conversionRate,
|
||||
convertedPrefix = '',
|
||||
placeholder = '0',
|
||||
readOnly = false,
|
||||
handleChange,
|
||||
value: initValue,
|
||||
} = this.props
|
||||
const { minWidth } = this.state
|
||||
const { value } = this.state
|
||||
|
||||
const convertedValue = conversionUtil(value, {
|
||||
fromNumericBase: 'dec',
|
||||
fromCurrency: primaryCurrency,
|
||||
toCurrency: convertedCurrency,
|
||||
const initValueToRender = conversionUtil(initValue, {
|
||||
fromNumericBase: 'hex',
|
||||
toNumericBase: 'dec',
|
||||
fromDenomination: 'WEI',
|
||||
numberOfDecimals: 6,
|
||||
conversionRate,
|
||||
})
|
||||
|
||||
return h('div.currency-display', {
|
||||
const convertedValue = conversionUtil(value || initValueToRender, {
|
||||
fromNumericBase: 'dec',
|
||||
fromCurrency: primaryCurrency,
|
||||
toCurrency: convertedCurrency,
|
||||
numberOfDecimals: 2,
|
||||
conversionRate,
|
||||
})
|
||||
|
||||
return h('div', {
|
||||
className,
|
||||
}, [
|
||||
|
||||
@ -58,35 +79,39 @@ CurrencyDisplay.prototype.render = function () {
|
||||
|
||||
h('div.currency-display__input-wrapper', [
|
||||
|
||||
h('input.currency-display__input', {
|
||||
value: `${value} ${primaryCurrency}`,
|
||||
h('input', {
|
||||
className: primaryBalanceClassName,
|
||||
value: `${value || initValueToRender} ${primaryCurrency}`,
|
||||
placeholder: `${0} ${primaryCurrency}`,
|
||||
readOnly,
|
||||
onChange: (event) => {
|
||||
let newValue = event.target.value.split(' ')[0]
|
||||
|
||||
if (newValue === '') {
|
||||
handleChange('0')
|
||||
this.setState({ value: '0' })
|
||||
}
|
||||
else if (newValue.match(/^0[1-9]$/)) {
|
||||
handleChange(newValue.match(/[1-9]/)[0])
|
||||
this.setState({ value: newValue.match(/[1-9]/)[0] })
|
||||
}
|
||||
else if (newValue && !isValidInput(newValue)) {
|
||||
event.preventDefault()
|
||||
}
|
||||
else {
|
||||
handleChange(newValue)
|
||||
this.setState({ value: newValue })
|
||||
}
|
||||
},
|
||||
onKeyUp: event => resetCaretIfPastEnd(value, event),
|
||||
onClick: event => resetCaretIfPastEnd(value, event),
|
||||
onBlur: event => this.handleChangeInHexWei(event.target.value.split(' ')[0]),
|
||||
onKeyUp: event => resetCaretIfPastEnd(value || initValueToRender, event),
|
||||
onClick: event => resetCaretIfPastEnd(value || initValueToRender, event),
|
||||
}),
|
||||
|
||||
]),
|
||||
|
||||
]),
|
||||
|
||||
h('div.currency-display__converted-value', {}, `${convertedPrefix}${convertedValue} ${convertedCurrency}`),
|
||||
h('div', {
|
||||
className: convertedBalanceClassName,
|
||||
}, `${convertedPrefix}${convertedValue} ${convertedCurrency}`),
|
||||
|
||||
])
|
||||
|
||||
|
@ -14,7 +14,7 @@ function FromDropdown () {
|
||||
FromDropdown.prototype.getListItemIcon = function (currentAccount, selectedAccount) {
|
||||
const listItemIcon = h(`i.fa.fa-check.fa-lg`, { style: { color: '#02c9b1' } })
|
||||
|
||||
return currentAccount.identity.address === selectedAccount.identity.address
|
||||
return currentAccount.address === selectedAccount.address
|
||||
? listItemIcon
|
||||
: null
|
||||
}
|
||||
|
47
ui/app/components/send/gas-fee-display-v2.js
Normal file
47
ui/app/components/send/gas-fee-display-v2.js
Normal file
@ -0,0 +1,47 @@
|
||||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const CurrencyDisplay = require('./currency-display');
|
||||
|
||||
const { multiplyCurrencies } = require('../../conversion-util')
|
||||
|
||||
module.exports = GasFeeDisplay
|
||||
|
||||
inherits(GasFeeDisplay, Component)
|
||||
function GasFeeDisplay () {
|
||||
Component.call(this)
|
||||
}
|
||||
|
||||
GasFeeDisplay.prototype.render = function () {
|
||||
const {
|
||||
conversionRate,
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
onClick,
|
||||
} = this.props
|
||||
|
||||
const readyToRender = Boolean(gasLimit && gasPrice)
|
||||
|
||||
return h('div', [
|
||||
|
||||
readyToRender
|
||||
? h(CurrencyDisplay, {
|
||||
primaryCurrency: 'ETH',
|
||||
convertedCurrency: 'USD',
|
||||
value: multiplyCurrencies(gasLimit, gasPrice, { toNumericBase: 'hex' }),
|
||||
conversionRate,
|
||||
convertedPrefix: '$',
|
||||
readOnly: true,
|
||||
})
|
||||
: h('div.currency-display', 'Loading...')
|
||||
,
|
||||
|
||||
h('div.send-v2__sliders-icon-container', {
|
||||
onClick,
|
||||
}, [
|
||||
h('i.fa.fa-sliders.send-v2__sliders-icon'),
|
||||
])
|
||||
|
||||
])
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ GasTooltip.prototype.render = function () {
|
||||
step: 1,
|
||||
min: 0,
|
||||
placeholder: '0',
|
||||
initValue: gasPrice,
|
||||
value: gasPrice,
|
||||
onChange: (newPrice) => this.updateGasPrice(newPrice),
|
||||
}),
|
||||
h('div.gas-tooltip-input-label', {
|
||||
@ -89,7 +89,7 @@ GasTooltip.prototype.render = function () {
|
||||
step: 1,
|
||||
min: 0,
|
||||
placeholder: '0',
|
||||
initValue: gasLimit,
|
||||
value: gasLimit,
|
||||
onChange: (newLimit) => this.updateGasLimit(newLimit),
|
||||
}),
|
||||
]),
|
||||
|
33
ui/app/components/send/memo-textarea.js
Normal file
33
ui/app/components/send/memo-textarea.js
Normal file
@ -0,0 +1,33 @@
|
||||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const Identicon = require('../identicon')
|
||||
|
||||
module.exports = MemoTextArea
|
||||
|
||||
inherits(MemoTextArea, Component)
|
||||
function MemoTextArea () {
|
||||
Component.call(this)
|
||||
}
|
||||
|
||||
MemoTextArea.prototype.render = function () {
|
||||
const { memo, identities, onChange } = this.props
|
||||
|
||||
return h('div.send-v2__memo-text-area', [
|
||||
|
||||
h('textarea.send-v2__memo-text-area__input', {
|
||||
placeholder: 'Optional',
|
||||
value: memo,
|
||||
onChange,
|
||||
// onBlur: () => {
|
||||
// this.setErrorsFor('memo')
|
||||
// },
|
||||
onFocus: event => {
|
||||
// this.clearErrorsFor('memo')
|
||||
},
|
||||
}),
|
||||
|
||||
])
|
||||
|
||||
}
|
||||
|
62
ui/app/components/send/send-v2-container.js
Normal file
62
ui/app/components/send/send-v2-container.js
Normal file
@ -0,0 +1,62 @@
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('../../actions')
|
||||
const abi = require('ethereumjs-abi')
|
||||
const SendEther = require('../../send-v2')
|
||||
|
||||
const { multiplyCurrencies } = require('../../conversion-util')
|
||||
|
||||
const {
|
||||
accountsWithSendEtherInfoSelector,
|
||||
getCurrentAccountWithSendEtherInfo,
|
||||
conversionRateSelector,
|
||||
getSelectedToken,
|
||||
getSelectedTokenExchangeRate,
|
||||
getSelectedAddress,
|
||||
} = require('../../selectors')
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(SendEther)
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const selectedAddress = getSelectedAddress(state);
|
||||
const selectedToken = getSelectedToken(state);
|
||||
const tokenExchangeRates = state.metamask.tokenExchangeRates
|
||||
const selectedTokenExchangeRate = getSelectedTokenExchangeRate(state)
|
||||
const conversionRate = conversionRateSelector(state)
|
||||
|
||||
let data;
|
||||
let primaryCurrency;
|
||||
let tokenToUSDRate;
|
||||
if (selectedToken) {
|
||||
data = Array.prototype.map.call(
|
||||
abi.rawEncode(['address', 'uint256'], [selectedAddress, '0x0']),
|
||||
x => ('00' + x.toString(16)).slice(-2)
|
||||
).join('')
|
||||
|
||||
primaryCurrency = selectedToken.symbol
|
||||
|
||||
tokenToUSDRate = multiplyCurrencies(
|
||||
conversionRate,
|
||||
selectedTokenExchangeRate,
|
||||
{ toNumericBase: 'dec' }
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
selectedAccount: getCurrentAccountWithSendEtherInfo(state),
|
||||
accounts: accountsWithSendEtherInfoSelector(state),
|
||||
conversionRate,
|
||||
selectedToken,
|
||||
primaryCurrency,
|
||||
data,
|
||||
tokenToUSDRate,
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps (dispatch) {
|
||||
return {
|
||||
showCustomizeGasModal: () => dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' })),
|
||||
estimateGas: params => dispatch(actions.estimateGas(params)),
|
||||
getGasPrice: () => dispatch(actions.getGasPrice()),
|
||||
updateTokenExchangeRate: token => dispatch(actions.updateTokenExchangeRate(token)),
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ function ToAutoComplete () {
|
||||
}
|
||||
|
||||
ToAutoComplete.prototype.render = function () {
|
||||
const { to, identities, onChange } = this.props
|
||||
const { to, accounts, onChange } = this.props
|
||||
|
||||
return h('div.send-v2__to-autocomplete', [
|
||||
|
||||
@ -32,7 +32,7 @@ ToAutoComplete.prototype.render = function () {
|
||||
|
||||
h('datalist#addresses', [
|
||||
// Corresponds to the addresses owned.
|
||||
...Object.entries(identities).map(([key, { address, name }]) => {
|
||||
...Object.entries(accounts).map(([key, { address, name }]) => {
|
||||
return h('option', {
|
||||
value: address,
|
||||
label: name,
|
||||
|
@ -128,7 +128,8 @@ const conversionUtil = (value, {
|
||||
value: value || '0',
|
||||
});
|
||||
|
||||
const addCurrencies = (a, b, { toNumericBase, numberOfDecimals }) => {
|
||||
const addCurrencies = (a, b, options = {}) => {
|
||||
const { toNumericBase, numberOfDecimals } = options
|
||||
const value = (new BigNumber(a)).add(b);
|
||||
return converter({
|
||||
value,
|
||||
@ -137,6 +138,16 @@ const addCurrencies = (a, b, { toNumericBase, numberOfDecimals }) => {
|
||||
})
|
||||
}
|
||||
|
||||
const multiplyCurrencies = (a, b, options = {}) => {
|
||||
const { toNumericBase, numberOfDecimals } = options
|
||||
const value = (new BigNumber(a)).times(b);
|
||||
return converter({
|
||||
value,
|
||||
toNumericBase,
|
||||
numberOfDecimals,
|
||||
})
|
||||
}
|
||||
|
||||
const conversionGreaterThan = (
|
||||
{ value, fromNumericBase },
|
||||
{ value: compareToValue, fromNumericBase: compareToBase },
|
||||
@ -152,5 +163,6 @@ const conversionGreaterThan = (
|
||||
module.exports = {
|
||||
conversionUtil,
|
||||
addCurrencies,
|
||||
multiplyCurrencies,
|
||||
conversionGreaterThan,
|
||||
}
|
@ -24,6 +24,16 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__account-balances {
|
||||
height: auto;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: #9b9b9b;
|
||||
margin-left: 34px;
|
||||
margin-top: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__account-name {
|
||||
font-size: 16px;
|
||||
margin-left: 8px;
|
||||
@ -34,13 +44,22 @@
|
||||
right: 12px;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
&__account-primary-balance,
|
||||
&__account-secondary-balance {
|
||||
font-family: Roboto;
|
||||
line-height: 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
&__account-primary-balance {
|
||||
margin-left: 34px;
|
||||
margin-top: 4px;
|
||||
color: $scorpion;
|
||||
border: none;
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
&__account-secondary-balance {
|
||||
margin-left: 34px;
|
||||
color: $dusty-gray;
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,6 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__input-wrapper {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
&__input {
|
||||
color: $scorpion;
|
||||
font-family: Roboto;
|
||||
|
51
ui/app/css/itcss/components/gas-slider.scss
Normal file
51
ui/app/css/itcss/components/gas-slider.scss
Normal file
@ -0,0 +1,51 @@
|
||||
.gas-slider {
|
||||
position: relative;
|
||||
width: 313px;
|
||||
|
||||
&__input {
|
||||
width: 317px;
|
||||
margin-left: -2px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
-webkit-appearance: none !important;
|
||||
}
|
||||
|
||||
input[type=range]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none !important;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
border: 2px solid #B8B8B8;
|
||||
background-color: #FFFFFF;
|
||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.08);
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
&__bar {
|
||||
height: 6px;
|
||||
width: 313px;
|
||||
background: $alto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
&__low, &__high {
|
||||
height: 6px;
|
||||
width: 49px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&__low {
|
||||
background-color: $crimson;
|
||||
}
|
||||
|
||||
&__high {
|
||||
background-color: $caribbean-green;
|
||||
}
|
||||
}
|
@ -35,3 +35,6 @@
|
||||
@import './account-menu.scss';
|
||||
|
||||
@import './menu.scss';
|
||||
|
||||
@import './gas-slider.scss';
|
||||
|
||||
|
@ -264,7 +264,7 @@
|
||||
.gas-tooltip-input-arrows {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 178px;
|
||||
right: 4px;
|
||||
width: 17px;
|
||||
height: 28px;
|
||||
border: 1px solid #dadada;
|
||||
@ -420,7 +420,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__send-eth-icon {
|
||||
&__send-header-icon-container {
|
||||
z-index: 25;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__send-header-icon {
|
||||
border-radius: 50%;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
@ -428,11 +437,6 @@
|
||||
z-index: 25;
|
||||
padding: 4px;
|
||||
background-color: $white;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__send-arrow-icon {
|
||||
@ -472,7 +476,7 @@
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
left: 178px;
|
||||
top: 71px;
|
||||
top: 65px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
@ -512,7 +516,9 @@
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__from-dropdown {
|
||||
@ -550,7 +556,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__to-autocomplete {
|
||||
&__to-autocomplete, &__memo-text-area {
|
||||
&__input {
|
||||
height: 54px;
|
||||
width: 240px;
|
||||
@ -566,6 +572,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__sliders-icon-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
border: 1px solid $curious-blue;
|
||||
border-radius: 4px;
|
||||
background-color: $white;
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__sliders-icon {
|
||||
color: $curious-blue;
|
||||
}
|
||||
|
||||
&__memo-text-area {
|
||||
&__input {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
height: 92px;
|
||||
width: 100%;
|
||||
@ -573,8 +605,7 @@
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
border-top: 1px solid $alto;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
margin-top: 29px;
|
||||
}
|
||||
|
||||
&__next-btn,
|
||||
@ -607,4 +638,155 @@
|
||||
color: $dusty-gray;
|
||||
border-color: $dusty-gray;
|
||||
}
|
||||
|
||||
&__customize-gas {
|
||||
border: 1px solid #D8D8D8;
|
||||
border-radius: 4px;
|
||||
background-color: #FFFFFF;
|
||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.14);
|
||||
font-family: Roboto;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
width: 355px;
|
||||
height: 598px;
|
||||
}
|
||||
|
||||
&__header {
|
||||
height: 52px;
|
||||
border-bottom: 1px solid $alto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin-left: 19.25px;
|
||||
}
|
||||
|
||||
&__close::after {
|
||||
content: '\00D7';
|
||||
font-size: 1.8em;
|
||||
color: $dusty-gray;
|
||||
font-family: sans-serif;
|
||||
cursor: pointer;
|
||||
margin-right: 19.25px;
|
||||
}
|
||||
|
||||
&__body {
|
||||
height: 248px;
|
||||
display: flex;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
width: 355px;
|
||||
height: 470px;
|
||||
flex-flow: column;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
height: 75px;
|
||||
border-top: 1px solid $alto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 181.75px;
|
||||
margin-right: 21.25px;
|
||||
}
|
||||
|
||||
&__revert, &__cancel, &__save {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__revert {
|
||||
color: $silver-chalice;
|
||||
font-size: 16px;
|
||||
margin-left: 21.25px;
|
||||
}
|
||||
|
||||
&__cancel, &__save {
|
||||
height: 34.64px;
|
||||
width: 85.74px;
|
||||
border: 1px solid $dusty-gray;
|
||||
border-radius: 2px;
|
||||
font-family: 'DIN OT';
|
||||
font-size: 12px;
|
||||
color: $dusty-gray;
|
||||
}
|
||||
}
|
||||
|
||||
&__gas-modal-card {
|
||||
width: 360px;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: flex-start;
|
||||
padding-left: 20px;
|
||||
|
||||
&__title {
|
||||
height: 26px;
|
||||
width: 84px;
|
||||
color: $tundora;
|
||||
font-family: Roboto;
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
line-height: 26px;
|
||||
margin-top: 17px;
|
||||
}
|
||||
|
||||
&__copy {
|
||||
height: 38px;
|
||||
width: 314px;
|
||||
color: $tundora;
|
||||
font-family: Roboto;
|
||||
font-size: 14px;
|
||||
line-height: 19px;
|
||||
margin-top: 17px;
|
||||
}
|
||||
|
||||
.customize-gas-input-wrapper {
|
||||
margin-top: 17px;
|
||||
}
|
||||
|
||||
.customize-gas-input {
|
||||
height: 54px;
|
||||
width: 315px;
|
||||
border: 1px solid $geyser;
|
||||
background-color: $white;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.gas-tooltip-input-arrows {
|
||||
width: 32px;
|
||||
height: 54px;
|
||||
border-left: 1px solid #dadada;
|
||||
font-size: 18px;
|
||||
color: $tundora;
|
||||
right: 0px;
|
||||
padding: 1px 4px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type="number"]:hover::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,16 @@ const selectors = {
|
||||
getSelectedIdentity,
|
||||
getSelectedAccount,
|
||||
getSelectedToken,
|
||||
getSelectedTokenExchangeRate,
|
||||
conversionRateSelector,
|
||||
transactionsSelector,
|
||||
accountsWithSendEtherInfoSelector,
|
||||
getCurrentAccountWithSendEtherInfo,
|
||||
}
|
||||
|
||||
module.exports = selectors
|
||||
|
||||
function getSelectedAddress (state) {
|
||||
// TODO: accounts is not defined. Is it needed?
|
||||
const selectedAddress = state.metamask.selectedAddress || Object.keys(state.metamask.accounts)[0]
|
||||
|
||||
return selectedAddress
|
||||
@ -40,10 +42,41 @@ function getSelectedToken (state) {
|
||||
return selectedToken || null
|
||||
}
|
||||
|
||||
function getSelectedTokenExchangeRate (state) {
|
||||
const tokenExchangeRates = state.metamask.tokenExchangeRates
|
||||
const selectedToken = getSelectedToken(state) || {}
|
||||
const { symbol = '' } = selectedToken
|
||||
|
||||
const pair = `${symbol.toLowerCase()}_eth`
|
||||
const { rate: tokenExchangeRate = 0 } = tokenExchangeRates[pair] || {}
|
||||
|
||||
return tokenExchangeRate
|
||||
}
|
||||
|
||||
function conversionRateSelector (state) {
|
||||
return state.metamask.conversionRate
|
||||
}
|
||||
|
||||
function accountsWithSendEtherInfoSelector (state) {
|
||||
const {
|
||||
accounts,
|
||||
identities,
|
||||
} = state.metamask
|
||||
|
||||
const accountsWithSendEtherInfo = Object.entries(accounts).map(([key, account]) => {
|
||||
return Object.assign({}, account, identities[key])
|
||||
})
|
||||
|
||||
return accountsWithSendEtherInfo
|
||||
}
|
||||
|
||||
function getCurrentAccountWithSendEtherInfo (state) {
|
||||
const currentAddress = getSelectedAddress(state)
|
||||
const accounts = accountsWithSendEtherInfoSelector(state)
|
||||
|
||||
return accounts.find(({ address }) => address === currentAddress)
|
||||
}
|
||||
|
||||
function transactionsSelector (state) {
|
||||
const { network, selectedTokenAddress } = state.metamask
|
||||
const unapprovedMsgs = valuesFor(state.metamask.unapprovedMsgs)
|
||||
|
@ -2,61 +2,135 @@ const { inherits } = require('util')
|
||||
const PersistentForm = require('../lib/persistent-form')
|
||||
const h = require('react-hyperscript')
|
||||
const connect = require('react-redux').connect
|
||||
|
||||
const Identicon = require('./components/identicon')
|
||||
const FromDropdown = require('./components/send/from-dropdown')
|
||||
const ToAutoComplete = require('./components/send/to-autocomplete')
|
||||
const CurrencyDisplay = require('./components/send/currency-display')
|
||||
const MemoTextArea = require('./components/send/memo-textarea')
|
||||
const GasFeeDisplay = require('./components/send/gas-fee-display-v2')
|
||||
|
||||
module.exports = connect(mapStateToProps)(SendTransactionScreen)
|
||||
const { showModal } = require('./actions')
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const mockAccounts = Array.from(new Array(5))
|
||||
.map((v, i) => ({
|
||||
identity: {
|
||||
name: `Test Account Name ${i}`,
|
||||
address: `0x02f567704cc6569127e18e3d00d2c85bcbfa6f0${i}`,
|
||||
},
|
||||
balancesToRender: {
|
||||
primary: `100${i}.000001 ETH`,
|
||||
secondary: `$30${i},000.00 USD`,
|
||||
}
|
||||
}))
|
||||
const conversionRate = 301.0005
|
||||
|
||||
return {
|
||||
accounts: mockAccounts,
|
||||
conversionRate
|
||||
}
|
||||
}
|
||||
module.exports = SendTransactionScreen
|
||||
|
||||
inherits(SendTransactionScreen, PersistentForm)
|
||||
function SendTransactionScreen () {
|
||||
PersistentForm.call(this)
|
||||
|
||||
this.state = {
|
||||
newTx: {
|
||||
from: '',
|
||||
to: '',
|
||||
gasPrice: null,
|
||||
gas: '0.001',
|
||||
amount: '10',
|
||||
txData: null,
|
||||
memo: '',
|
||||
},
|
||||
from: '',
|
||||
to: '',
|
||||
gasPrice: null,
|
||||
gasLimit: null,
|
||||
amount: '0x0',
|
||||
txData: null,
|
||||
memo: '',
|
||||
dropdownOpen: false,
|
||||
}
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.componentWillMount = function () {
|
||||
const {
|
||||
updateTokenExchangeRate,
|
||||
selectedToken = {},
|
||||
getGasPrice,
|
||||
estimateGas,
|
||||
selectedAddress,
|
||||
data,
|
||||
} = this.props
|
||||
const { symbol } = selectedToken || {}
|
||||
|
||||
const estimateGasParams = {
|
||||
from: selectedAddress,
|
||||
gas: '746a528800',
|
||||
}
|
||||
|
||||
if (symbol) {
|
||||
updateTokenExchangeRate(symbol)
|
||||
Object.assign(estimateGasParams, { value: '0x0' })
|
||||
}
|
||||
|
||||
if (data) {
|
||||
Object.assign(estimateGasParams, { data })
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
getGasPrice(),
|
||||
estimateGas({
|
||||
from: selectedAddress,
|
||||
gas: '746a528800',
|
||||
}),
|
||||
])
|
||||
.then(([blockGasPrice, estimatedGas]) => {
|
||||
this.setState({
|
||||
gasPrice: blockGasPrice,
|
||||
gasLimit: estimatedGas,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.renderHeaderIcon = function () {
|
||||
const { selectedToken } = this.props
|
||||
|
||||
return h('div.send-v2__send-header-icon-container', [
|
||||
selectedToken
|
||||
? h(Identicon, {
|
||||
diameter: 40,
|
||||
address: selectedToken.address,
|
||||
})
|
||||
: h('img.send-v2__send-header-icon', { src: '../images/eth_logo.svg' })
|
||||
])
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.renderTitle = function () {
|
||||
const { selectedToken } = this.props
|
||||
|
||||
return h('div.send-v2__title', [selectedToken ? 'Send Tokens' : 'Send Funds'])
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.renderCopy = function () {
|
||||
const { selectedToken } = this.props
|
||||
|
||||
const tokenText = selectedToken ? 'tokens' : 'ETH'
|
||||
|
||||
return h('div', [
|
||||
|
||||
h('div.send-v2__copy', `Only send ${tokenText} to an Ethereum address.`),
|
||||
|
||||
h('div.send-v2__copy', 'Sending to a different crytpocurrency that is not Ethereum may result in permanent loss.'),
|
||||
|
||||
])
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.render = function () {
|
||||
const { accounts, conversionRate } = this.props
|
||||
const { dropdownOpen, newTx } = this.state
|
||||
const { to, amount, gas } = newTx
|
||||
const {
|
||||
accounts,
|
||||
conversionRate,
|
||||
tokenToUSDRate,
|
||||
selectedToken,
|
||||
showCustomizeGasModal,
|
||||
selectedAccount,
|
||||
primaryCurrency = 'ETH',
|
||||
} = this.props
|
||||
|
||||
const {
|
||||
dropdownOpen,
|
||||
to,
|
||||
amount,
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
memo,
|
||||
} = this.state
|
||||
|
||||
const amountConversionRate = selectedToken ? tokenToUSDRate : conversionRate
|
||||
|
||||
return (
|
||||
|
||||
h('div.send-v2__container', [
|
||||
h('div.send-v2__header', {}, [
|
||||
|
||||
h('img.send-v2__send-eth-icon', { src: '../images/eth_logo.svg' }),
|
||||
this.renderHeaderIcon(),
|
||||
|
||||
h('div.send-v2__arrow-background', [
|
||||
h('i.fa.fa-lg.fa-arrow-circle-right.send-v2__send-arrow-icon'),
|
||||
@ -66,11 +140,9 @@ SendTransactionScreen.prototype.render = function () {
|
||||
|
||||
]),
|
||||
|
||||
h('div.send-v2__title', 'Send Funds'),
|
||||
this.renderTitle(),
|
||||
|
||||
h('div.send-v2__copy', 'Only send ETH to an Ethereum address.'),
|
||||
|
||||
h('div.send-v2__copy', 'Sending to a different crytpocurrency that is not Ethereum may result in permanent loss.'),
|
||||
this.renderCopy(),
|
||||
|
||||
h('div.send-v2__form', {}, [
|
||||
|
||||
@ -81,10 +153,11 @@ SendTransactionScreen.prototype.render = function () {
|
||||
h(FromDropdown, {
|
||||
dropdownOpen,
|
||||
accounts,
|
||||
selectedAccount: accounts[0],
|
||||
selectedAccount,
|
||||
setFromField: () => console.log('Set From Field'),
|
||||
openDropdown: () => this.setState({ dropdownOpen: true }),
|
||||
closeDropdown: () => this.setState({ dropdownOpen: false }),
|
||||
conversionRate,
|
||||
}),
|
||||
|
||||
]),
|
||||
@ -95,13 +168,11 @@ SendTransactionScreen.prototype.render = function () {
|
||||
|
||||
h(ToAutoComplete, {
|
||||
to,
|
||||
identities: accounts.map(({ identity }) => identity),
|
||||
accounts,
|
||||
onChange: (event) => {
|
||||
this.setState({
|
||||
newTx: {
|
||||
...this.state.newTx,
|
||||
to: event.target.value,
|
||||
},
|
||||
...this.state,
|
||||
to: event.target.value,
|
||||
})
|
||||
},
|
||||
}),
|
||||
@ -113,17 +184,15 @@ SendTransactionScreen.prototype.render = function () {
|
||||
h('div.send-v2__form-label', 'Amount:'),
|
||||
|
||||
h(CurrencyDisplay, {
|
||||
primaryCurrency: 'ETH',
|
||||
primaryCurrency,
|
||||
convertedCurrency: 'USD',
|
||||
value: amount,
|
||||
conversionRate,
|
||||
conversionRate: amountConversionRate,
|
||||
convertedPrefix: '$',
|
||||
handleChange: (value) => {
|
||||
this.setState({
|
||||
newTx: {
|
||||
...this.state.newTx,
|
||||
amount: value,
|
||||
},
|
||||
...this.state,
|
||||
amount: value,
|
||||
})
|
||||
}
|
||||
}),
|
||||
@ -134,13 +203,33 @@ SendTransactionScreen.prototype.render = function () {
|
||||
|
||||
h('div.send-v2__form-label', 'Gas fee:'),
|
||||
|
||||
h(CurrencyDisplay, {
|
||||
primaryCurrency: 'ETH',
|
||||
convertedCurrency: 'USD',
|
||||
value: gas,
|
||||
h(GasFeeDisplay, {
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
conversionRate,
|
||||
convertedPrefix: '$',
|
||||
readOnly: true,
|
||||
onClick: showCustomizeGasModal,
|
||||
}),
|
||||
|
||||
h('div.send-v2__sliders-icon-container', {
|
||||
onClick: showCustomizeGasModal,
|
||||
}, [
|
||||
h('i.fa.fa-sliders.send-v2__sliders-icon'),
|
||||
])
|
||||
|
||||
]),
|
||||
|
||||
h('div.send-v2__form-row', [
|
||||
|
||||
h('div.send-v2__form-label', 'Transaction Memo:'),
|
||||
|
||||
h(MemoTextArea, {
|
||||
memo,
|
||||
onChange: (event) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
memo: event.target.value,
|
||||
})
|
||||
},
|
||||
}),
|
||||
|
||||
]),
|
||||
|
Loading…
Reference in New Issue
Block a user