From 07c4c92db64ffaaefbb9eb661d24bbb4c8c5ddb6 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 23 Oct 2017 13:54:47 -0230 Subject: [PATCH] Style dropdown of to-autocomplete. --- ui/app/components/send/account-list-item.js | 8 +- ui/app/components/send/to-autocomplete.js | 126 ++++++++++++++---- .../itcss/components/account-dropdown.scss | 7 + ui/app/css/itcss/components/send.scss | 10 ++ ui/app/send-v2.js | 24 ++-- 5 files changed, 136 insertions(+), 39 deletions(-) diff --git a/ui/app/components/send/account-list-item.js b/ui/app/components/send/account-list-item.js index ba7eec940..cc514cbd4 100644 --- a/ui/app/components/send/account-list-item.js +++ b/ui/app/components/send/account-list-item.js @@ -27,6 +27,8 @@ AccountListItem.prototype.render = function () { icon = null, conversionRate, currentCurrency, + displayBalance = true, + displayAddress = false, } = this.props const { name, address, balance } = account || {} @@ -46,13 +48,15 @@ AccountListItem.prototype.render = function () { }, ), - h('div.account-list-item__account-name', {}, name), + h('div.account-list-item__account-name', {}, name || address), icon && h('div.account-list-item__icon', [icon]), ]), - h(CurrencyDisplay, { + displayAddress && name && h('div.account-list-item__account-address', address), + + displayBalance && h(CurrencyDisplay, { primaryCurrency: 'ETH', convertedCurrency: currentCurrency, value: balance, diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index 686a7a23e..081b85ab7 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -2,54 +2,126 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const Identicon = require('../identicon') +const AccountListItem = require('./account-list-item') module.exports = ToAutoComplete inherits(ToAutoComplete, Component) function ToAutoComplete () { Component.call(this) + + this.state = { accountsToRender: [] } +} + +ToAutoComplete.prototype.getListItemIcon = function (listItemAddress, toAddress) { + const listItemIcon = h(`i.fa.fa-check.fa-lg`, { style: { color: '#02c9b1' } }) + + return toAddress && listItemAddress === toAddress + ? listItemIcon + : null +} + +ToAutoComplete.prototype.renderDropdown = function () { + const { + accounts, + closeDropdown, + onChange, + to, + } = this.props + const { accountsToRender } = this.state + + return accountsToRender.length && h('div', {}, [ + + h('div.send-v2__from-dropdown__close-area', { + onClick: closeDropdown, + }), + + h('div.send-v2__from-dropdown__list', {}, [ + + ...accountsToRender.map(account => h(AccountListItem, { + account, + handleClick: () => { + onChange(account.address) + closeDropdown() + }, + icon: this.getListItemIcon(account.address, to), + displayBalance: false, + displayAddress: true, + })) + + ]), + + ]) +} + +ToAutoComplete.prototype.handleInputEvent = function (event = {}, cb) { + const { + to, + accounts, + closeDropdown, + openDropdown, + } = this.props + + const matchingAccounts = accounts.filter(({ address }) => address.match(to)) + + if (!to) { + this.setState({ accountsToRender: accounts }) + openDropdown() + } + else if (matchingAccounts.length === 1 && matchingAccounts[0].address === to) { + this.setState({ accountsToRender: [] }) + event.target && event.target.select() + closeDropdown() + } + else if (matchingAccounts.length) { + this.setState({ accountsToRender: matchingAccounts }) + openDropdown() + } + else { + this.setState({ accountsToRender: [] }) + event.target && event.target.select() + closeDropdown() + } + cb && cb(event.target.value) +} + +ToAutoComplete.prototype.componentDidUpdate = function (nextProps, nextState) { + if (this.props.to !== nextProps.to) { + this.handleInputEvent() + } } ToAutoComplete.prototype.render = function () { - const { to, accounts, onChange, inError } = this.props + const { + to, + accounts, + openDropdown, + closeDropdown, + dropdownOpen, + onChange, + inError, + } = this.props - return h('div.send-v2__to-autocomplete', [ + return h('div.to-autocomplete', {}, [ h('input.send-v2__to-autocomplete__input', { - name: 'address', - list: 'addresses', placeholder: 'Recipient Address', className: inError ? `send-v2__error-border` : '', value: to, - onChange, - onFocus: event => { - to && event.target.select() - }, + onChange: event => onChange(event.target.value), + onFocus: event => this.handleInputEvent(event), style: { borderColor: inError ? 'red' : null, } }), - h('datalist#addresses', [ - // Corresponds to the addresses owned. - ...Object.entries(accounts).map(([key, { address, name }]) => { - return h('option', { - value: address, - label: name, - key: address, - }) - }), - // Corresponds to previously sent-to addresses. - // ...addressBook.map(({ address, name }) => { - // return h('option', { - // value: address, - // label: name, - // key: address, - // }) - // }), - ]), + !to && h(`i.fa.fa-caret-down.fa-lg.send-v2__to-autocomplete__down-caret`, { + style: { color: '#dedede' }, + onClick: () => this.handleInputEvent(), + }), + + dropdownOpen && this.renderDropdown(), ]) - } diff --git a/ui/app/css/itcss/components/account-dropdown.scss b/ui/app/css/itcss/components/account-dropdown.scss index 4fc7c705a..c298c4019 100644 --- a/ui/app/css/itcss/components/account-dropdown.scss +++ b/ui/app/css/itcss/components/account-dropdown.scss @@ -62,4 +62,11 @@ &__account-secondary-balance { color: $dusty-gray; } + + &__account-address { + margin-left: 35px; + width: 80%; + overflow: hidden; + text-overflow: ellipsis; + } } diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index bac5f4d05..3013ee66b 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -594,6 +594,16 @@ } } + &__to-autocomplete { + position: relative; + + &__down-caret { + position: absolute; + top: 18px; + right: 12px; + } + } + &__to-autocomplete, &__memo-text-area { &__input { height: 54px; diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 0086faa1f..9b1bf88f7 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -32,7 +32,8 @@ function SendTransactionScreen () { PersistentForm.call(this) this.state = { - dropdownOpen: false, + fromDropdownOpen: false, + toDropdownOpen: false, errors: { to: null, amount: null, @@ -157,7 +158,7 @@ SendTransactionScreen.prototype.renderFromRow = function () { updateSendFrom, } = this.props - const { dropdownOpen } = this.state + const { fromDropdownOpen } = this.state return h('div.send-v2__form-row', [ @@ -165,12 +166,12 @@ SendTransactionScreen.prototype.renderFromRow = function () { h('div.send-v2__form-field', [ h(FromDropdown, { - dropdownOpen, + dropdownOpen: fromDropdownOpen, accounts: fromAccounts, selectedAccount: from, onSelect: updateSendFrom, - openDropdown: () => this.setState({ dropdownOpen: true }), - closeDropdown: () => this.setState({ dropdownOpen: false }), + openDropdown: () => this.setState({ fromDropdownOpen: true }), + closeDropdown: () => this.setState({ fromDropdownOpen: false }), conversionRate, }), ]), @@ -178,9 +179,8 @@ SendTransactionScreen.prototype.renderFromRow = function () { ]) } -SendTransactionScreen.prototype.handleToChange = function (event) { +SendTransactionScreen.prototype.handleToChange = function (to) { const { updateSendTo, updateSendErrors } = this.props - const to = event.target.value let toError = null if (!to) { @@ -194,8 +194,9 @@ SendTransactionScreen.prototype.handleToChange = function (event) { } SendTransactionScreen.prototype.renderToRow = function () { - const { toAccounts, errors } = this.props - const { to } = this.state + const { toAccounts, errors, to } = this.props + + const { toDropdownOpen } = this.state return h('div.send-v2__form-row', [ @@ -210,7 +211,10 @@ SendTransactionScreen.prototype.renderToRow = function () { h('div.send-v2__form-field', [ h(ToAutoComplete, { to, - accounts: toAccounts, + accounts: Object.entries(toAccounts).map(([key, account]) => account), + dropdownOpen: toDropdownOpen, + openDropdown: () => this.setState({ toDropdownOpen: true }), + closeDropdown: () => this.setState({ toDropdownOpen: false }), onChange: this.handleToChange, inError: Boolean(errors.to), }),