OSDN Git Service

e846298ed25e8b5148bbf12ab7d22df8f876ea1d
[bytom/bytom-electron.git] / src / features / transactions / components / New / AdvancedTransactionForm.jsx
1 import {
2   BaseNew,
3   FormSection,
4   FieldLabel,
5   SubmitIndicator,
6   ErrorBanner,
7   PasswordField
8 } from 'features/shared/components'
9 import TransactionDetails from './MultiSignTransactionDetails/TransactionDetails'
10 import {DropdownButton, MenuItem} from 'react-bootstrap'
11 import {reduxForm} from 'redux-form'
12 import ActionItem from './FormActionItem'
13 import React from 'react'
14 import styles from './New.scss'
15 import  TxContainer  from './NewTransactionsContainer/TxContainer'
16 import disableAutocomplete from 'utility/disableAutocomplete'
17 import actions from 'actions'
18 import { getAssetDecimal} from '../../transactions'
19 import {withNamespaces} from 'react-i18next'
20
21
22 class AdvancedTxForm extends React.Component {
23   constructor(props) {
24     super(props)
25     this.state = {
26       showDropdown: false,
27       showAdvanced: false,
28       counter: 0
29     }
30
31     this.submitWithValidation = this.submitWithValidation.bind(this)
32     this.addActionItem = this.addActionItem.bind(this)
33     this.removeActionItem = this.removeActionItem.bind(this)
34     this.toggleDropwdown = this.toggleDropwdown.bind(this)
35     this.closeDropdown = this.closeDropdown.bind(this)
36     this.disableSubmit = this.disableSubmit.bind(this)
37   }
38
39   toggleDropwdown() {
40     this.setState({showDropdown: !this.state.showDropdown})
41   }
42
43   closeDropdown() {
44     this.setState({showDropdown: false})
45   }
46
47   addActionItem(type) {
48     const counter = this.state.counter
49     this.props.fields.actions.addField({
50       type: type,
51       ID: counter
52     })
53     this.closeDropdown()
54     this.setState({
55       counter: counter+1
56     })
57   }
58
59   disableSubmit(actions) {
60     return actions.length == 0 && !this.state.showAdvanced
61   }
62
63   removeActionItem(index) {
64     this.props.fields.actions.removeField(index)
65   }
66
67   submitWithValidation(data) {
68     return new Promise((resolve, reject) => {
69       this.props.submitForm(Object.assign({}, data, {state: this.state, form: 'advancedTx'}))
70         .catch((err) => {
71           const response = {}
72
73           if (err.data) {
74             response.actions = []
75
76             err.data.forEach((error) => {
77               response.actions[error.data.actionIndex] = {type: error}
78             })
79           }
80
81           response['_error'] = err
82           return reject(response)
83         })
84     })
85   }
86
87   render() {
88     const {
89       fields: {signTransaction, actions, submitAction, password},
90       error,
91       handleSubmit,
92       submitting
93     } = this.props
94     const t = this.props.t
95
96     let submitLabel = t('transaction.new.submit')
97     const hasBaseTransaction = ((signTransaction.value || '').trim()).length > 0
98     if (submitAction.value == 'generate' && !hasBaseTransaction) {
99       submitLabel = t('transaction.advance.generateJson')
100     }
101
102     return (
103       <TxContainer
104         error={error}
105         onSubmit={handleSubmit(this.submitWithValidation)}
106         submitting={submitting}
107         submitLabel= {submitLabel}
108         disabled={this.disableSubmit(actions)}
109         className={`${styles.content} ${styles.center}`}
110       >
111         <FormSection title='Actions'>
112           {actions.map((action, index) =>
113             <ActionItem
114               key={action.ID.value}
115               index={index}
116               fieldProps={action}
117               accounts={this.props.accounts}
118               assets={this.props.assets}
119               remove={this.removeActionItem}
120               decimal={getAssetDecimal(action, this.props.asset)}
121             />)}
122
123           <div className={`btn-group ${styles.addActionContainer} ${this.state.showDropdown && 'open'}`}>
124             <DropdownButton
125               className={`btn btn-default ${styles.addAction}`}
126               id='input-dropdown-addon'
127               title='+ Add action'
128               onSelect={this.addActionItem}
129             >
130               <MenuItem eventKey='spend_account'>Spend from account</MenuItem>
131               <MenuItem eventKey='control_address'>Control with address</MenuItem>
132               <MenuItem eventKey='vote_output'>Vote</MenuItem>
133               <MenuItem eventKey='unvote'>Veto</MenuItem>
134               <MenuItem eventKey='cross_chain_in'>Cross Chain In</MenuItem>
135               <MenuItem eventKey='cross_chain_out'>Cross Chain Out</MenuItem>
136             </DropdownButton>
137           </div>
138         </FormSection>
139
140         {!this.state.showAdvanced &&
141         <FormSection>
142           <a href='#'
143              className={styles.showAdvanced}
144              onClick={(e) => {
145                e.preventDefault()
146                this.setState({showAdvanced: true})
147              }}
148           >
149           {t('transaction.advance.showAdvanced')}
150           </a>
151         </FormSection>
152         }
153
154         {this.state.showAdvanced &&
155         <FormSection title={t('transaction.advance.option')}>
156           <div>
157             <TransactionDetails
158               fieldProps={signTransaction}
159               decode={this.props.decode}
160               transaction={this.props.decodedTx}
161               showJsonModal={this.props.showJsonModal}
162               asset={this.props.asset}
163               btmAmountUnit = {this.props.btmAmountUnit}
164             />
165
166             <FieldLabel>{t('transaction.advance.buildType')}</FieldLabel>
167             <table className={styles.submitTable}>
168               <tbody>
169               <tr>
170                 <td><input id='submit_action_submit' type='radio' {...submitAction} value='submit'
171                            checked={submitAction.value == 'submit'}/></td>
172                 <td>
173                   <label
174                     htmlFor='submit_action_submit'>{ t('transaction.advance.submitToBlockchain')}</label>
175                   <br/>
176                   <label htmlFor='submit_action_submit' className={styles.submitDescription}>
177                     {t('transaction.advance.submitLabel')}
178                   </label>
179                 </td>
180               </tr>
181               <tr>
182                 <td><input id='submit_action_generate' type='radio' {...submitAction} value='generate'
183                            checked={submitAction.value == 'generate'}/></td>
184                 <td>
185                   <label htmlFor='submit_action_generate'>{ t('transaction.advance.needMoreSign')}</label>
186                   <br/>
187                   <label htmlFor='submit_action_generate' className={styles.submitDescription}>
188                     {t('transaction.advance.needMoreSignDescription')}
189                   </label>
190                 </td>
191               </tr>
192               </tbody>
193             </table>
194           </div>
195         </FormSection>}
196
197         {(actions.length > 0 || this.state.showAdvanced) && <FormSection>
198             <label className={styles.title}>{t('key.password')}</label>
199             <PasswordField
200               placeholder={t('key.passwordPlaceholder')}
201               fieldProps={password}
202             />
203           </FormSection>}
204         </TxContainer>
205     )
206   }
207 }
208
209 const validate = (values, props) => {
210   const errors = {actions: {}}
211   const t = props.t
212
213   // Base transaction
214   let baseTx = (values.signTransaction || '').trim()
215   try {
216     JSON.parse(baseTx)
217   } catch (e) {
218     if (baseTx && e) {
219       errors.signTransaction = t('errorMessage.jsonError')
220     }
221   }
222
223   // Actions
224   let numError
225   values.actions.forEach((action, index) => {
226     numError = (!/^\d+(\.\d+)?$/i.test(values.actions[index].amount))
227     if (numError) {
228       errors.actions[index] = {...errors.actions[index], amount: t('errorMessage.amountError')}
229     }
230   })
231   return errors
232 }
233
234 const mapDispatchToProps = (dispatch) => ({
235   ...BaseNew.mapDispatchToProps('transaction')(dispatch),
236   decode: (transaction) => dispatch( actions.transaction.decode(transaction)),
237   showJsonModal: (body) => dispatch(actions.app.showModal(
238     body,
239     actions.app.hideModal,
240     null,
241     { wide: true }
242   )),
243 })
244
245 export default withNamespaces('translations') (BaseNew.connect(
246   (state, ownProps) => ({
247     ...BaseNew.mapStateToProps('transaction')(state, ownProps),
248     decodedTx: state.transaction.decodedTx
249   }),
250   mapDispatchToProps,
251   reduxForm({
252     form: 'AdvancedTransactionForm',
253     fields: [
254       'signTransaction',
255       'actions[].ID',
256       'actions[].accountId',
257       'actions[].accountAlias',
258       'actions[].assetId',
259       'actions[].assetAlias',
260       'actions[].amount',
261       'actions[].outputId',
262       'actions[].type',
263       'actions[].address',
264       'actions[].vote',
265       'actions[].sourceId',
266       'actions[].sourcePos',
267       'actions[].password',
268       'submitAction',
269       'password'
270     ],
271     validate,
272     touchOnChange: true,
273     initialValues: {
274       submitAction: 'submit',
275     },
276   }
277   )(AdvancedTxForm)
278 ))
279
280