12 } from 'features/shared/components'
13 import {chainClient} from 'utility/environment'
14 import {reduxForm} from 'redux-form'
15 import React from 'react'
16 import styles from './New.scss'
17 import disableAutocomplete from 'utility/disableAutocomplete'
18 import { btmID } from 'utility/environment'
19 import actions from 'actions'
20 import ConfirmModal from './ConfirmModal/ConfirmModal'
23 class NormalTxForm extends React.Component {
26 this.connection = chainClient().connection
31 this.submitWithValidation = this.submitWithValidation.bind(this)
32 this.disableSubmit = this.disableSubmit.bind(this)
35 disableSubmit(props) {
36 const hasValue = target => {
37 return !!(target && target.value)
40 return !( (this.state.estimateGas) &&
41 (hasValue(props.accountId) || hasValue(props.accountAlias)) &&
42 (hasValue(props.assetId) || hasValue(props.assetAlias)) &&
43 hasValue(props.address) && (hasValue(props.amount))
47 submitWithValidation(data) {
48 return new Promise((resolve, reject) => {
49 this.props.submitForm(Object.assign({}, data, {state: this.state, form: 'normalTx'}))
51 this.props.closeModal()
56 response['_error'] = err
57 return reject(response)
62 confirmedTransaction(e){
66 onSubmit={this.submitWithValidation}
67 gas={this.state.estimateGas}
72 estimateNormalTransactionGas() {
73 const transaction = this.props.fields
74 const address = transaction.address.value
75 const amount = transaction.amount.value
76 const accountAlias = transaction.accountAlias.value
77 const accountId = transaction.accountId.value
78 const assetAlias = transaction.assetAlias.value
79 const assetId = transaction.assetId.value
81 const noAccount = !accountAlias && !accountId
82 const noAsset = !assetAlias && !assetId
84 if (!address || !amount || noAccount || noAsset) {
85 this.setState({estimateGas: null})
94 amount: Number(amount),
97 const receiveAction = {
101 amount: Number(amount),
102 type: 'control_address'
109 amount: Math.pow(10, 7),
110 type: 'spend_account'
113 const actions = [spendAction, receiveAction, gasAction]
114 const body = {actions, ttl: 1}
115 this.connection.request('/build-transaction', body).then(resp => {
116 if (resp.status === 'fail') {
117 this.setState({estimateGas: null})
118 this.props.showError(new Error(resp.msg))
122 return this.connection.request('/estimate-transaction-gas', {
123 transactionTemplate: resp.data
125 if (resp.status === 'fail') {
126 this.setState({estimateGas: null})
127 this.props.showError(new Error(resp.msg))
130 this.setState({estimateGas: Math.ceil(resp.data.totalNeu/100000)*100000})
137 fields: {accountId, accountAlias, assetId, assetAlias, address, amount, gasLevel},
141 const lang = this.props.lang;
142 [amount, accountAlias, accountId, assetAlias, assetId].forEach(key => {
143 key.onBlur = this.estimateNormalTransactionGas.bind(this)
146 let submitLabel = lang === 'zh' ? '提交交易' : 'Submit transaction'
148 const assetDecimal = this.props.assetDecimal(this.props.fields) || 0
150 const showAvailableBalance = (accountAlias.value || accountId.value) &&
151 (assetAlias.value || assetId.value)
153 const availableBalance = this.props.balanceAmount(this.props.fields, assetDecimal)
155 const showBtmAmountUnit = (assetAlias.value === 'BTM' || assetId.value === btmID)
159 className={styles.container}
160 onSubmit={e => this.confirmedTransaction(e)}
161 {...disableAutocomplete}
162 // onKeyDown={(e) => { this.props.handleKeyDown(e, handleSubmit(this.submitWithValidation), this.disableSubmit(this.props.fields)) }}
165 <label className={styles.title}>{lang === 'zh' ? '从' : 'From'}</label>
166 <div className={styles.main}>
168 key='account-selector-field'
169 keyIndex='normaltx-account'
171 title={lang === 'zh' ? '账户' : 'Account'}
172 aliasField={Autocomplete.AccountAlias}
180 key='asset-selector-field'
181 keyIndex='normaltx-asset'
183 title={lang === 'zh' ? '资产' : 'Asset'}
184 aliasField={Autocomplete.AssetAlias}
190 {showAvailableBalance && availableBalance &&
191 <small className={styles.balanceHint}>{lang === 'zh' ? '可用余额:' : 'Available balance:'} {availableBalance}</small>}
195 <label className={styles.title}>{lang === 'zh' ? '至' : 'To'}</label>
196 <div className={styles.main}>
197 <TextField title={lang === 'zh' ? '地址' : 'Address'} fieldProps={{
201 this.estimateNormalTransactionGas()
204 {!showBtmAmountUnit &&
205 <AmountInputMask title={lang === 'zh' ? '数量' : 'Amount'} fieldProps={amount} decimal={assetDecimal}
207 {showBtmAmountUnit &&
208 <AmountUnitField title={lang === 'zh' ? '数量' : 'Amount'} fieldProps={amount}/>
212 <label className={styles.title}>{lang === 'zh' ? '选择手续费' : 'Select Fee'}</label>
214 gas={this.state.estimateGas}
215 fieldProps={gasLevel}
216 btmAmountUnit={this.props.btmAmountUnit}
220 <FormSection className={styles.submitSection}>
223 title='Error submitting form'
226 <div className={styles.submit}>
227 <button type='submit' className='btn btn-primary'
228 disabled={submitting || this.disableSubmit(this.props.fields)}
243 const validate = (values, props) => {
244 const errors = {gas: {}}
245 const lang = props.lang
248 if (values.amount && !/^\d+(\.\d+)?$/i.test(values.amount)) {
249 errors.amount = ( lang === 'zh' ? '请输入数字' : 'Invalid amount type' )
254 const asyncValidate = (values) => {
255 return new Promise((resolve, reject) => {
256 const address = values.address
257 chainClient().accounts.validateAddresses(address)
260 if(!resp.data.valid){
261 reject({ address: 'invalid address'})
267 reject({ address: err })
273 export default BaseNew.connect(
274 BaseNew.mapStateToProps('transaction'),
276 showError: err => dispatch({type: 'ERROR', payload: err}),
277 closeModal: () => dispatch(actions.app.hideModal),
278 showModal: (body) => dispatch(actions.app.showModal(
280 actions.app.hideModal,
287 ...BaseNew.mapDispatchToProps('transaction')(dispatch)
290 form: 'NormalTransactionForm',
301 asyncBlurFields: [ 'address'],
303 destroyOnUnmount: false,