OSDN Git Service

update the issue asset transaction logic
authorZhiting Lin <zlin035@uottawa.ca>
Mon, 15 Apr 2019 08:24:01 +0000 (16:24 +0800)
committerZhiting Lin <zlin035@uottawa.ca>
Mon, 15 Apr 2019 08:24:01 +0000 (16:24 +0800)
src/features/shared/components/AmountField/AmountField.jsx [new file with mode: 0644]
src/features/shared/components/AmountField/AmountField.scss [new file with mode: 0644]
src/features/transactions/actions.js
src/features/transactions/components/New/AdvancedTransactionForm.jsx
src/features/transactions/components/New/FormActionItem.jsx
src/features/transactions/components/New/IssueAssets.jsx
src/features/transactions/components/New/New.jsx
src/features/transactions/components/New/New.scss
src/features/transactions/components/New/NewTransactionsContainer/TxContainer.jsx [new file with mode: 0644]
src/features/transactions/components/New/NewTransactionsContainer/TxContainer.scss [new file with mode: 0644]
src/features/transactions/components/New/NormalTransactionForm.jsx

diff --git a/src/features/shared/components/AmountField/AmountField.jsx b/src/features/shared/components/AmountField/AmountField.jsx
new file mode 100644 (file)
index 0000000..3e96621
--- /dev/null
@@ -0,0 +1,27 @@
+import React from 'react'
+import {AmountInputMask, AmountUnitField } from '../'
+
+class AmountField extends React.Component {
+  constructor(props) {
+    super(props)
+  }
+
+  render() {
+    const isBTM = this.props.isBTM
+
+    return(isBTM ?
+          <AmountUnitField
+            title={this.props.title}
+            fieldProps={this.props.fieldProps}
+          />
+          :
+          <AmountInputMask
+            title={this.props.title}
+            fieldProps={this.props.fieldProps}
+            decimal={this.props.decimal}
+          />
+    )
+  }
+}
+
+export default AmountField
\ No newline at end of file
diff --git a/src/features/shared/components/AmountField/AmountField.scss b/src/features/shared/components/AmountField/AmountField.scss
new file mode 100644 (file)
index 0000000..d91b441
--- /dev/null
@@ -0,0 +1,9 @@
+.base {
+  background: red;
+}
+
+.unit{
+  & > div{
+    z-index: unset !important;
+  }
+}
index 0e4acbd..2a2aa0e 100644 (file)
@@ -223,6 +223,7 @@ const decode = (data) => {
         }
       })
       .catch(err => {
+        dispatch({type: 'DECODE_TRANSACTION', data:[]})
         throw {_error: err}
       })
   }
index 308d6c8..0c7654b 100644 (file)
@@ -12,6 +12,7 @@ import {reduxForm} from 'redux-form'
 import ActionItem from './FormActionItem'
 import React from 'react'
 import styles from './New.scss'
+import  TxContainer  from './NewTransactionsContainer/TxContainer'
 import disableAutocomplete from 'utility/disableAutocomplete'
 import actions from 'actions'
 import { getAssetDecimal} from '../../transactions'
@@ -99,12 +100,14 @@ class AdvancedTxForm extends React.Component {
     }
 
     return (
-      <form
+      <TxContainer
+        error={error}
+        onSubmit={handleSubmit(this.submitWithValidation)}
+        submitting={submitting}
+        submitLabel= {submitLabel}
+        disabled={this.disableSubmit(actions)}
         className={`${styles.content} ${styles.center}`}
-        onSubmit={handleSubmit(this.submitWithValidation)} {...disableAutocomplete}
-            // onKeyDown={(e) => { this.props.handleKeyDown(e, handleSubmit(this.submitWithValidation), this.disableSubmit(actions)) }}
       >
-
         <FormSection title='Actions'>
           {actions.map((action, index) =>
             <ActionItem
@@ -196,24 +199,7 @@ class AdvancedTxForm extends React.Component {
               fieldProps={password}
             />
           </FormSection>}
-
-          <FormSection className={styles.submitSection}>
-            {error &&
-            <ErrorBanner
-              title={t('form.errorTitle')}
-              error={error} />}
-
-            <div className={styles.submit}>
-              <button type='submit' className='btn btn-primary' disabled={submitting || this.disableSubmit(actions)}>
-                {submitLabel ||  t('form.submit')}
-              </button>
-
-              { submitting &&
-              <SubmitIndicator />
-              }
-            </div>
-          </FormSection>
-        </form>
+        </TxContainer>
     )
   }
 }
