OSDN Git Service

update multi-sign account mode.
authorZhiting Lin <zlin035@uottawa.ca>
Tue, 16 Jul 2019 03:02:35 +0000 (11:02 +0800)
committerZhiting Lin <zlin035@uottawa.ca>
Tue, 16 Jul 2019 03:02:35 +0000 (11:02 +0800)
src/features/accounts/actions.js
src/features/accounts/components/AccountShow.jsx
src/features/accounts/components/New.jsx
src/features/shared/components/XpubField/XpubField.jsx
src/sdk/api/accounts.js

index 89f3775..1273049 100644 (file)
@@ -1,6 +1,7 @@
 import { chainClient } from 'utility/environment'
 import { baseCreateActions, baseUpdateActions, baseListActions } from 'features/shared/actions'
 import {push} from 'react-router-redux'
+import action from 'actions'
 
 const type = 'account'
 
@@ -16,7 +17,15 @@ const update = baseUpdateActions(type, {
 
 const switchAccount = (accountAlias) => {
   return (dispatch) => {
-    dispatch({type: 'SET_CURRENT_ACCOUNT', account: accountAlias})
+    return action.transaction.getAddresses({accountAlias}).then(address => {
+      return chainClient().accounts.setMiningAddress({'miningAddress':address}).then(resp =>{
+        if (resp.status === 'fail') {
+          throw resp
+        }
+
+        dispatch({type: 'SET_CURRENT_ACCOUNT', account: accountAlias})
+      })
+    })
   }
 }
 
@@ -29,6 +38,7 @@ const setDefaultAccount = () =>{
     })
   }
 }
