diff options
Diffstat (limited to 'ui/app/components')
-rw-r--r-- | ui/app/components/account-dropdowns.js | 19 | ||||
-rw-r--r-- | ui/app/components/balance-component.js | 92 | ||||
-rw-r--r-- | ui/app/components/buy-options.js | 74 | ||||
-rw-r--r-- | ui/app/components/dropdown.js | 2 | ||||
-rw-r--r-- | ui/app/components/ens-input.js | 7 | ||||
-rw-r--r-- | ui/app/components/modal.js | 96 | ||||
-rw-r--r-- | ui/app/components/network.js | 2 | ||||
-rw-r--r-- | ui/app/components/pending-tx.js | 634 | ||||
-rw-r--r-- | ui/app/components/tx-view.js | 231 | ||||
-rw-r--r-- | ui/app/components/wallet-content-display.js | 56 | ||||
-rw-r--r-- | ui/app/components/wallet-view.js | 133 |
11 files changed, 1024 insertions, 322 deletions
diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index b23600e9b..3129e0226 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -218,16 +218,16 @@ class AccountDropdowns extends Component { }, [ enableAccountsSelector && h( - // 'i.fa.fa-angle-down', - 'div.cursor-pointer.color-orange.accounts-selector', + 'i.fa.fa-angle-down', + // 'div.cursor-pointer.color-orange.accounts-selector', { style: { - // fontSize: '1.8em', - background: 'url(images/switch_acc.svg) white center center no-repeat', - height: '25px', - width: '25px', - transform: 'scale(0.75)', - marginRight: '3px', + // fontSize: '135%', + // background: 'url(images/switch_acc.svg) white center center no-repeat', + // height: '25px', + // width: '25px', + // transform: 'scale(0.75)', + // marginRight: '3px', }, onClick: (event) => { event.stopPropagation() @@ -243,8 +243,7 @@ class AccountDropdowns extends Component { 'i.fa.fa-ellipsis-h', { style: { - marginRight: '0.5em', - fontSize: '1.8em', + fontSize: '135%', }, onClick: (event) => { event.stopPropagation() diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js new file mode 100644 index 000000000..47da24c74 --- /dev/null +++ b/ui/app/components/balance-component.js @@ -0,0 +1,92 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits + +const { formatBalance, generateBalanceObject } = require('../util') + +module.exports = BalanceComponent + +inherits(BalanceComponent, Component) +function BalanceComponent () { + Component.call(this) +} + +BalanceComponent.prototype.render = function () { + const props = this.props + const { balanceValue } = props + const needsParse = 'needsParse' in props ? props.needsParse : true + const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse) : '...' + + return h('div.balance-container', {}, [ + // laptop: 50px 50px + // mobile: 100px 100px + + // TODO: balance icon needs to be passed in + h('img.balance-icon', { + src: '../images/eth_logo.svg', + style: {}, + }), + + this.renderBalance(formattedBalance), + ]) +} + +BalanceComponent.prototype.renderBalance = function (formattedBalance) { + const props = this.props + const { shorten } = props + const showFiat = 'showFiat' in props ? props.showFiat : true + + if (formattedBalance === 'None' || formattedBalance === '...') { + return h('div.flex-column.balance-display', {}, [ + h('div.token-amount', { + style: {}, + }, formattedBalance), + ]) + } + + // laptop: 5vw? + // phone: 50vw? + return h('div.flex-column.balance-display', {}, [ + h('div.token-amount', { + style: {}, + }, this.getTokenBalance(formattedBalance, shorten)), + + showFiat ? this.renderFiatValue(formattedBalance) : null, + ]) +} + +BalanceComponent.prototype.renderFiatValue = function (formattedBalance) { + + const props = this.props + const { conversionRate, currentCurrency } = props + + const fiatDisplayNumber = this.getFiatDisplayNumber(formattedBalance, conversionRate) + + return this.renderFiatAmount(fiatDisplayNumber, currentCurrency) +} + +BalanceComponent.prototype.renderFiatAmount = function (fiatDisplayNumber, fiatSuffix) { + if (fiatDisplayNumber === 'N/A') return null + + return h('div.fiat-amount', { + style: {}, + }, `${fiatDisplayNumber} ${fiatSuffix}`) +} + +BalanceComponent.prototype.getTokenBalance = function (formattedBalance, shorten) { + const balanceObj = generateBalanceObject(formattedBalance, shorten ? 1 : 3) + + const balanceValue = shorten ? balanceObj.shortBalance : balanceObj.balance + const label = balanceObj.label + + return `${balanceValue} ${label}` +} + +BalanceComponent.prototype.getFiatDisplayNumber = function (formattedBalance, conversionRate) { + if (formattedBalance === 'None') return formattedBalance + if (conversionRate === 0) return 'N/A' + + const splitBalance = formattedBalance.split(' ') + + return (Number(splitBalance[0]) * conversionRate).toFixed(2) +} diff --git a/ui/app/components/buy-options.js b/ui/app/components/buy-options.js new file mode 100644 index 000000000..d36328efd --- /dev/null +++ b/ui/app/components/buy-options.js @@ -0,0 +1,74 @@ +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') + +function mapStateToProps (state) { + return { + network: state.metamask.network, + address: state.metamask.selectedAddress, + } +} + +function mapDispatchToProps (dispatch) { + return { + toCoinbase: (address) => { + dispatch(actions.buyEth({ network: '1', address, amount: 0 })) + }, + } +} + +inherits(BuyOptions, Component) +function BuyOptions () { + Component.call(this) +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(BuyOptions) + +// BuyOptions is currently meant to be rendered inside <Modal /> +// It is the only component in this codebase that does so +// It utilizes modal styles +BuyOptions.prototype.render = function () { + return h('div', {}, [ + h('div.modal-content.transfers-subview', { + }, [ + h('div.modal-content-title-wrapper.flex-column.flex-center', { + style: {}, + }, [ + h('div.modal-content-title', { + style: {}, + }, 'Transfers'), + h('div', {}, 'How would you like to buy Ether?'), + ]), + + h('div.modal-content-options.flex-column.flex-center', {}, [ + + h('div.modal-content-option', { + onClick: () => { + const { toCoinbase, address } = this.props + toCoinbase(address) + }, + }, [ + h('div.modal-content-option-title', {}, 'Coinbase'), + h('div.modal-content-option-subtitle', {}, 'Buy with Fiat'), + ]), + + h('div.modal-content-option', {}, [ + h('div.modal-content-option-title', {}, 'Shapeshift'), + h('div.modal-content-option-subtitle', {}, 'Trade any digital asset for any other'), + ]), + + h('div.modal-content-option', {}, [ + h('div.modal-content-option-title', {}, 'Direct Deposit'), + h('div.modal-content-option-subtitle', {}, 'Deposit from another account'), + ]), + + ]), + + h('div.modal-content-footer', { + style: {}, + }, 'Cancel'), + ]) + ]) +} diff --git a/ui/app/components/dropdown.js b/ui/app/components/dropdown.js index 34c7149ee..d9593efe2 100644 --- a/ui/app/components/dropdown.js +++ b/ui/app/components/dropdown.js @@ -22,7 +22,7 @@ class Dropdown extends Component { { useCssTransition, isOpen, - zIndex: 11, + zIndex: 30, onClickOutside, style, innerStyle: innerStyleDefaults, diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 3a33ebf74..93c07599d 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -44,6 +44,13 @@ EnsInput.prototype.render = function () { return h('div', { style: { width: '100%' }, }, [ + h('span', { + style: { + textAlign: 'left', + } + }, [ + 'To:' + ]), h('input.large-input', opts), // The address book functionality. h('datalist#addresses', diff --git a/ui/app/components/modal.js b/ui/app/components/modal.js new file mode 100644 index 000000000..89de1cedb --- /dev/null +++ b/ui/app/components/modal.js @@ -0,0 +1,96 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits +const connect = require('react-redux').connect +const FadeModal = require('boron').FadeModal +const actions = require('../actions') +const isMobileView = require('../../lib/is-mobile-view') + +function mapStateToProps (state) { + return { + active: state.appState.modalOpen + } +} + +function mapDispatchToProps (dispatch) { + return { + hideModal: () => { + dispatch(actions.hideModal()) + }, + } +} + +inherits(Modal, Component) +function Modal () { + Component.call(this) +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(Modal) + +const mobileModalStyles = { + width: '95%', + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', +} + +const laptopModalStyles = { + width: '66%', + top: '30%', + boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', +} + +const backdropStyles = { + backgroundColor: 'rgba(245, 245, 245, 0.85)', +} + +Modal.prototype.render = function () { + + return h(FadeModal, + { + className: 'modal', + keyboard: false, + onHide: () => {this.onHide()}, + ref: (ref) => { + this.modalRef = ref + }, + modalStyle: isMobileView() ? mobileModalStyles : laptopModalStyles, + backdropStyle: backdropStyles, + }, + this.props.children, + ) +} + +Modal.prototype.componentWillReceiveProps = function(nextProps) { + if (nextProps.active) { + this.show() + } else if (this.props.active) { + this.hide() + } +} + +Modal.prototype.onHide = function() { + if (this.props.onHideCallback) { + this.props.onHideCallback() + } + this.props.hideModal() +} + +Modal.prototype.hide = function() { + this.modalRef.hide() +} + +Modal.prototype.show = function() { + this.modalRef.show() +} + +// TODO: specify default props and proptypes +// Modal.defaultProps = {} + +// const elementType = require('react-prop-types/lib/elementType') +// const PropTypes from 'prop-types' + +// Modal.propTypes = { +// active: PropTypes.bool, +// hideModal: PropTypes.func.isRequired, +// component: elementType, +// onHideCallback: PropTypes.func, +// } diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 698a0bbb9..ba1d0ea11 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -60,7 +60,7 @@ Network.prototype.render = function () { } return ( - h('#network_component.pointer', { + h('.network-component.pointer', { title: hoverText, onClick: (event) => this.props.onClick(event), }, [ diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index 5324ccd64..1c47440f2 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -20,6 +20,34 @@ const GWEI_FACTOR = new BN(1e9) const MIN_GAS_PRICE_BN = MIN_GAS_PRICE_GWEI_BN.mul(GWEI_FACTOR) const MIN_GAS_LIMIT_BN = new BN(21000) + +// Faked, for Icon +const Identicon = require('./identicon') +const ARAGON = '960b236A07cf122663c4303350609A66A7B288C0' + +// Next: create separate react components +// roughly 5 components: +// heroIcon +// numericDisplay (contains symbol + currency) +// divider +// contentBox +// actionButtons +const sectionDivider = h('div', { + style: { + height:'1px', + background:'#E7E7E7', + }, +}) + +const contentDivider = h('div', { + style: { + marginLeft: '16px', + marginRight: '16px', + height:'1px', + background:'#E7E7E7', + }, +}) + module.exports = PendingTx inherits(PendingTx, Component) function PendingTx () { @@ -70,344 +98,342 @@ PendingTx.prototype.render = function () { this.inputs = [] return ( - - h('div', { - key: txMeta.id, + h('div.flex-column.flex-grow', { + style: { + // overflow: 'scroll', + minWidth: '355px', // TODO: maxWidth TBD, use home.html + }, }, [ - h('form#pending-tx-form', { - onSubmit: this.onSubmit.bind(this), - + // Main Send token Card + h('div.send-screen.flex-column.flex-grow', { + style: { + marginLeft: '3.5%', + marginRight: '3.5%', + background: '#FFFFFF', // $background-white + boxShadow: '0 2px 4px 0 rgba(0,0,0,0.08)', + } }, [ + h('section.flex-center.flex-row', { + style: { + zIndex: 15, // $token-icon-z-index + marginTop: '-35px', + } + }, [ + h(Identicon, { + address: ARAGON, + diameter: 76, + }), + ]), - // tx info - h('div', [ + // + // Required Fields + // - h('.flex-row.flex-center', { - style: { - maxWidth: '100%', - }, - }, [ + h('h3.flex-center', { + style: { + marginTop: '-18px', + fontSize: '16px', + }, + }, [ + 'Confirm Transaction', + ]), - h(MiniAccountPanel, { - imageSeed: address, - picOrder: 'right', - }, [ - h('span.font-small', { - style: { - fontFamily: 'Montserrat Bold, Montserrat, sans-serif', - }, - }, identity.name), - - h(Copyable, { - value: ethUtil.toChecksumAddress(address), - }, [ - h('span.font-small', { - style: { - fontFamily: 'Montserrat Light, Montserrat, sans-serif', - }, - }, addressSummary(address, 6, 4, false)), - ]), - - h('span.font-small', { - style: { - fontFamily: 'Montserrat Light, Montserrat, sans-serif', - }, - }, [ - h(EthBalance, { - value: balance, - conversionRate, - currentCurrency, - inline: true, - labelColor: '#F7861C', - }), - ]), - ]), + h('h3.flex-center', { + style: { + textAlign: 'center', + fontSize: '12px', + }, + }, [ + 'You\'re sending to Recipient ...5924', + ]), - forwardCarrat(), + h('h3.flex-center', { + style: { + textAlign: 'center', + fontSize: '36px', + marginTop: '8px', + }, + }, [ + '0.24', + ]), - this.miniAccountPanelForRecipient(), - ]), + h('h3.flex-center', { + style: { + textAlign: 'center', + fontSize: '12px', + marginTop: '4px', + }, + }, [ + 'ANT', + ]), - h('style', ` - .table-box { - margin: 7px 0px 0px 0px; - width: 100%; - } - .table-box .row { - margin: 0px; - background: rgb(236,236,236); - display: flex; - justify-content: space-between; - font-family: Montserrat Light, sans-serif; - font-size: 13px; - padding: 5px 25px; - } - .table-box .row .value { - font-family: Montserrat Regular; - } - `), + // error message + props.error && h('span.error.flex-center', props.error), - h('.table-box', [ + sectionDivider, - // Ether Value - // Currently not customizable, but easily modified - // in the way that gas and gasLimit currently are. - h('.row', [ - h('.cell.label', 'Amount'), - h(EthBalance, { value: txParams.value, currentCurrency, conversionRate }), - ]), + h('section.flex-row.flex-center', { + }, [ + h('div', { + style: { + width: '50%', + } + }, [ + h('span', { + style: { + textAlign: 'left', + fontSize: '12px', + } + }, [ + 'From' + ]) + ]), - // Gas Limit (customizable) - h('.cell.row', [ - h('.cell.label', 'Gas Limit'), - h('.cell.value', { - }, [ - h(BNInput, { - name: 'Gas Limit', - value: gasBn, - precision: 0, - scale: 0, - // The hard lower limit for gas. - min: MIN_GAS_LIMIT_BN.toString(10), - max: safeGasLimit, - suffix: 'UNITS', - style: { - position: 'relative', - top: '5px', - }, - onChange: this.gasLimitChanged.bind(this), - - ref: (hexInput) => { this.inputs.push(hexInput) }, - }), - ]), - ]), + h('div', { + style: { + width: '50%', + } + },[ + h('div', { + style: { + textAlign: 'left', + fontSize: '10px', + marginBottom: '-10px', + }, + }, 'Aragon Token'), - // Gas Price (customizable) - h('.cell.row', [ - h('.cell.label', 'Gas Price'), - h('.cell.value', { - }, [ - h(BNInput, { - name: 'Gas Price', - value: gasPriceBn, - precision: 9, - scale: 9, - suffix: 'GWEI', - min: MIN_GAS_PRICE_GWEI_BN.toString(10), - style: { - position: 'relative', - top: '5px', - }, - onChange: this.gasPriceChanged.bind(this), - ref: (hexInput) => { this.inputs.push(hexInput) }, - }), - ]), - ]), + h('div', { + style: { + textAlign: 'left', + fontSize: '8px', + }, + }, 'Your Balance 2.34 ANT') + ]) + ]), - // Max Transaction Fee (calculated) - h('.cell.row', [ - h('.cell.label', 'Max Transaction Fee'), - h(EthBalance, { value: txFeeBn.toString(16), currentCurrency, conversionRate }), - ]), + contentDivider, - h('.cell.row', { + h('section.flex-row.flex-center', { + }, [ + h('div', { + style: { + width: '50%', + } + }, [ + h('span', { style: { - fontFamily: 'Montserrat Regular', - background: 'white', - padding: '10px 25px', - }, + textAlign: 'left', + fontSize: '12px', + } }, [ - h('.cell.label', 'Max Total'), - h('.cell.value', { - style: { - display: 'flex', - alignItems: 'center', - }, - }, [ - h(EthBalance, { - value: maxCost.toString(16), - currentCurrency, - conversionRate, - inline: true, - labelColor: 'black', - fontSize: '16px', - }), - ]), - ]), + 'To' + ]) + ]), - // Data size row: - h('.cell.row', { + h('div', { + style: { + width: '50%', + } + },[ + h('div', { style: { - background: '#f7f7f7', - paddingBottom: '0px', + textAlign: 'left', + fontSize: '10px', + marginBottom: '-10px', }, - }, [ - h('.cell.label'), - h('.cell.value', { - style: { - fontFamily: 'Montserrat Light', - fontSize: '11px', - }, - }, `Data included: ${dataLength} bytes`), - ]), - ]), // End of Table + }, 'Ethereum Address'), + h('div', { + style: { + textAlign: 'left', + fontSize: '8px', + }, + }, '...5924') + ]) ]), - h('style', ` - .conf-buttons button { - margin-left: 10px; - text-transform: uppercase; - } - `), + contentDivider, - txMeta.simulationFails ? - h('.error', { - style: { - marginLeft: 50, - fontSize: '0.9em', - }, - }, 'Transaction Error. Exception thrown in contract code.') - : null, - - !isValidAddress ? - h('.error', { + h('section.flex-row.flex-center', { + }, [ + h('div', { style: { - marginLeft: 50, - fontSize: '0.9em', - }, - }, 'Recipient address is invalid. Sending this transaction will result in a loss of ETH.') - : null, - - insufficientBalance ? - h('span.error', { + width: '50%', + } + }, [ + h('span', { + style: { + textAlign: 'left', + fontSize: '12px', + } + }, [ + 'Gas Fee' + ]) + ]), + + h('div', { style: { - marginLeft: 50, - fontSize: '0.9em', - }, - }, 'Insufficient balance for transaction') - : null, - - // send + cancel - h('.flex-row.flex-space-around.conf-buttons', { + width: '50%', + } + },[ + h('div', { + style: { + textAlign: 'left', + fontSize: '10px', + marginBottom: '-10px', + }, + }, '$0.04 USD'), + + h('div', { + style: { + textAlign: 'left', + fontSize: '8px', + }, + }, '0.001575 ETH') + ]) + ]), + + contentDivider, + + h('section.flex-row.flex-center', { style: { - display: 'flex', - justifyContent: 'flex-end', - margin: '14px 25px', - }, + backgroundColor: '#F6F6F6', // $wild-sand + borderRadius: '8px', + marginLeft: '10px', + marginRight: '10px', + paddingLeft: '6px', + paddingRight: '6px', + marginBottom: '10px', + } }, [ + h('div', { + style: { + width: '50%', + } + }, [ + h('div', { + style: { + textAlign: 'left', + fontSize: '12px', + marginBottom: '-10px', + } + }, [ + 'Total Tokens' + ]), + h('div', { + style: { + textAlign: 'left', + fontSize: '8px', + } + }, [ + 'Total Gas' + ]) - insufficientBalance ? - h('button.btn-green', { - onClick: props.buyEth, - }, 'Buy Ether') - : null, - - h('button', { - onClick: (event) => { - this.resetGasFields() - event.preventDefault() - }, - }, 'Reset'), - - // Accept Button - h('input.confirm.btn-green', { - type: 'submit', - value: 'SUBMIT', - style: { marginLeft: '10px' }, - disabled: insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting, - }), + ]), - h('button.cancel.btn-red', { - onClick: props.cancelTransaction, - }, 'Reject'), - ]), - ]), - ]) - ) -} + h('div', { + style: { + width: '50%', + } + },[ + h('div', { + style: { + textAlign: 'left', + fontSize: '10px', + marginBottom: '-10px', + }, + }, '0.24 ANT (127.00 USD)'), -PendingTx.prototype.miniAccountPanelForRecipient = function () { - const props = this.props - const txData = props.txData - const txParams = txData.txParams || {} - const isContractDeploy = !('to' in txParams) - - // If it's not a contract deploy, send to the account - if (!isContractDeploy) { - return h(MiniAccountPanel, { - imageSeed: txParams.to, - picOrder: 'left', - }, [ + h('div', { + style: { + textAlign: 'left', + fontSize: '8px', + }, + }, '0.249 ETH') + ]) + ]), - h('span.font-small', { - style: { - fontFamily: 'Montserrat Bold, Montserrat, sans-serif', - }, - }, nameForAddress(txParams.to, props.identities)), + ]), // end of container - h(Copyable, { - value: ethUtil.toChecksumAddress(txParams.to), + h('form#pending-tx-form.flex-column.flex-center', { + onSubmit: this.onSubmit.bind(this), }, [ - h('span.font-small', { + // Reset Button + // h('button', { + // onClick: (event) => { + // this.resetGasFields() + // event.preventDefault() + // }, + // }, 'Reset'), + + // Accept Button + h('input.confirm.btn-green', { + type: 'submit', + value: 'CONFIRM', style: { - fontFamily: 'Montserrat Light, Montserrat, sans-serif', + marginTop: '8px', + width: '8em', + color: '#FFFFFF', + borderRadius: '2px', + fontSize: '12px', + lineHeight: '20px', + textAlign: 'center', + borderStyle: 'none', }, - }, addressSummary(txParams.to, 6, 4, false)), - ]), - - ]) - } else { - return h(MiniAccountPanel, { - picOrder: 'left', - }, [ + disabled: insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting, + }), - h('span.font-small', { - style: { - fontFamily: 'Montserrat Bold, Montserrat, sans-serif', - }, - }, 'New Contract'), - - ]) - } -} - -PendingTx.prototype.gasPriceChanged = function (newBN, valid) { - log.info(`Gas price changed to: ${newBN.toString(10)}`) - const txMeta = this.gatherTxMeta() - txMeta.txParams.gasPrice = '0x' + newBN.toString('hex') - this.setState({ - txData: clone(txMeta), - valid, - }) -} - -PendingTx.prototype.gasLimitChanged = function (newBN, valid) { - log.info(`Gas limit changed to ${newBN.toString(10)}`) - const txMeta = this.gatherTxMeta() - txMeta.txParams.gas = '0x' + newBN.toString('hex') - this.setState({ - txData: clone(txMeta), - valid, - }) + // Cancel Button + h('button.cancel.btn-light', { + style: { + background: '#F7F7F7', // $alabaster + border: 'none', + opacity: 1, + width: '8em', + }, + onClick: props.cancelTransaction, + }, 'CANCEL'), + ]), + ]) // end of minwidth wrapper + ) } -PendingTx.prototype.resetGasFields = function () { - log.debug(`pending-tx resetGasFields`) - - this.inputs.forEach((hexInput) => { - if (hexInput) { - hexInput.setValid() - } - }) - - this.setState({ - txData: null, - valid: true, - }) -} +// PendingTx.prototype.gasPriceChanged = function (newBN, valid) { +// log.info(`Gas price changed to: ${newBN.toString(10)}`) +// const txMeta = this.gatherTxMeta() +// txMeta.txParams.gasPrice = '0x' + newBN.toString('hex') +// this.setState({ +// txData: clone(txMeta), +// valid, +// }) +// } + +// PendingTx.prototype.gasLimitChanged = function (newBN, valid) { +// log.info(`Gas limit changed to ${newBN.toString(10)}`) +// const txMeta = this.gatherTxMeta() +// txMeta.txParams.gas = '0x' + newBN.toString('hex') +// this.setState({ +// txData: clone(txMeta), +// valid, +// }) +// } + +// PendingTx.prototype.resetGasFields = function () { +// log.debug(`pending-tx resetGasFields`) + +// this.inputs.forEach((hexInput) => { +// if (hexInput) { +// hexInput.setValid() +// } +// }) + +// this.setState({ +// txData: null, +// valid: true, +// }) +// } PendingTx.prototype.onSubmit = function (event) { event.preventDefault() @@ -466,15 +492,3 @@ PendingTx.prototype.bnMultiplyByFraction = function (targetBN, numerator, denomi const denomBN = new BN(denominator) return targetBN.mul(numBN).div(denomBN) } - -function forwardCarrat () { - return ( - h('img', { - src: 'images/forward-carrat.svg', - style: { - padding: '5px 6px 0px 10px', - height: '37px', - }, - }) - ) -} diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js new file mode 100644 index 000000000..9d7bc9138 --- /dev/null +++ b/ui/app/components/tx-view.js @@ -0,0 +1,231 @@ +const Component = require('react').Component +const connect = require('react-redux').connect +const h = require('react-hyperscript') +const ethUtil = require('ethereumjs-util') +const inherits = require('util').inherits +const actions = require('../actions') +// slideout menu +const WalletView = require('./wallet-view') + +// balance component +const BalanceComponent = require('./balance-component') + +const Identicon = require('./identicon') +// const AccountDropdowns = require('./account-dropdowns').AccountDropdowns +// const Content = require('./wallet-content-display') + +module.exports = connect(mapStateToProps, mapDispatchToProps)(TxView) + +function mapStateToProps (state) { + return { + sidebarOpen: state.appState.sidebarOpen, + identities: state.metamask.identities, + accounts: state.metamask.accounts, + address: state.metamask.selectedAddress, + conversionRate: state.metamask.conversionRate, + currentCurrency: state.metamask.currentCurrency, + } +} + +function mapDispatchToProps (dispatch) { + return { + showSidebar: () => { dispatch(actions.showSidebar()) }, + hideSidebar: () => { dispatch(actions.hideSidebar()) }, + showModal: () => { dispatch(actions.showModal()) }, + } +} + +const contentDivider = h('div', { + style: { + marginLeft: '1.3em', + marginRight: '1.3em', + height:'1px', + background:'#E7E7E7', // TODO: make custom color + }, +}) + +inherits(TxView, Component) +function TxView () { + Component.call(this) +} + +TxView.prototype.render = function () { + + var props = this.props + var selected = props.address || Object.keys(props.accounts)[0] + var checksumAddress = selected && ethUtil.toChecksumAddress(selected) + var identity = props.identities[selected] + var account = props.accounts[selected] + const { conversionRate, currentCurrency } = props + + return h('div.tx-view.flex-column', { + style: {}, + }, [ + + h('div.flex-row.phone-visible', { + style: { + margin: '1em 0.9em', + alignItems: 'center' + }, + onClick: () => { + this.props.sidebarOpen ? this.props.hideSidebar() : this.props.showSidebar() + }, + }, [ + // burger + h('div.fa.fa-bars', { + style: { + fontSize: '1.3em', + }, + }, []), + + // account display + h('.identicon-wrapper.select-none', { + style: { + marginLeft: '0.9em', + }, + }, [ + h(Identicon, { + diameter: 24, + address: selected, + }), + ]), + + h('span.account-name', { + style: {}, + }, [ + identity.name, + ]), + + ]), + + // laptop: flex-row, flex-center + // mobile: flex-column + h('div.hero-balance', { + style: {}, + }, [ + + h(BalanceComponent, { + balanceValue: account && account.balance, + conversionRate, + currentCurrency, + style: {}, + }), + + // laptop: 10vw? + // phone: 75vw? + h('div.flex-row.flex-center.hero-balance-buttons', { + style: {} + }, [ + h('button.btn-clear', { + style: { + textAlign: 'center', + }, + onClick: () => { + this.props.showModal() + }, + }, 'BUY'), + + h('button.btn-clear', { + style: { + textAlign: 'center', + marginLeft: '1.4em', + }, + }, 'SEND'), + + ]), + ]), + + h('div.flex-row', { + style: { + margin: '1.8em 0.9em 0.8em 0.9em', + } + }, [ + + // tx-view-tab.js + h('div.flex-row', { + }, [ + + h('div', { + style: { + borderBottom: '0.07em solid black', + paddingBottom: '0.015em', + } + }, 'TRANSACTIONS'), + + h('div', { + style: { + marginLeft: '1.25em', + } + }, 'TOKENS'), + + ]), + ]), + + contentDivider, + + this.renderTransactionListItem(), + + contentDivider, + + this.renderTransactionListItem(), + + contentDivider, + + ]) + // column + // tab row + // divider + // item +} + +TxView.prototype.renderTransactionListItem = function () { + return h('div.flex-column', { + style: { + alignItems: 'stretch', + margin: '0.6em 1.3em 0.6em 1.3em', + } + }, [ + + h('div', { + style: { + flexGrow: 1, + marginTop: '0.3em', + } + }, 'Jul 01, 2017'), + + h('div.flex-row', { + style: { + alignItems: 'stretch', + } + }, [ + + h('div', { + style: { + flexGrow: 1, + } + }, 'icon'), + + h('div', { + style: { + flexGrow: 3, + } + }, 'Hash'), + + h('div', { + style: { + flexGrow: 5, + } + }, 'Status'), + + h('div', { + style: { + flexGrow: 2, + } + }, 'Details'), + + ]) + + ]) +} + + diff --git a/ui/app/components/wallet-content-display.js b/ui/app/components/wallet-content-display.js new file mode 100644 index 000000000..3baffad69 --- /dev/null +++ b/ui/app/components/wallet-content-display.js @@ -0,0 +1,56 @@ +const Component = require('react').Component +const h = require('react-hyperscript') +const inherits = require('util').inherits + +module.exports = WalletContentDisplay + +inherits(WalletContentDisplay, Component) +function WalletContentDisplay () { + Component.call(this) +} + +WalletContentDisplay.prototype.render = function () { + const { title, amount, fiatValue, active, style } = this.props + + // TODO: Separate component: wallet-content-account + return h('div.flex-column', { + style: { + marginLeft: '1.3em', + alignItems: 'flex-start', + ...style, + } + }, [ + + h('span', { + style: { + fontSize: '1.1em', + }, + }, title), + + h('span', { + style: { + fontSize: '1.8em', + margin: '0.4em 0em', + }, + }, amount), + + h('span', { + style: { + fontSize: '1.3em', + }, + }, fiatValue), + + active && h('div', { + style: { + position: 'absolute', + marginLeft: '-1.3em', + height: '6em', + width: '0.3em', + background: '#D8D8D8', // TODO: add to resuable colors + } + }, [ + ]) + ]) + +} + diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js new file mode 100644 index 000000000..3c331a100 --- /dev/null +++ b/ui/app/components/wallet-view.js @@ -0,0 +1,133 @@ +const Component = require('react').Component +const connect = require('react-redux').connect +const h = require('react-hyperscript') +const inherits = require('util').inherits +const Identicon = require('./identicon') +const AccountDropdowns = require('./account-dropdowns').AccountDropdowns +const Content = require('./wallet-content-display') +const actions = require('../actions') + +module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView) + +function mapStateToProps (state) { + return { + network: state.metamask.network, + sidebarOpen: state.appState.sidebarOpen, + identities: state.metamask.identities, + } +} + +function mapDispatchToProps (dispatch) { + return { + showSendPage: () => {dispatch(actions.showSendPage())}, + hideSidebar: () => {dispatch(actions.hideSidebar())}, + } +} + +inherits(WalletView, Component) +function WalletView () { + Component.call(this) +} + +const noop = () => {} + +WalletView.prototype.render = function () { + const selected = '0x82df11beb942BEeeD58d466fCb0F0791365C7684' // TODO: remove fake address + const { network, responsiveDisplayClassname, style, identities } = this.props + + return h('div.wallet-view.flex-column' + (responsiveDisplayClassname || ''), { + style: {}, + }, [ + + // TODO: Separate component: wallet account details + h('div.flex-column', { + style: {} + }, [ + + h('div.flex-row.account-options-menu', { + }, [ + + h(AccountDropdowns, { + // selected, + // network, + // identities: props.identities, + enableAccountOptions: true, + }, []), + + ]), + + h('div.flex-column.flex-center', { + style: { + // constrains size of absolutely positioned wrappers + position: 'relative', + }, + }, [ + + h('.identicon-wrapper.select-none', { + style: { + marginBottom: '1%', + }, + }, [ + h(Identicon, { + diameter: 54, + address: selected, + }), + ]), + + h('span.account-name', { + style: {} + }, [ + 'Account 1' + ]), + + h(AccountDropdowns, { + style: { + position: 'absolute', + left: 'calc(50% + 28px + 5.5px)', + // left: '42px', + // top: '-10px' + // left: '66.5%', + top: '19.5%', + }, + selected, + network, + identities, + enableAccountsSelector: true, + }, []), + ]), + + h( + AccountDropdowns, + { + style: { + marginLeft: 'auto', + cursor: 'pointer', + }, + selected, + network, // TODO: this prop could be in the account dropdown container + identities: {}, + }, + ), + + ]), + + h(Content, { + title: 'Wallet', + amount: '1001.124 ETH', + fiatValue: '$300,000.00 USD', + active: true, + }), + + // Wallet contents + h(Content, { + title: "Total Token Balance", + amount: "45.439 ETH", + fiatValue: "$13,000.00 USD", + active: false, + style: { + marginTop: '1.3em', + } + }) + + ]) +} |