Allow editing account name in account details modal

feature/default_network_editable
Alexander Tseung 7 years ago committed by Chi Kei Chan
parent fa95303e1e
commit 22d9e3a7e6
  1. 24
      ui/app/actions.js
  2. 115
      ui/app/components/editable-label.js
  3. 19
      ui/app/components/modals/account-details-modal.js
  4. 10
      ui/app/components/qr-code.js
  5. 34
      ui/app/css/itcss/components/editable-label.scss
  6. 2
      ui/app/css/itcss/components/index.scss
  7. 5
      ui/app/css/itcss/components/modal.scss

@ -1213,14 +1213,22 @@ function saveAccountLabel (account, label) {
return (dispatch) => { return (dispatch) => {
dispatch(actions.showLoadingIndication()) dispatch(actions.showLoadingIndication())
log.debug(`background.saveAccountLabel`) log.debug(`background.saveAccountLabel`)
background.saveAccountLabel(account, label, (err) => {
dispatch(actions.hideLoadingIndication()) return new Promise((resolve, reject) => {
if (err) { background.saveAccountLabel(account, label, (err) => {
return dispatch(actions.displayWarning(err.message)) dispatch(actions.hideLoadingIndication())
}
dispatch({ if (err) {
type: actions.SAVE_ACCOUNT_LABEL, dispatch(actions.displayWarning(err.message))
value: { account, label }, reject(err)
}
dispatch({
type: actions.SAVE_ACCOUNT_LABEL,
value: { account, label },
})
resolve(account)
}) })
}) })
} }

@ -1,57 +1,88 @@
const Component = require('react').Component const { Component } = require('react')
const PropTypes = require('prop-types')
const h = require('react-hyperscript') const h = require('react-hyperscript')
const inherits = require('util').inherits const classnames = require('classnames')
const findDOMNode = require('react-dom').findDOMNode
module.exports = EditableLabel class EditableLabel extends Component {
constructor (props) {
super(props)
inherits(EditableLabel, Component) this.state = {
function EditableLabel () { isEditing: false,
Component.call(this) value: props.defaultValue || '',
} }
}
handleSubmit () {
const { value } = this.state
if (value === '') {
return
}
Promise.resolve(this.props.onSubmit(value))
.then(() => this.setState({ isEditing: false }))
}
saveIfEnter (event) {
if (event.key === 'Enter') {
this.handleSubmit()
}
}
EditableLabel.prototype.render = function () { renderEditing () {
const props = this.props const { value } = this.state
const state = this.state
if (state && state.isEditingLabel) { return ([
return h('div.editable-label', [ h('input.large-input.editable-label__input', {
h('input.sizing-input', { type: 'text',
defaultValue: props.textValue, required: true,
maxLength: '20', value: this.state.value,
onKeyPress: (event) => { onKeyPress: (event) => {
this.saveIfEnter(event) if (event.key === 'Enter') {
this.handleSubmit()
}
}, },
onChange: event => this.setState({ value: event.target.value }),
className: classnames({ 'editable-label__input--error': value === '' }),
}), }),
h('button.editable-button', { h('div.editable-label__icon-wrapper', [
onClick: () => this.saveText(), h('i.fa.fa-check.editable-label__icon', {
}, 'Save'), onClick: () => this.handleSubmit(),
}),
]),
]) ])
} else {
return h('div.name-label', {
onClick: (event) => {
const nameAttribute = event.target.getAttribute('name')
// checks for class to handle smaller CTA above the account name
const classAttribute = event.target.getAttribute('class')
if (nameAttribute === 'edit' || classAttribute === 'edit-text') {
this.setState({ isEditingLabel: true })
}
},
}, this.props.children)
} }
}
EditableLabel.prototype.saveIfEnter = function (event) { renderReadonly () {
if (event.key === 'Enter') { return ([
this.saveText() h('div.editable-label__value', this.state.value),
h('div.editable-label__icon-wrapper', [
h('i.fa.fa-pencil.editable-label__icon', {
onClick: () => this.setState({ isEditing: true }),
}),
]),
])
}
render () {
const { isEditing } = this.state
const { className } = this.props
return (
h('div.editable-label', { className: classnames(className) },
isEditing
? this.renderEditing()
: this.renderReadonly()
)
)
} }
} }
EditableLabel.prototype.saveText = function () { EditableLabel.propTypes = {
// eslint-disable-next-line react/no-find-dom-node onSubmit: PropTypes.func.isRequired,
var container = findDOMNode(this) defaultValue: PropTypes.string,
var text = container.querySelector('.editable-label input').value className: PropTypes.string,
var truncatedText = text.substring(0, 20)
this.props.saveText(truncatedText)
this.setState({ isEditingLabel: false, textLabel: truncatedText })
} }
module.exports = EditableLabel

@ -7,6 +7,7 @@ const AccountModalContainer = require('./account-modal-container')
const { getSelectedIdentity, getSelectedAddress } = require('../../selectors') const { getSelectedIdentity, getSelectedAddress } = require('../../selectors')
const genAccountLink = require('../../../lib/account-link.js') const genAccountLink = require('../../../lib/account-link.js')
const QrView = require('../qr-code') const QrView = require('../qr-code')
const EditableLabel = require('../editable-label')
function mapStateToProps (state) { function mapStateToProps (state) {
return { return {
@ -23,6 +24,7 @@ function mapDispatchToProps (dispatch) {
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' })) dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
}, },
hideModal: () => dispatch(actions.hideModal()), hideModal: () => dispatch(actions.hideModal()),
saveAccountLabel: (address, label) => dispatch(actions.saveAccountLabel(address, label)),
} }
} }
@ -41,14 +43,19 @@ AccountDetailsModal.prototype.render = function () {
selectedIdentity, selectedIdentity,
network, network,
showExportPrivateKeyModal, showExportPrivateKeyModal,
hideModal, saveAccountLabel,
} = this.props } = this.props
const { name, address } = selectedIdentity const { name, address } = selectedIdentity
return h(AccountModalContainer, {}, [ return h(AccountModalContainer, {}, [
h(EditableLabel, {
className: 'account-modal__name',
defaultValue: name,
onSubmit: label => saveAccountLabel(address, label),
}),
h(QrView, { h(QrView, {
Qr: { Qr: {
message: name,
data: address, data: address,
}, },
}), }),
@ -57,14 +64,12 @@ AccountDetailsModal.prototype.render = function () {
h('button.btn-clear', { h('button.btn-clear', {
onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }),
}, [ 'View account on Etherscan' ]), }, 'View account on Etherscan'),
// Holding on redesign for Export Private Key functionality // Holding on redesign for Export Private Key functionality
h('button.btn-clear', { h('button.btn-clear', {
onClick: () => { onClick: () => showExportPrivateKeyModal(),
showExportPrivateKeyModal() }, 'Export private key'),
},
}, [ 'Export private key' ]),
]) ])
} }