index 5c7ce00..8a53077 100644 (file)
@@ -1,5 +1,5 @@
 import React from 'react'
-import { ErrorBanner, HiddenField, Autocomplete, JsonField, TextField, ObjectSelectorField, AmountUnitField, AmountInputMask } from 'features/shared/components'
+import { ErrorBanner, HiddenField, Autocomplete, JsonField, TextField, ObjectSelectorField,AmountField } from 'features/shared/components'
 import styles from './FormActionItem.scss'
 import { btmID } from 'utility/environment'
 import {withNamespaces} from 'react-i18next'
@@ -122,11 +122,13 @@ class ActionItem extends React.Component {
             }}
           />}
 
-        {visible.amount && !btmAmounUnitVisible &&
-          <AmountInputMask title={ t('form.amount') } fieldProps={amount} decimal={decimal} />}
-
-        {visible.amount && btmAmounUnitVisible &&
-          <AmountUnitField title={ t('form.amount') } fieldProps={amount} />}
+        {visible.amount &&
+          <AmountField
+            isBTM={btmAmounUnitVisible}
+            title={t('form.amount')}
+            fieldProps={amount}
+            decimal={decimal}
+          />}
 
         {visible.password && false &&
           <TextField title={t('key.password')} placeholder={t('key.password')} fieldProps={password} autoFocus={false} type={'password'} />
index 481a6b1..d06229f 100644 (file)
@@ -2,12 +2,10 @@ import {
   BaseNew,
   FormSection,
   Autocomplete,
-  SubmitIndicator,
   ObjectSelectorField,
-  ErrorBanner,
   TextField,
-  AmountInputMask,
   AmountUnitField,
+  AmountField,
   PasswordField,
   RadioField,
   KeyValueTable,
@@ -15,10 +13,10 @@ import {
 import { Connection } from 'sdk'
 import {chainClient} from 'utility/environment'
 import { addZeroToDecimalPosition } from 'utility/buildInOutDisplay'
+import  TxContainer  from './NewTransactionsContainer/TxContainer'
 import {reduxForm} from 'redux-form'
 import React from 'react'
 import styles from './New.scss'
-import disableAutocomplete from 'utility/disableAutocomplete'
 import actions from 'actions'
 import { btmID } from 'utility/environment'
 import { getAssetDecimal} from '../../transactions'
@@ -29,18 +27,14 @@ class IssueAssets extends React.Component {
   constructor(props) {
     super(props)
     this.state = {
-      counter: 1
+      counter: 1,
     }
 
     this.submitWithValidation = this.submitWithValidation.bind(this)
-    // this.disableSubmit = this.disableSubmit.bind(this)
     this.addReceiverItem = this.addReceiverItem.bind(this)
+    this.removeReceiverItem = this.removeReceiverItem.bind(this)
   }
 
-  // disableSubmit(actions) {
-  //   return actions.length == 0 && !this.state.showAdvanced
-  // }
-
   submitWithValidation(data) {
     return new Promise((resolve, reject) => {
       this.props.submitForm(Object.assign({}, data, {state: this.state, form: 'issueAssetTx'}))
@@ -49,10 +43,6 @@ class IssueAssets extends React.Component {
 
           if (err.data) {
             response.actions = []
-
-            // err.data.forEach((error) => {
-            //   response.actions[error.data.actionIndex] = {type: error}
-            // })
           }
 
           response['_error'] = err
@@ -83,6 +73,48 @@ class IssueAssets extends React.Component {
     }
   }
 
+  componentWillReceiveProps(nextProps) {
+    if(nextProps.decodedTx.length !== 0 && nextProps.decodedTx !== this.props.decodedTx && nextProps.fields.submitAction.value === 'sign'){
+      const transaction = nextProps.decodedTx
+
+      const inputs = transaction.inputs
+      const outputs = transaction.outputs
+
+      const issueAction = inputs.filter(input => input.type === 'issue')[0]
+      const issueAssetId = issueAction.assetId
+
+      const issueReceivers = outputs.filter(output => output.assetId == issueAssetId)
+
+      const diffLength = issueReceivers.length - this.props.fields.receivers.length
+
+      if(diffLength > 0 ){
+        const counter = this.state.counter
+        for (let i = 0; i < diffLength; i++) {
+          this.props.fields.receivers.addField({
+            id: counter+i
+          })
+        }
+        this.setState({
+          counter: counter+diffLength,
+        })
+      }else if(diffLength < 0){
+        for (let i = 0; i < -diffLength; i++) {
+          this.removeReceiverItem(i)
+        }
+      }
+    }
+
+    else if( nextProps.fields.submitAction.value === 'submit' && this.props.fields.submitAction.value === 'sign'){
+      const length = nextProps.fields.receivers.length
+      if(length>1){
+        for (let i = 0; i < (length-1) ; i++) {
+          nextProps.fields.receivers.removeField(i)
+        }
+      }
+    }
+
+  }
+
   render() {
     const {
       fields: {assetAlias, assetId, receivers, password, submitAction, signTransaction, accountId, accountAlias, gas},
@@ -93,39 +125,40 @@ class IssueAssets extends React.Component {
     const t = this.props.t
 
     let submitLabel = t('transaction.new.submit')
-    // const hasBaseTransaction = ((signTransaction.value || '').trim()).length > 0
-    // if (submitAction.value == 'generate' && !hasBaseTransaction) {
-    //   submitLabel = t('transaction.advance.generateJson')
-    // }
+    if (submitAction.value == 'sign') {
+      submitLabel = 'sign tx'
+    }
 
     const options = [
       {label: t('transaction.advance.submitToBlockchain') , value: 'submit'},
       {label: 'sign raw transaction', value: 'sign'}
     ]
+
     const showBtmAmountUnit = (assetAlias.value === 'BTM' || assetId.value === btmID)
     const assetDecimal = getAssetDecimal(this.props.fields, this.props.asset) || 0
 
     const asset = this.props.asset.filter(a => (a.id === assetId.value || a.alias === assetAlias.value))[0]
 
     let assetItem
-    if(submitAction.value === 'sign' && this.props.decodedTx.length != 0 && signTransaction.value){
+
+    if (submitAction.value === 'sign' && this.props.decodedTx.length !== 0 && signTransaction.value && signTransaction.valid) {
       const transaction = this.props.decodedTx
 
       const inputs = transaction.inputs
       const outputs = transaction.outputs
 
-      const issueAction = inputs.filter(input => input.type=='issue')[0]
+      const issueAction = inputs.filter(input => input.type === 'issue')[0]
       const issueAssetId = issueAction.assetId
       assetId.value = issueAssetId
 
-      gas.value = transaction.fee/Math.pow(10, 8) + ' BTM'
+      gas.value = transaction.fee / Math.pow(10, 8) + ' BTM'
 
-      accountAlias.value = inputs.filter(input => input.type=='spend')[0].address
+      accountAlias.value = inputs.filter(input => input.type === 'spend')[0].address
 
       const assetDefinition = issueAction.assetDefinition
 
       assetItem = <KeyValueTable
-        title={'definition'}
+        title={'Definition'}
         id={issueAssetId}
         object='asset'
         items={[
@@ -142,11 +175,13 @@ class IssueAssets extends React.Component {
       const issueReceivers = outputs.filter(output => output.assetId == issueAssetId)
 
       receivers.map((receiver, index) =>{
-        receiver.address.value = issueReceivers[index].address
-        receiver.amount.value = addZeroToDecimalPosition((issueReceivers[index].amount/Math.pow(10, assetDefinition.decimals)), Number(assetDefinition.decimals))
+        if(issueReceivers[index]){
+          receiver.address.value = issueReceivers[index].address
+          receiver.amount.value = addZeroToDecimalPosition((issueReceivers[index].amount/Math.pow(10, assetDefinition.decimals)), Number(assetDefinition.decimals))
+        }
       })
 
-    }else if(asset){
+    } else if (asset) {
       assetItem = <KeyValueTable
         title={'definition'}
         id={asset.id}
@@ -156,7 +191,7 @@ class IssueAssets extends React.Component {
           {label: t('form.alias'), value: asset.alias},
           {label: t('form.symbol'), value: asset.definition.symbol},
           {label: t('form.decimals'), value: asset.definition.decimals},
-          {label: t('form.reissueTitle'), value: (asset.alias === 'BTM' || asset.limitHeight > 0)? 'false': 'true'},
+          {label: t('form.reissueTitle'), value: (asset.alias === 'BTM' || asset.limitHeight > 0) ? 'false' : 'true'},
           {label: t('form.xpubs'), value: (asset.xpubs || []).length},
           {label: t('form.quorum'), value: asset.quorum},
           {label: t('asset.additionInfo'), value: asset.definition.description},
@@ -165,29 +200,50 @@ class IssueAssets extends React.Component {
     }
 
     return (
-      <form
+      <TxContainer
+        error={error}
+        onSubmit={handleSubmit(this.submitWithValidation)}
+        submitting={submitting}
+        submitLabel= {submitLabel}
         className={styles.container}
-        onSubmit={handleSubmit(this.submitWithValidation)} {...disableAutocomplete}
       >
 
         <FormSection  title= { 'Issue asset'}>
-        {/*<FormSection>*/}
-          <div>
-            {/*<label>definition</label>*/}
-             {assetItem}
-            <ObjectSelectorField
-              key='asset-selector-field'
-              keyIndex='normaltx-asset'
-              title={ t('form.asset')}
-              aliasField={Autocomplete.AssetAlias}
-              disabled = {submitAction.value === 'sign'}
-              selected = {submitAction.value === 'sign'? 'ID':'Alias'}
-              fieldProps={{
-                id: assetId,
-                alias: assetAlias
-              }}
-            />
+          {assetItem}
+          <label className={styles.title}>Input</label>
+          <div className={`${styles.mainBox} ${this.props.tutorialVisible? styles.tutorialItem: styles.item}`}>
+            {
+              submitAction.value === 'sign'?
+                <TextField title={'Account address'}
+                           disabled = {true}
+                           fieldProps={accountAlias}/>
+                :
+                <ObjectSelectorField
+                  key='account-selector-field'
+                  keyIndex='normaltx-account'
+                  title={t('form.account')}
+                  aliasField={Autocomplete.AccountAlias}
+                  fieldProps={{
+                    id: accountId,
+                    alias: accountAlias
+                  }}
+                />
+            }
+
+            {
+              submitAction.value === 'submit' && <ObjectSelectorField
+                key='asset-selector-field'
+                keyIndex='normaltx-asset'
+                title={ t('form.asset')}
+                aliasField={Autocomplete.AssetAlias}
+                fieldProps={{
+                  id: assetId,
+                  alias: assetAlias
+                }}
+              />
+            }
           </div>
+          <label className={styles.title}>Output</label>
           <div className={styles.mainBox}>
             {receivers.map((receiver, index) =>
               <div
@@ -209,19 +265,12 @@ class IssueAssets extends React.Component {
                       disabled = {true}
                       fieldProps={receiver.amount}
                     />:
-                    <div>
-                      {
-                        showBtmAmountUnit ?
-                          <AmountUnitField title={t('form.amount')}
-                          fieldProps={receiver.amount}
-                          />
-                          :
-                          <AmountInputMask title={t('form.amount')}
-                                           fieldProps={receiver.amount}
-                                           decimal={assetDecimal}
-                          />
-                      }
-                    </div>
+                    <AmountField
+                      isBTM={showBtmAmountUnit}
+                      title={t('form.amount')}
+                      fieldProps={receiver.amount}
+                      decimal={assetDecimal}
+                    />
                 }
 
                 <button
@@ -249,34 +298,33 @@ class IssueAssets extends React.Component {
 
             {
               submitAction.value === 'sign'?
-                <div className={styles.item}>
-                    <TextField title={t('form.address')}
-                           disabled = {true}
-                           fieldProps={accountAlias}/>
                   <TextField title={'gas'}
                            disabled = {true}
                            fieldProps={gas}/>
-                </div>
+                // </div>
                 :
-                <div className={styles.item}>
-                  <ObjectSelectorField
-                    key='account-selector-field'
-                    keyIndex='normaltx-account'
-                    title={t('form.account')}
-                    aliasField={Autocomplete.AccountAlias}
-                    fieldProps={{
-                      id: accountId,
-                      alias: accountAlias
-                    }}
-                  />
+                // <div className={styles.item}>
+                //   <ObjectSelectorField
+                //     key='account-selector-field'
+                //     keyIndex='normaltx-account'
+                //     title={t('form.account')}
+                //     aliasField={Autocomplete.AccountAlias}
+                //     fieldProps={{
+                //       id: accountId,
+                //       alias: accountAlias
+                //     }}
+                //   />
                 <AmountUnitField title={'gas'} fieldProps={gas}/>
-              </div>
+              // </div>
             }
 
         </FormSection>
 
         <FormSection  title= { 'transaction'}>
-          <RadioField title={t('transaction.advance.buildType')} options={options} fieldProps={submitAction} />
+          <RadioField title={t('transaction.advance.buildType')} options={options} fieldProps={{
+            ...submitAction,
+            // onChange: submitactionOnChange,
+          }} />
           {
             submitAction.value === 'sign' &&
             <TextField
@@ -299,24 +347,8 @@ class IssueAssets extends React.Component {
             fieldProps={password}
           />
         </FormSection>
+      </TxContainer>
 
-        <FormSection >
-          {error &&
-          <ErrorBanner
-            title={t('form.errorTitle')}
-            error={error} />}
-
-          <div className={styles.submit}>
-            <button type='submit' className='btn btn-primary' disabled={submitting || this.disableSubmit(actions)}>
-              {submitLabel ||  t('form.submit')}
-            </button>
-
-            { submitting &&
-            <SubmitIndicator />
-            }
-          </div>
-        </FormSection>
-      </form>
     )
   }
 }
@@ -375,7 +407,16 @@ const mapDispatchToProps = (dispatch) => ({
 
 const mapStateToProps = (state, ownProps) => ({
   ...BaseNew.mapStateToProps('transaction')(state, ownProps),
-  decodedTx: state.transaction.decodedTx
+  decodedTx: state.transaction.decodedTx,
+  initialValues:{
+    assetAlias: ownProps.location.query.alias,
+    submitAction: 'submit',
+    receivers:[{
+      id: 0,
+      amount:'',
+      address:''
+    }]
+  }
 })
 
 export default withNamespaces('translations') (BaseNew.connect(
@@ -400,14 +441,6 @@ export default withNamespaces('translations') (BaseNew.connect(
     asyncBlurFields: ['receivers[].address'],
     validate,
     touchOnChange: true,
-    initialValues: {
-      submitAction: 'submit',
-      receivers:[{
-        id: 0,
-        amount:'',
-        address:''
-      }]
-    },
   }
   )(IssueAssets)
 ))
index 30ed3ab..c2a894e 100644 (file)
@@ -124,9 +124,8 @@ class Form extends React.Component {
 
               {this.props.issueAssetSelected &&
               <IssueAssets
-                btmAmountUnit={this.props.btmAmountUnit}
-                asset={this.props.asset}
                 handleKeyDown={this.handleKeyDown}
+                {...this.props}
               />}
           </div>
 
index 45c78af..d02440a 100644 (file)
   display: flex;
   position: relative;
 
-  >div:first-of-type{
-    width: 50%;
-  }
-
-  >div:last-of-type{
-    width: 50%;
-    margin-left: $gutter-size;
+  :global {
+    .form-group {
+      flex: 1;
+      &:not(:last-child) {
+        margin-right: $gutter-size;
+      }
+    }
   }
 }
 
diff --git a/src/features/transactions/components/New/NewTransactionsContainer/TxContainer.jsx b/src/features/transactions/components/New/NewTransactionsContainer/TxContainer.jsx
new file mode 100644 (file)
index 0000000..c19e31e
--- /dev/null
@@ -0,0 +1,36 @@
+import React from 'react'
+import { ErrorBanner, FormSection, SubmitIndicator } from 'features/shared/components'
+import disableAutocomplete from 'utility/disableAutocomplete'
+
+import styles from './TxContainer.scss'
+import {withNamespaces} from 'react-i18next'
+
+class TxContainer extends React.Component {
+  render() {
+    const t = this.props.t
+    return(
+      <form className={this.props.className} onSubmit={this.props.onSubmit} {...disableAutocomplete}>
+        {this.props.children}
+
+        <FormSection>
+          {this.props.error && this.props.error.message !== 'PasswordWrong' &&
+          <ErrorBanner
+            title={ t('form.errorTitle')}
+            error={this.props.error} />}
+
+          <div className={styles.submit}>
+            <button type='submit' className='btn btn-primary' disabled={this.props.submitting || this.props.disabled}>
+              {this.props.submitLabel ||  (t('form.submit'))}
+            </button>
+
+            {this.props.showSubmitIndicator && this.props.submitting &&
+            <SubmitIndicator />
+            }
+          </div>
+        </FormSection>
+      </form>
+    )
+  }
+}
+
+export default withNamespaces('translations') (TxContainer)
diff --git a/src/features/transactions/components/New/NewTransactionsContainer/TxContainer.scss b/src/features/transactions/components/New/NewTransactionsContainer/TxContainer.scss
new file mode 100644 (file)
index 0000000..9e4c536
--- /dev/null
@@ -0,0 +1,17 @@
+.main {
+  background: $background-color;
+  display: flex;
+  flex-direction: row;
+  padding: 0 $gutter-size;
+  margin-top: $title-height;
+}
+
+.content {
+  min-width: 400px;
+  width: 55%;
+  margin: 0 auto;
+}
+
+.submit {
+  text-align: right;
+}
index 213d8ad..1d66e11 100644 (file)
@@ -1,19 +1,16 @@
 import {
   BaseNew,
-  FormSection,
   TextField,
   Autocomplete,
   ObjectSelectorField,
-  AmountUnitField,
-  AmountInputMask,
-  ErrorBanner,
+  AmountField,
   GasField
 } from 'features/shared/components'
 import {chainClient} from 'utility/environment'
 import {reduxForm} from 'redux-form'
 import React from 'react'
 import styles from './New.scss'
-import disableAutocomplete from 'utility/disableAutocomplete'
+import  TxContainer  from './NewTransactionsContainer/TxContainer'
 import { btmID } from 'utility/environment'
 import actions from 'actions'
 import ConfirmModal from './ConfirmModal/ConfirmModal'
@@ -164,11 +161,14 @@ class NormalTxForm extends React.Component {
     const showBtmAmountUnit = (assetAlias.value === 'BTM' || assetId.value === btmID)
 
     return (
-        <form
-          className={styles.container}
-          onSubmit={e => this.confirmedTransaction(e, assetDecimal)}
-          {...disableAutocomplete}
-        >
+          <TxContainer
+            error={error}
+            onSubmit={e => this.confirmedTransaction(e, assetDecimal)}
+            submitting={submitting}
+            submitLabel= {submitLabel}
+            disabled={this.disableSubmit()}
+            className={styles.container}
+          >
           <div className={styles.borderBottom}>
             <label className={styles.title}>{t('transaction.normal.from')}</label>
             <div className={`${styles.mainBox} ${this.props.tutorialVisible? styles.tutorialItem: styles.item}`}>
@@ -213,12 +213,12 @@ class NormalTxForm extends React.Component {
                   },
                 }}/>
 
-                {!showBtmAmountUnit &&
-                <AmountInputMask title={t('form.amount')} fieldProps={receiver.amount} decimal={assetDecimal}
-                />}
-                {showBtmAmountUnit &&
-                <AmountUnitField title={t('form.amount')} fieldProps={receiver.amount}/>
-                }
+                <AmountField
+                  isBTM={showBtmAmountUnit}
+                  title={t('form.amount')}
+                  fieldProps={receiver.amount}
+                  decimal={assetDecimal}
+                />
 
                 <button
                   className={`btn btn-danger btn-xs ${styles.deleteButton}`}
@@ -255,21 +255,7 @@ class NormalTxForm extends React.Component {
               <span className={styles.feeDescription}> {t('transaction.normal.feeDescription')}</span>
             </div>
           </div>
-
-          <FormSection className={styles.submitSection}>
-            {error && error.message !== 'PasswordWrong' &&
-            <ErrorBanner
-              title={t('form.errorTitle')}
-              error={error} />}
-
-            <div className={styles.submit}>
-              <button type='submit' className='btn btn-primary'
-                      disabled={submitting || this.disableSubmit()}>
-                {submitLabel}
-              </button>
-            </div>
-          </FormSection>
-        </form>
+        </TxContainer>
     )
   }
 }