+
 const createAccount = (data) => {
   return (dispatch) => {
     if (typeof data.alias == 'string')  data.alias = data.alias.trim()
@@ -44,13 +54,21 @@ const createAccount = (data) => {
           throw resp
         }
 
+        if (data.xpubs) {
+          data.rootXpubs = [resp.data.xpub]
+          data.xpubs.forEach(key => {
+            if (key.value) {
+              data.rootXpubs.push(key.value)
+            }
+          })
+          delete data.xpubs
+        }
+
         const accountData = {
-          'root_xpubs':[resp.data.xpub],
-          'quorum':1,
+          'root_xpubs':data.rootXpubs,
+          'quorum':  parseInt(data.quorum),
           'alias': data.alias}
 
-        dispatch({type: 'NEW_KEY', data: resp.data.mnemonic})
-
         return chainClient().accounts.create(accountData)
           .then((resp) => {
             if (resp.status === 'fail') {
@@ -59,7 +77,7 @@ const createAccount = (data) => {
 
             if(resp.status === 'success') {
               dispatch({type: 'SET_CURRENT_ACCOUNT', account: resp.data.alias})
-              dispatch( push('/accounts/mnemonic') )
+              dispatch(createSuccess() )
             }
           })
           .catch((err) => {
index 55b1fe4..fa7b727 100644 (file)
@@ -114,7 +114,7 @@ class AccountShow extends BaseShow {
             <KeyValueTable
               key={index}
               title={t('account.xpubs', {id: index + 1})}
-              actions={[
+              actions={ index===0 && [
                 <Link key='check-password-btn' className='btn btn-link' to={`/accounts/key/check-password/${key}`}>{t('key.tryPassword') }</Link>,
                 <Link key='reset-password-btn' className='btn btn-link' to={`/accounts/key/reset-password/${key}`}>{t('key.resetPassword')}</Link>
               ]}
index cfa520b..c549b01 100644 (file)
@@ -1,5 +1,5 @@
 import React from 'react'
-import { BaseNew, FormContainer, FormSection, JsonField, PasswordField, TextField } from 'features/shared/components'
+import { BaseNew, FormContainer, FormSection, JsonField, KeyConfiguration, TextField, PasswordField } from 'features/shared/components'
 import { reduxForm } from 'redux-form'
 import {withNamespaces} from 'react-i18next'
 import actions from 'actions'
@@ -20,7 +20,7 @@ class Form extends React.Component {
 
   render() {
     const {
-      fields: { alias, password, repeatPassword },
+      fields: { alias, xpubs, quorum, password, confirmPassword },
       error,
       handleSubmit,
       submitting,
@@ -38,7 +38,15 @@ class Form extends React.Component {
         <FormSection title={ t('account.new.information') }>
           <TextField title={ t('form.alias')} placeholder={  t('form.alias')} fieldProps={alias} autoFocus={true} />
           <PasswordField title={ t('key.password')}  placeholder={ t('key.passwordPlaceholder')} fieldProps={password} autoFocus={false} />
-          <PasswordField title={ t('key.repeatPassword')} placeholder={ t('key.repeatPasswordPlaceholder')} fieldProps={repeatPassword} autoFocus={false} />
+          <PasswordField title={ t('key.repeatPassword')} placeholder={ t('key.repeatPasswordPlaceholder')} fieldProps={confirmPassword} autoFocus={false} />
+        </FormSection>
+
+        <FormSection title={ t('form.keyAndSign')}>
+          <KeyConfiguration
+            xpubs={xpubs}
+            quorum={quorum}
+            quorumHint={t('account.new.quorumHint')}
+          />
         </FormSection>
       </FormContainer>
     )
@@ -49,27 +57,51 @@ const validate = ( values, props ) => {
   const errors = { xpubs:{} }
   const t = props.t
 
+  const tagError = JsonField.validator(values.tags)
+  if (tagError) { errors.tags = tagError }
+
   if (!values.alias) { errors.alias = ( t('account.new.aliasWarning')) }
 
+  if (!values.password) {
+    errors.password = ( t('key.passwordRequired') )
+  }else if( values.password.length < 5 ) {
+    errors.password = ( t('key.reset.newPWarning'))
+  }
+  if ( values.password !== values.confirmPassword ) {
+    errors.confirmPassword = ( t('key.reset.repeatPWarning'))
+  }
+
+  values.xpubs.forEach((xpub, index) => {
+    if (index>0 && !values.xpubs[index].value) {
+      errors.xpubs[index] = {...errors.xpubs[index], value: ( t('account.new.keyWarning'))}
+    }
+  })
 
   return errors
 }
 
 const fields = [
   'alias',
+  'xpubs[].value',
+  'xpubs[].type',
+  'quorum',
   'password',
-  'repeatPassword'
+  'confirmPassword'
 ]
+const mapDispatchToProps = ( dispatch ) => ({
+  createAccount: (data) => dispatch(actions.account.createAccount(data)),
+  ...BaseNew.mapDispatchToProps('account')(dispatch)
+})
 
 export default withNamespaces('translations')( BaseNew.connect(
   BaseNew.mapStateToProps('account'),
-  (dispatch) => ({
-    ...BaseNew.mapDispatchToProps('account')(dispatch),
-    createAccount: (data) => dispatch(actions.account.createAccount(data))
-  }),
+  mapDispatchToProps,
   reduxForm({
     form: 'newAccountForm',
     fields,
     validate,
+    initialValues: {
+      quorum: 1,
+    }
   })(Form)
-))
+))
\ No newline at end of file
index e155ba0..2995c9d 100644 (file)
@@ -5,7 +5,7 @@ import { connect } from 'react-redux'
 import actions from 'features/mockhsm/actions'
 import {withNamespaces} from 'react-i18next'
 
-const methodOptions = ['mockhsm', 'provide']
+const methodOptions = ['provide']
 
 class XpubField extends React.Component {
   constructor(props) {
@@ -72,22 +72,38 @@ class XpubField extends React.Component {
           <tbody>
             {methodOptions.map((key) =>
               <tr key={`key-${this.props.index}-option-${key}`}>
-                <td className={styles.label}>
-                  <label>
-                    <input type='radio'
-                      className={styles.radio}
-                      name={`keys-${this.props.index}`}
-                      onChange={typeOnChange}
-                      checked={key == typeProps.value}
-                      value={key}
-                    />
-                    { t('xpub.methodOptions', { returnObjects: true })[key]}
-                  </label>
-                </td>
-
-                <td className={styles.field}>
-                  {typeProps.value == key && fields[key]}
-                </td>
+                {this.props.index === 0?
+                  <td>
+                    <label>
+                      <input type='radio'
+                             className={styles.radio}
+                             name={`keys-${this.props.index}`}
+                             onChange={typeOnChange}
+                             checked={key == typeProps.value}
+                             value={key}
+                             disabled
+                      />
+                      { t('xpub.methodOptions.currentAccount')}
+                    </label>
+                  </td>:[
+                    <td className={styles.label}>
+                      <label>
+                        <input type='radio'
+                          className={styles.radio}
+                          name={`keys-${this.props.index}`}
+                          onChange={typeOnChange}
+                          checked={key == typeProps.value}
+                          value={key}
+                          disabled
+                        />
+                        { t('xpub.methodOptions', { returnObjects: true })[key]}
+                      </label>
+                    </td>,
+                    <td className={styles.field}>
+                      {typeProps.value == key && fields[key]}
+                    </td>
+                  ]
+                }
               </tr>
             )}
           </tbody>
index f06effc..27c774b 100644 (file)
@@ -38,6 +38,11 @@ const accountsAPI = (client) => {
     validateAddresses: (address, cb) => shared.query(client, 'accounts', '/validate-address', {'address': address},  {cb}),
 
     listAccountVotes: (params, cb) => shared.query(client, 'accounts', '/list-account-votes', params, {cb}),
+
+    setMiningAddress: (params, cb) => shared.tryCallback(
+      client.request('/set-mining-address', params),
+      cb
+    ),
   }
 }