From f36927e1e6fb8b7917ff04c940975f8acf46153e Mon Sep 17 00:00:00 2001 From: Krysto Date: Mon, 21 Jan 2019 00:17:37 +0700 Subject: [PATCH] separated SendForm using redux-form --- app/App/SendPage/LookupAddressModal.js | 2 +- app/App/SendPage/SendForm.js | 312 +++++++++++++++++++++++++ app/App/SendPage/index.js | 90 +------ tsconfig.json | 3 +- 4 files changed, 317 insertions(+), 90 deletions(-) create mode 100644 app/App/SendPage/SendForm.js diff --git a/app/App/SendPage/LookupAddressModal.js b/app/App/SendPage/LookupAddressModal.js index dc9ec4820..7e8fc5c9d 100644 --- a/app/App/SendPage/LookupAddressModal.js +++ b/app/App/SendPage/LookupAddressModal.js @@ -48,7 +48,7 @@ class LookupAddressModal extends Component { className="tda" onClick={() => { this.closeModal(); - this.props.updateAddress(ele.address); + this.props.updateRecipient(ele.address); }} > {ele.address} diff --git a/app/App/SendPage/SendForm.js b/app/App/SendPage/SendForm.js new file mode 100644 index 000000000..1f834ae44 --- /dev/null +++ b/app/App/SendPage/SendForm.js @@ -0,0 +1,312 @@ +// External Dependencies +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { reduxForm, Field, reset, change, touch } from 'redux-form'; +import styled from '@emotion/styled'; + +// Internal Global Dependencies +import * as RPC from 'scripts/rpc'; +import Text from 'components/Text'; +import Icon from 'components/Icon'; +import Button from 'components/Button'; +import TextField from 'components/TextField'; +import Select from 'components/Select'; +import FormField from 'components/FormField'; +import InputGroup from 'components/InputGroup'; +import UIController from 'components/UIController'; +import Link from 'components/Link'; +import { rpcErrorHandler } from 'utils/form'; + +// Internal Local Dependencies +import LookupAddressModal from './LookupAddressModal'; + +// Resources +import sendIcon from 'images/send.sprite.svg'; +import addressBookIcon from 'images/address-book.sprite.svg'; + +const formName = 'sendNXS'; +const floatRegex = /^[0-9]+(.[0-9]*)?$/; + +const SendFormComponent = styled.form({ + maxWidth: 620, + margin: '0 auto', +}); + +const SendAmount = styled.div({ + display: 'flex', +}); + +const SendAmountField = styled.div({ + flex: 1, +}); + +const SendAmountEqual = styled.div({ + display: 'flex', + alignItems: 'flex-end', + padding: '.1em .6em', + fontSize: '1.2em', +}); + +const SendFormButtons = styled.div({ + display: 'flex', + justifyContent: 'space-between', + marginTop: '2em', +}); + +const getAccountOptions = AccountChanger => { + if (AccountChanger) { + return AccountChanger.map(e => ({ + value: e.name, + display: `${e.name} (${e.val} NXS)`, + })); + } + return []; +}; + +const getNxsFiatPrice = (rawNXSvalues, fiatCurrency) => { + if (rawNXSvalues) { + const marketInfo = rawNXSvalues.find(e => e.name === fiatCurrency); + if (marketInfo) { + return marketInfo.price; + } + } + return null; +}; + +const getDefaultSendFrom = AccountChanger => { + if (AccountChanger && AccountChanger.length > 0) { + if (AccountChanger.find(acc => acc.name === 'default')) { + return 'default'; + } else { + return AccountChanger[0].name; + } + } + return null; +}; + +const mapStateToProps = ({ + sendReceive: { AccountChanger }, + settings: { fiatCurrency, minConfirmations }, + common: { rawNXSvalues, encrypted, loggedIn }, +}) => { + return { + accountOptions: getAccountOptions(AccountChanger), + fiatCurrency: fiatCurrency, + minConfirmations: minConfirmations, + encrypted: encrypted, + loggedIn: loggedIn, + nxsFiatPrice: getNxsFiatPrice(rawNXSvalues, fiatCurrency), + initialValues: { + sendFrom: getDefaultSendFrom(AccountChanger), + sendTo: null, + amount: 0, + fiatAmount: 0, + message: '', + }, + }; +}; + +const mapDispatchToProps = dispatch => ({ + updateRecipient: address => dispatch(change(formName, 'sendTo', address)), + updateNxsAmount: amount => dispatch(change(formName, 'amount', amount)), + updateFiatAmount: fiatAmount => + dispatch(change(formName, 'fiatAmount', fiatAmount)), + touch: () => dispatch(touch()), +}); + +@connect( + mapStateToProps, + mapDispatchToProps +) +@reduxForm({ + form: formName, + validate: ({ sendFrom, sendTo, amount }) => { + const errors = {}; + if (!sendFrom) { + errors.sendFrom = 'No accounts selected'; + } + if (!sendTo) { + errors.sendTo = ; + } + if (!amount || parseFloat(amount) <= 0) { + errors.amount = ; + } + return errors; + }, + asyncBlurFields: ['sendTo'], + asyncValidate: async ({ sendTo }) => { + if (sendTo) { + try { + const result = await RPC.PROMISE('validateaddress', [sendTo]); + if (!result.isvalid) { + throw { sendTo: }; + } + if (result.ismine) { + throw { sendTo: }; + } + } catch (err) { + throw { sendTo: err }; + } + } + return null; + }, + onSubmit: ({ sendFrom, sendTo, amount, message }, dispatch, props) => { + const params = [ + sendFrom, + sendTo, + parseFloat(amount), + parseInt(props.minConfirmations), + ]; + if (message) params.push(message); + return RPC.PROMISE('sendfrom', params); + }, + onSubmitSuccess: (result, dispatch, props) => { + UIController.openSuccessDialog({ + message: , + }); + dispatch(reset(formName)); + props.getAccountData(); + }, + onSubmitFail: rpcErrorHandler('Error Saving Settings'), +}) +export default class SendForm extends Component { + nxsToFiat = (e, value) => { + if (floatRegex.test(value)) { + const nxs = parseFloat(value); + const { nxsFiatPrice } = this.props; + if (nxsFiatPrice) { + const fiat = nxs * nxsFiatPrice; + this.props.updateFiatAmount(fiat.toFixed(2)); + } + } + }; + + fiatToNxs = (e, value) => { + if (floatRegex.test(value)) { + const fiat = parseFloat(value); + const { nxsFiatPrice } = this.props; + if (nxsFiatPrice) { + const nxs = fiat / nxsFiatPrice; + this.props.updateNxsAmount(nxs.toFixed(5)); + } + } + }; + + lookupAddress = () => { + UIController.openModal(LookupAddressModal, { + updateRecipient: this.props.updateRecipient, + }); + }; + + confirmSend = () => { + const { handleSubmit, invalid, encrypted, loggedIn, touch } = this.props; + + if (invalid) { + // Mark the form touched so that the validation errors will be shown + touch(); + return; + } + + if (encrypted && !loggedIn) { + const modalId = UIController.openErrorDialog({ + message: 'You are not logged in', + note: ( + <> +

You need to log in to your wallet before sending transactions

+ { + UIController.removeModal(modalId); + }} + > + Log in now + + + ), + }); + return; + } + + UIController.openConfirmDialog({ + question: , + yesCallback: handleSubmit, + }); + }; + + render() { + const { accountOptions, fiatCurrency } = this.props; + return ( + + + + + + + + + + + + + + + }> + + + + + = + + + + + + + + + + {placeholder => ( + }> + + + )} + + + +
+ + + + ); + } +} diff --git a/app/App/SendPage/index.js b/app/App/SendPage/index.js index 16cc50baa..be61c5a30 100644 --- a/app/App/SendPage/index.js +++ b/app/App/SendPage/index.js @@ -25,6 +25,7 @@ import Link from 'components/Link'; // Internal Local Dependencies import LookupAddressModal from './LookupAddressModal'; import MoveBetweenAccountsModal from './MoveBetweenAccountsModal'; +import SendForm from './SendForm'; import Queue from './Queue'; import styles from './style.css'; @@ -33,11 +34,6 @@ import sendIcon from 'images/send.sprite.svg'; import swapIcon from 'images/swap.sprite.svg'; import addressBookIcon from 'images/address-book.sprite.svg'; -const SendForm = styled.div({ - maxWidth: 620, - margin: '0 auto', -}); - const SendAmount = styled.div({ display: 'flex', }); @@ -485,89 +481,7 @@ class SendPage extends Component { ) : (
- - -