11 } from 'features/shared/components'
12 import {chainClient} from 'utility/environment'
13 import {reduxForm} from 'redux-form'
14 import React from 'react'
15 import styles from './New.scss'
16 import disableAutocomplete from 'utility/disableAutocomplete'
17 import { normalizeBTMAmountUnit } from 'utility/buildInOutDisplay'
19 const rangeOptions = [
37 const btmID = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
39 class NormalTxForm extends React.Component {
42 this.connection = chainClient().connection
47 this.submitWithValidation = this.submitWithValidation.bind(this)
48 this.disableSubmit = this.disableSubmit.bind(this)
52 this.props.fields.gas.type.onChange(rangeOptions[0].label)
53 this.props.fields.gas.price.onChange(rangeOptions[0].value)
56 disableSubmit(props) {
57 const hasValue = target => {
58 return !!(target && target.value)
61 return !( (this.state.estimateGas || hasValue(props.gas.price))&&
62 (hasValue(props.accountId) || hasValue(props.accountAlias)) &&
63 (hasValue(props.assetId) || hasValue(props.assetAlias)) &&
64 hasValue(props.address) && (hasValue(props.amount)) &&
65 hasValue(props.password)
69 submitWithValidation(data) {
70 return new Promise((resolve, reject) => {
71 this.props.submitForm(Object.assign({}, data, {state: this.state, form: 'normalTx'}))
78 err.data.forEach((error) => {
79 response.actions[error.data.actionIndex] = {type: error}
83 response['_error'] = err
84 return reject(response)
89 estimateNormalTransactionGas() {
90 const transaction = this.props.fields
91 const address = transaction.address.value
92 const amount = transaction.amount.value
93 const accountAlias = transaction.accountAlias.value
94 const accountId = transaction.accountId.value
95 const assetAlias = transaction.assetAlias.value
96 const assetId = transaction.assetId.value
98 const noAccount = !accountAlias && !accountId
99 const noAsset = !assetAlias && !assetId
101 if (!address || !amount || noAccount || noAsset) {
102 this.setState({estimateGas: null})
106 const spendAction = {
111 amount: Number(amount),
112 type: 'spend_account'
114 const receiveAction = {
118 amount: Number(amount),
119 type: 'control_address'
126 amount: Math.pow(10, 7),
127 type: 'spend_account'
130 const actions = [spendAction, receiveAction, gasAction]
131 const body = {actions, ttl: 1}
132 this.connection.request('/build-transaction', body).then(resp => {
133 if (resp.status === 'fail') {
134 this.setState({estimateGas: null})
135 this.props.showError(new Error(resp.msg))
139 return this.connection.request('/estimate-transaction-gas', {
140 transactionTemplate: resp.data
142 if (resp.status === 'fail') {
143 this.setState({estimateGas: null})
144 this.props.showError(new Error(resp.msg))
147 this.setState({estimateGas: Math.ceil(resp.data.totalNeu/100000)*100000})
154 fields: {accountId, accountAlias, assetId, assetAlias, address, amount, gas, password},
159 const lang = this.props.lang;
160 [amount, accountAlias, accountId, assetAlias, assetId].forEach(key => {
161 key.onBlur = this.estimateNormalTransactionGas.bind(this)
164 let submitLabel = lang === 'zh' ? '提交交易' : 'Submit transaction'
166 const gasOnChange = event => {
167 gas.type.onChange(event)
169 const range = rangeOptions.find(item => item.label === event.target.value)
170 gas.price.onChange(range.value)
172 const assetDecimal = this.props.assetDecimal(this.props.fields)
174 const showAvailableBalance = (accountAlias.value || accountId.value) &&
175 (assetAlias.value || assetId.value)
177 const availableBalance = this.props.balanceAmount(this.props.fields, assetDecimal)
179 const showBtmAmountUnit = (assetAlias.value === 'BTM' || assetId.value === btmID)
183 onSubmit={handleSubmit(this.submitWithValidation)} {...disableAutocomplete}
184 onKeyDown={(e) => { this.props.handleKeyDown(e, handleSubmit(this.submitWithValidation), this.disableSubmit(this.props.fields)) }}>
185 <FormSection title={lang === 'zh' ? '简单交易' : 'Normal Trasaction'}>
186 <label className={styles.title}>{lang === 'zh' ? '从' : 'From'}</label>
187 <div className={styles.main}>
189 key='account-selector-field'
191 title={lang === 'zh' ? '账户' : 'Account'}
192 aliasField={Autocomplete.AccountAlias}
199 key='asset-selector-field'
201 title={lang === 'zh' ? '资产' : 'Asset'}
202 aliasField={Autocomplete.AssetAlias}
208 {showAvailableBalance && availableBalance &&
209 <small className={styles.balanceHint}>{availableBalance} {lang === 'zh' ? '可用' : 'available'} </small>}
212 <label className={styles.title}>{lang === 'zh' ? '至' : 'To'}</label>
213 <div className={styles.main}>
214 <TextField title={lang === 'zh' ? '地址' : 'Address'} fieldProps={{
218 this.estimateNormalTransactionGas()
221 {!showBtmAmountUnit && !assetDecimal &&
222 <TextField title={lang === 'zh' ? '数量' : 'Amount'} fieldProps={amount}
224 {!showBtmAmountUnit && assetDecimal &&
225 <AmountInputMask title={lang === 'zh' ? '数量' : 'Amount'} fieldProps={amount} decimal={assetDecimal}
227 {showBtmAmountUnit &&
228 <AmountUnitField title={lang === 'zh' ? '数量' : 'Amount'} fieldProps={amount}/>
232 <label className={styles.title}>Gas</label>
233 <table className={styles.optionsBtnContianer}>
234 {rangeOptions.map((option) =>
235 <tr className={styles.optionsBtn}>
236 <td className={styles.optionsLabel}>
240 onChange={gasOnChange}
242 checked={option.label == gas.type.value}
244 {lang === 'zh' ? option.label_zh : option.label}
249 option.label == gas.type.value && option.label !== 'Customize'
250 && this.state.estimateGas && ((lang === 'zh' ? '估算' : 'estimated') + ' ' + normalizeBTMAmountUnit(btmID,
251 option.ratio * this.state.estimateGas,
252 this.props.btmAmountUnit))
255 option.label === 'Customize' && gas.type.value === 'Customize' &&
259 fieldProps={gas.price}
260 placeholder='Enter gas'/>
268 <label className={styles.title}>{lang === 'zh' ? '密码' : 'Password'}</label>
269 <TextField placeholder={lang === 'zh' ? '请输入密码' : 'Please enter the password'} fieldProps={password}
270 autoFocus={false} type={'password'}/>
273 <FormSection className={styles.submitSection}>
276 title='Error submitting form'
279 <div className={styles.submit}>
280 <button type='submit' className='btn btn-primary' disabled={submitting || this.disableSubmit(this.props.fields)}>
281 {submitLabel || ( lang === 'zh' ? '提交' : 'Submit' )}
294 const validate = (values, props) => {
295 const errors = {gas: {}}
296 const lang = props.lang
299 if (values.amount && !/^\d+(\.\d+)?$/i.test(values.amount)) {
300 errors.amount = ( lang === 'zh' ? '请输入数字' : 'Invalid amount type' )
305 const asyncValidate = (values) => {
306 return new Promise((resolve, reject) => {
307 const address = values.address
308 chainClient().accounts.validateAddresses(address)
311 if(!resp.data.valid){
312 reject({ address: 'invalid address'})
318 reject({ address: err })
324 export default BaseNew.connect(
325 BaseNew.mapStateToProps('transaction'),
327 showError: err => dispatch({type: 'ERROR', payload: err}),
328 ...BaseNew.mapDispatchToProps('transaction')(dispatch)
331 form: 'NormalTransactionForm',
346 asyncBlurFields: [ 'address'],
350 submitAction: 'submit',