Browse Source

fix(ui): autofocus and clear pay and request forms

When the payment and request forms open ensure that the forms are empty
and the most relevant form field is selected by default.

Fix #389
renovate/lint-staged-8.x
Tom Kirkpatrick 6 years ago
parent
commit
eb71b6c579
No known key found for this signature in database GPG Key ID: 72203A8EC5967EA8
  1. 6
      app/components/AmountInput/AmountInput.js
  2. 17
      app/components/Form/Pay.js
  3. 197
      app/components/Form/Request.js
  4. 8
      test/unit/components/Form/Pay.spec.js
  5. 4
      test/unit/components/Form/Request.spec.js

6
app/components/AmountInput/AmountInput.js

@ -7,6 +7,7 @@ class AmountInput extends React.Component {
this.handleChange = this.handleChange.bind(this) this.handleChange = this.handleChange.bind(this)
this.handleBlur = this.handleBlur.bind(this) this.handleBlur = this.handleBlur.bind(this)
this.handleKeyDown = this.handleKeyDown.bind(this) this.handleKeyDown = this.handleKeyDown.bind(this)
this.textInput = React.createRef()
} }
setRules() { setRules() {
@ -41,6 +42,10 @@ class AmountInput extends React.Component {
} }
} }
focusTextInput() {
this.textInput.current.focus()
}
parseNumber(_value) { parseNumber(_value) {
let value = _value || '' let value = _value || ''
if (typeof _value === 'string') { if (typeof _value === 'string') {
@ -143,6 +148,7 @@ class AmountInput extends React.Component {
onBlur={this.handleBlur} onBlur={this.handleBlur}
onKeyDown={this.handleKeyDown} onKeyDown={this.handleKeyDown}
readOnly={readOnly} readOnly={readOnly}
ref={this.textInput}
type="text" type="text"
required required
value={amount} value={amount}

17
app/components/Form/Pay.js

@ -12,6 +12,22 @@ import AmountInput from 'components/AmountInput'
import styles from './Pay.scss' import styles from './Pay.scss'
class Pay extends Component { class Pay extends Component {
constructor(props) {
super(props)
this.paymentRequestInput = React.createRef()
}
componentDidMount() {
const { setPayInput, setPayAmount } = this.props
// Clear the form of any previous data.
setPayInput('')
setPayAmount('')
// Focus the payment request input field.
this.paymentRequestInput.current.focus()
}
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const { const {
isLn, isLn,
@ -110,6 +126,7 @@ class Pay extends Component {
onBlur={onPayInputBlur} onBlur={onPayInputBlur}
id="paymentRequest" id="paymentRequest"
rows="4" rows="4"
ref={this.paymentRequestInput}
/> />
<section <section
className={`${styles.errorMessage} ${ className={`${styles.errorMessage} ${

197
app/components/Form/Request.js

@ -1,4 +1,4 @@
import React from 'react' import React, { Component } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Isvg from 'react-inlinesvg' import Isvg from 'react-inlinesvg'
@ -9,100 +9,121 @@ import { btc } from 'lib/utils'
import AmountInput from 'components/AmountInput' import AmountInput from 'components/AmountInput'
import styles from './Request.scss' import styles from './Request.scss'
const Request = ({ class Request extends Component {
requestform: { amount, memo, showCurrencyFilters }, constructor(props) {
ticker, super(props)
this.amountInput = React.createRef()
setRequestAmount, }
setRequestMemo,
setCurrency,
setRequestCurrencyFilters,
currencyName,
requestFiatAmount,
currentCurrencyFilters, componentDidMount() {
const { setRequestMemo, setRequestAmount } = this.props
onRequestSubmit // Clear the form of any previous data.
}) => { setRequestMemo('')
const onCurrencyFilterClick = currency => { setRequestAmount('')
// change the input amount
setRequestAmount(btc.convert(ticker.currency, currency, amount))
setCurrency(currency) // Focus the amount input field.
setRequestCurrencyFilters(false) this.amountInput.current.focusTextInput()
} }
return ( render() {
<div className={styles.container}> const {
<header className={styles.header}> requestform: { amount, memo, showCurrencyFilters },
<Isvg src={hand} /> ticker,
<h1>Request Payment</h1>
</header> setRequestAmount,
setRequestMemo,
<div className={styles.content}> setCurrency,
<section className={styles.amount}> setRequestCurrencyFilters,
<div className={styles.top}> currencyName,
<label htmlFor="amount">Amount</label> requestFiatAmount,
<span />
</div> currentCurrencyFilters,
<div className={styles.bottom}>
<AmountInput onRequestSubmit
id="amount" } = this.props
amount={amount}
currency={ticker.currency} const onCurrencyFilterClick = currency => {
onChangeEvent={setRequestAmount} // change the input amount
/> setRequestAmount(btc.convert(ticker.currency, currency, amount))
<div className={styles.currency}>
<section setCurrency(currency)
className={styles.currentCurrency} setRequestCurrencyFilters(false)
onClick={() => setRequestCurrencyFilters(!showCurrencyFilters)} }
>
<span>{currencyName}</span> return (
<span> <div className={styles.container}>
<FaAngleDown /> <header className={styles.header}>
</span> <Isvg src={hand} />
</section> <h1>Request Payment</h1>
<ul className={showCurrencyFilters ? styles.active : undefined}> </header>
{currentCurrencyFilters.map(filter => (
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}> <div className={styles.content}>
{filter.name} <section className={styles.amount}>
</li> <div className={styles.top}>
))} <label htmlFor="amount">Amount</label>
</ul> <span />
</div>
<div className={styles.bottom}>
<AmountInput
id="amount"
amount={amount}
currency={ticker.currency}
onChangeEvent={setRequestAmount}
ref={this.amountInput}
/>
<div className={styles.currency}>
<section
className={styles.currentCurrency}
onClick={() => setRequestCurrencyFilters(!showCurrencyFilters)}
>
<span>{currencyName}</span>
<span>
<FaAngleDown />
</span>
</section>
<ul className={showCurrencyFilters ? styles.active : undefined}>
{currentCurrencyFilters.map(filter => (
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}>
{filter.name}
</li>
))}
</ul>
</div>
</div> </div>
</div>
<div className={styles.fiatAmount}>{`${requestFiatAmount || 0} ${
<div className={styles.fiatAmount}>{`${requestFiatAmount || 0} ${ ticker.fiatTicker
ticker.fiatTicker }`}</div>
}`}</div> </section>
</section>
<section className={styles.memo}>
<section className={styles.memo}> <div className={styles.top}>
<div className={styles.top}> <label htmlFor="memo">Memo</label>
<label htmlFor="memo">Memo</label> </div>
</div> <div className={styles.bottom}>
<div className={styles.bottom}> <input
<input type="text"
type="text" placeholder="Details about the request"
placeholder="Details about the request" value={memo}
value={memo} onChange={event => setRequestMemo(event.target.value)}
onChange={event => setRequestMemo(event.target.value)} id="memo"
id="memo" />
/> </div>
</div> </section>
</section>
<section className={styles.submit}>
<section className={styles.submit}> <div
<div className={`${styles.button} ${amount > 0 ? styles.active : undefined}`}
className={`${styles.button} ${amount > 0 ? styles.active : undefined}`} onClick={onRequestSubmit}
onClick={onRequestSubmit} >
> Request
Request </div>
</div> </section>
</section> </div>
</div> </div>
</div> )
) }
} }
Request.propTypes = { Request.propTypes = {

8
test/unit/components/Form/Pay.spec.js

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { configure, shallow } from 'enzyme' import { configure, mount } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16' import Adapter from 'enzyme-adapter-react-16'
import Pay from 'components/Form/Pay' import Pay from 'components/Form/Pay'
@ -45,7 +45,7 @@ const defaultProps = {
describe('Form', () => { describe('Form', () => {
describe('should show the form without an input', () => { describe('should show the form without an input', () => {
const el = shallow(<Pay {...defaultProps} />) const el = mount(<Pay {...defaultProps} />)
it('should contain Pay', () => { it('should contain Pay', () => {
expect(el.find('input#paymentRequest').props.value).toBe(undefined) expect(el.find('input#paymentRequest').props.value).toBe(undefined)
@ -54,7 +54,7 @@ describe('Form', () => {
describe('should show lightning with a lightning input', () => { describe('should show lightning with a lightning input', () => {
const props = { ...defaultProps, isLn: true } const props = { ...defaultProps, isLn: true }
const el = shallow(<Pay {...props} />) const el = mount(<Pay {...props} />)
it('should contain Pay', () => { it('should contain Pay', () => {
expect(el.find('input#paymentRequest').props.value).toBe(undefined) expect(el.find('input#paymentRequest').props.value).toBe(undefined)
@ -63,7 +63,7 @@ describe('Form', () => {
describe('should show on-chain with an on-chain input', () => { describe('should show on-chain with an on-chain input', () => {
const props = { ...defaultProps, isOnchain: true } const props = { ...defaultProps, isOnchain: true }
const el = shallow(<Pay {...props} />) const el = mount(<Pay {...props} />)
it('should contain Pay', () => { it('should contain Pay', () => {
expect(el.find('input#paymentRequest').props.value).toBe(undefined) expect(el.find('input#paymentRequest').props.value).toBe(undefined)

4
test/unit/components/Form/Request.spec.js

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { configure, shallow } from 'enzyme' import { configure, mount } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16' import Adapter from 'enzyme-adapter-react-16'
import Request from 'components/Form/Request' import Request from 'components/Form/Request'
@ -28,7 +28,7 @@ const defaultProps = {
describe('Form', () => { describe('Form', () => {
describe('should show request form when formType is REQUEST_FORM', () => { describe('should show request form when formType is REQUEST_FORM', () => {
const props = { ...defaultProps } const props = { ...defaultProps }
const el = shallow(<Request {...props} />) const el = mount(<Request {...props} />)
it('should contain Request', () => { it('should contain Request', () => {
expect(el.contains('Request')).toBe(true) expect(el.contains('Request')).toBe(true)
}) })

Loading…
Cancel
Save