@ -29,11 +29,11 @@ QrCodeView.prototype.render = function () {
const qrImage = qrCode(4, 'M') const qrImage = qrCode(4, 'M')
qrImage.addData(address) qrImage.addData(address)
qrImage.make() qrImage.make()
return h('.div.flex-column.flex-center', {
style: { return h('.div.flex-column.flex-center', [
}, Array.isArray(Qr.message)
}, [ ? h('.message-container', this.renderMultiMessage())
Array.isArray(Qr.message) ? h('.message-container', this.renderMultiMessage()) : h('.qr-header', Qr.message), : Qr.message && h('.qr-header', Qr.message),
this.props.warning ? this.props.warning && h('span.error.flex-center', { this.props.warning ? this.props.warning && h('span.error.flex-center', {
style: { style: {

@ -0,0 +1,34 @@
.editable-label {
display: flex;
align-items: center;
justify-content: center;
position: relative;
&__value {
max-width: 250px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&__input {
width: 250px;
font-size: 14px;
text-align: center;
&--error {
border: 1px solid $monzo;
}
}
&__icon-wrapper {
position: absolute;
margin-left: 10px;
left: 100%;
}
&__icon {
cursor: pointer;
color: $dusty-gray;
}
}

@ -47,3 +47,5 @@
@import './request-signature.scss'; @import './request-signature.scss';
@import './account-dropdown-mini.scss'; @import './account-dropdown-mini.scss';
@import './editable-label.scss';

@ -294,6 +294,11 @@
font-size: 18px; font-size: 18px;
} }
.account-modal__name {
margin-top: 9px;
font-size: 20px;
}
.private-key-password { .private-key-password {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

Loading…
Cancel
Save