Browse Source

Merge pull request #25 from SuperNETorg/v0.25

V0.25
v0.25
pbca26 7 years ago
committed by GitHub
parent
commit
f6c5489247
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      react/src/actions/actions/elections.js
  2. 4
      react/src/actions/actions/electrum.js
  3. BIN
      react/src/assets/images/cryptologo/vote.png
  4. 3
      react/src/components/addcoin/addcoinOptionsAC.js
  5. 243
      react/src/components/dashboard/notaryElectionsModal/notaryElectionsModal.js
  6. 29
      react/src/components/dashboard/notaryElectionsModal/notaryElectionsModal.scss
  7. 26
      react/src/components/dashboard/walletsData/walletsData.render.js
  8. 9
      react/src/components/dashboard/walletsData/walletsData.scss
  9. 1
      react/src/components/dashboard/walletsTxInfo/walletsTxInfo.render.js
  10. 1
      react/src/translate/en.js
  11. 4
      react/src/util/coinHelper.js

35
react/src/actions/actions/elections.js

@ -165,4 +165,39 @@ export function shepherdElectionsSend(coin, value, sendToAddress, changeAddress,
resolve(json);
});
});
}
export function shepherdElectionsSendMany(coin, targets, change, opreturn) {
return new Promise((resolve, reject) => {
return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/electrum/createrawtx-multiout`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
token: Config.token,
coin,
targets,
change,
opreturn,
push: true,
verify: false,
vote: true,
}),
})
.catch((error) => {
console.log(error);
Store.dispatch(
triggerToaster(
'shepherdElectionsSendMany',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
resolve(json);
});
});
}

4
react/src/actions/actions/electrum.js

@ -362,12 +362,12 @@ export function shepherdElectrumBip39Keys(seed, match, addressdepth, accounts) {
});
}
// split test
// split utxo
export function shepherdElectrumSplitUtxoPromise(payload) {
console.warn(payload);
return new Promise((resolve, reject) => {
return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/electrum/createrawtx-test`, {
return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/electrum/createrawtx-split`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',

BIN
react/src/assets/images/cryptologo/vote.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

3
react/src/components/addcoin/addcoinOptionsAC.js

@ -24,7 +24,8 @@ const addCoinOptionsAC = () => {
'etomic',
'btch',
'beer',
'pizza'
'pizza',
'vote'
];
let _items = [];

243
react/src/components/dashboard/notaryElectionsModal/notaryElectionsModal.js

@ -4,6 +4,7 @@ import { translate } from '../../../translate/translate';
import {
toggleNotaryElectionsModal,
shepherdElectionsSend,
shepherdElectionsSendMany,
shepherdElectionsLogout,
shepherdElectionsLogin,
shepherdElectionsStatus,
@ -35,6 +36,11 @@ class NotaryElectionsModal extends React.Component {
pub: null,
amount: 0,
address: '',
voteType: 'multi',
multiOutAddress1: '',
multiOutAddress2: '',
multiOutAddress3: '',
multiOutAddress4: '',
};
this.defaultState = JSON.parse(JSON.stringify(this.state));
this.closeModal = this.closeModal.bind(this);
@ -42,13 +48,16 @@ class NotaryElectionsModal extends React.Component {
this.resizeLoginTextarea = this.resizeLoginTextarea.bind(this);
this.updateLoginPassPhraseInput = this.updateLoginPassPhraseInput.bind(this);
this.setUserType = this.setUserType.bind(this);
this.setVoteType = this.setVoteType.bind(this);
this.setRegion = this.setRegion.bind(this);
this.loginSeed = this.loginSeed.bind(this);
this.logout = this.logout.bind(this);
this.sync = this.sync.bind(this);
this.send = this.send.bind(this);
this.sendMulti = this.sendMulti.bind(this);
this.updateInput = this.updateInput.bind(this);
this.sendValidate = this.sendValidate.bind(this);
this.verifyMultiSendForm = this.verifyMultiSendForm.bind(this);
this.electionsDataInterval = null;
}
@ -105,20 +114,52 @@ class NotaryElectionsModal extends React.Component {
return valid;
}
send() {
if (this.sendValidate()) {
shepherdElectionsSend(
sendMulti() {
const _divisor = 10;
let _addressValidateMsg = [];
for (let i = 0; i < 4; i++) {
const _validateAddress = mainWindow.addressVersionCheck(this.state.coin, this.state[`multiOutAddress${i + 1}`]);
if (!_validateAddress ||
_validateAddress === 'Invalid pub address') {
_addressValidateMsg.push(this.state[`multiOutAddress${i + 1}`]);
}
}
if (_addressValidateMsg.length) {
Store.dispatch(
triggerToaster(
`Address(es) ${_addressValidateMsg.join(', ')} is(are) invalid!`,
'Notary voting 2018',
'error',
false
)
);
} else {
shepherdElectionsSendMany(
this.state.coin,
(this.state.amount * 100000000) - 10000,
this.state.address,
[{
address: this.state.multiOutAddress1,
value: parseInt((this.state.balance / _divisor) * 100000000),
}, {
address: this.state.multiOutAddress2,
value: parseInt((this.state.balance / _divisor) * 100000000),
}, {
address: this.state.multiOutAddress3,
value: parseInt((this.state.balance / _divisor) * 100000000),
}, {
address: this.state.multiOutAddress4,
value: parseInt((this.state.balance / _divisor) * 100000000),
}],
this.state.pub,
'ne2k18-' + this.state.region,
['ne2k18-na-1-eu-2-ae-3-sh-4']
)
.then((res) => {
if (res.msg === 'success') {
Store.dispatch(
triggerToaster(
`You succesfully voted ${this.state.amount} for ${this.state.address}`,
`You succesfully voted`,
'Notary voting 2018',
'success',
false
@ -126,13 +167,29 @@ class NotaryElectionsModal extends React.Component {
);
let _transactions = this.state.transactions;
_transactions.unshift({
address: this.state.address,
amount: this.state.amount - 0.0001,
region: 'ne2k18-' + this.state.region,
address: this.state.multiOutAddress1,
amount: this.state.balance / _divisor,
region: 'ne2k18-na',
timestamp: Math.floor(Date.now() / 1000),
}, {
address: this.state.multiOutAddress2,
amount: this.state.balance / _divisor,
region: 'ne2k18-eu',
timestamp: Math.floor(Date.now() / 1000),
}, {
address: this.state.multiOutAddress3,
amount: this.state.balance / _divisor,
region: 'ne2k18-ae',
timestamp: Math.floor(Date.now() / 1000),
}, {
address: this.state.multiOutAddress4,
amount: this.state.balance / _divisor,
region: 'ne2k18-sh',
timestamp: Math.floor(Date.now() / 1000),
});
this.setState({
transactions: _transactions,
balance: 0,
});
} else {
Store.dispatch(
@ -147,6 +204,64 @@ class NotaryElectionsModal extends React.Component {
}
}
send() {
const _validateAddress = mainWindow.addressVersionCheck(this.state.coin, this.state.address);
if (!_validateAddress ||
_validateAddress === 'Invalid pub address') {
_addressValidateMsg.push(this.state[`multiOutAddress${i + 1}`]);
Store.dispatch(
triggerToaster(
`Address ${this.state.address} is invalid!`,
'Notary voting 2018',
'error',
false
)
);
} else {
if (this.sendValidate()) {
shepherdElectionsSend(
this.state.coin,
(this.state.amount * 100000000) - 10000,
this.state.address,
this.state.pub,
'ne2k18-' + this.state.region,
)
.then((res) => {
if (res.msg === 'success') {
Store.dispatch(
triggerToaster(
`You succesfully voted ${this.state.amount} for ${this.state.address}`,
'Notary voting 2018',
'success',
false
)
);
let _transactions = this.state.transactions;
_transactions.unshift({
address: this.state.address,
amount: this.state.amount - 0.0001,
region: 'ne2k18-' + this.state.region,
timestamp: Math.floor(Date.now() / 1000),
});
this.setState({
transactions: _transactions,
balance: this.state.balance - this.state.amount - 0.0001,
});
} else {
Store.dispatch(
triggerToaster(
res.result.txid || res.result,
'Notary voting 2018',
'error'
)
);
}
});
}
}
}
sync() {
shepherdElectionsStatus()
.then((res) => {
@ -216,6 +331,12 @@ class NotaryElectionsModal extends React.Component {
});
}
setVoteType(type) {
this.setState({
voteType: type,
});
}
toggleSeedInputVisibility() {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
@ -262,6 +383,7 @@ class NotaryElectionsModal extends React.Component {
isAuth: true,
pub: res.result,
});
this.sync();
} else {
Store.dispatch(
triggerToaster(
@ -281,8 +403,6 @@ class NotaryElectionsModal extends React.Component {
// reset login input vals
this.refs.loginPassphrase.value = '';
this.refs.loginPassphraseTextarea.value = '';
this.sync();
}
logout() {
@ -305,6 +425,17 @@ class NotaryElectionsModal extends React.Component {
}
}
verifyMultiSendForm() {
if (!this.state.multiOutAddress1 || !this.state.multiOutAddress1.length ||
!this.state.multiOutAddress2 || !this.state.multiOutAddress2.length ||
!this.state.multiOutAddress3 || !this.state.multiOutAddress3.length ||
!this.state.multiOutAddress4 || !this.state.multiOutAddress4.length) {
return false;
} else {
return true;
}
}
renderHistoryRegion(region) {
let _region;
@ -334,8 +465,8 @@ class NotaryElectionsModal extends React.Component {
_items.push(
<tr key={ `notary-elections-history-${i}` }>
<td>{ _history[i].address }</td>
<td>{ Number(_history[i].amount) }</td>
<td>{ this.renderHistoryRegion(_history[i].region) }</td>
<td>{ _history[i].amount === 'unknown' ? 'unknown' : Number(_history[i].amount) }</td>
<td>{ _history[i].region === 'unknown' ? 'unknown' : this.renderHistoryRegion(_history[i].region) }</td>
<td>{ secondsToString(_history[i].timestamp) }</td>
</tr>
);
@ -401,13 +532,13 @@ class NotaryElectionsModal extends React.Component {
<span className="margin-left-30 margin-right-30">|</span>
<a
className={ this.state.userType === 'candidate' ? 'active' : '' }
onClick={ () => this.setUserType('candidate') }><i className="fa fa-user margin-right-10"></i>I'm a candidate</a>
onClick={ () => this.setUserType('candidate') }><i className="fa fa-user-o margin-right-10"></i>I'm a candidate</a>
</div>
{ !this.state.isAuth &&
<div className="elections-login">
<label
className="floating-label"
htmlFor="inputPassword">{ translate('INDEX.WALLET_SEED') }</label>
htmlFor="inputPassword">{ this.state.userType === 'voter' ? translate('INDEX.WALLET_SEED') : 'Pub key' }</label>
<input
type="password"
name="loginPassphrase"
@ -445,7 +576,7 @@ class NotaryElectionsModal extends React.Component {
{ this.state.isAuth &&
this.state.userType === 'voter' &&
<div className="elections-voter-ui">
<div className="elections-map">
<div className={ 'elections-map' + (this.state.voteType === 'multi' ? ' disable' : '') }>
<img src={ `assets/images/world-map.png` } />
<div className={ 'elections-map-node elections-map-node--na' + (this.state.region === 'na' ? ' active' : '') }>
<label className="notary-elections-node-title">NA</label>
@ -481,7 +612,21 @@ class NotaryElectionsModal extends React.Component {
}
{ this.state.isAuth &&
this.state.userType === 'voter' &&
<div className="elections-send margin-top-10">
<div className={ 'elections-user-type' + (this.state.voteType === 'single' ? ' margin-bottom-30' : '') }>
<a
className={ this.state.voteType === 'multi' ? 'active' : '' }
onClick={ () => this.setVoteType('multi') }><i className="fa fa-users margin-right-10"></i>4-way vote</a>
<span className="margin-left-30 margin-right-30">|</span>
<a
className={ this.state.voteType === 'single' ? 'active' : '' }
onClick={ () => this.setVoteType('single') }><i className="fa fa-user margin-right-10"></i>1-way vote</a>
</div>
}
{ this.state.isAuth &&
this.state.userType === 'voter' &&
this.state.voteType === 'single' &&
this.state.balance > 0 &&
<div className="elections-send elections-send--single margin-top-10">
<input
type="text"
className="form-control block margin-bottom-10"
@ -506,6 +651,68 @@ class NotaryElectionsModal extends React.Component {
</button>
</div>
}
{ this.state.isAuth &&
this.state.userType === 'voter' &&
this.state.voteType === 'multi' &&
this.state.balance > 0 &&
<div className="elections-send margin-top-50">
<div className="margin-bottom-30">Each candidate is going to recieve 25% of your VOTE funds</div>
<div>
<label>NA</label>
<input
type="text"
className="form-control margin-left-15 margin-bottom-10"
name="multiOutAddress1"
value={ this.state.multiOutAddress1 !== 0 ? this.state.multiOutAddress1 : '' }
onChange={ this.updateInput }
placeholder="Enter an address for NA region"
autoComplete="off" />
<span className="margin-left-25">{ this.state.balance / 4 } VOTE</span>
</div>
<div className="margin-top-10">
<label>EU</label>
<input
type="text"
className="form-control margin-left-15 margin-bottom-10"
name="multiOutAddress2"
value={ this.state.multiOutAddress2 !== 0 ? this.state.multiOutAddress2 : '' }
onChange={ this.updateInput }
placeholder="Enter an address for EU region"
autoComplete="off" />
<span className="margin-left-25">{ this.state.balance / 4 } VOTE</span>
</div>
<div className="margin-top-10">
<label>AE</label>
<input
type="text"
className="form-control margin-left-15 margin-bottom-10"
name="multiOutAddress3"
value={ this.state.multiOutAddress3 !== 0 ? this.state.multiOutAddress3 : '' }
onChange={ this.updateInput }
placeholder="Enter an address for AE region"
autoComplete="off" />
<span className="margin-left-25">{ this.state.balance / 4 } VOTE</span>
</div>
<div className="margin-top-10">
<label>SH</label>
<input
type="text"
className="form-control margin-left-15 margin-bottom-10"
name="multiOutAddress4"
value={ this.state.multiOutAddress4 !== 0 ? this.state.multiOutAddress4 : '' }
onChange={ this.updateInput }
placeholder="Enter an address for SH region"
autoComplete="off" />
<span className="margin-left-25">{ this.state.balance / 4 } VOTE</span>
</div>
<button
onClick={ this.sendMulti }
disabled={ !this.verifyMultiSendForm() }
className="btn btn-md btn-primary btn-block ladda-button elections-login-btn margin-top-20">
Vote
</button>
</div>
}
{ this.displayTxHistoryRender() &&
<div>
<div className={ `elections-history` + (this.state.userType === 'voter' ? ' margin-top-20' : '') }>

29
react/src/components/dashboard/notaryElectionsModal/notaryElectionsModal.scss

@ -65,6 +65,10 @@
left: 0;
height: 350px;
text-align: center;
&.disable {
pointer-events: none;
}
}
.elections-map-node {
@ -154,18 +158,27 @@
.elections-send {
.form-control {
display: inline-block;
width: 250px;
}
.btn {
position: relative;
top: -6px;
left: 15px;
display: inline-block;
width: 350px;
}
.block {
width: 365px;
width: 400px;
display: block;
}
&.elections-send--single {
.btn {
position: relative;
top: -6px;
left: 15px;
display: inline-block;
}
.form-control {
width: 250px;
}
.block {
width: 365px;
}
}
}
}

26
react/src/components/dashboard/walletsData/walletsData.render.js

@ -152,6 +152,12 @@ export const TxTypeRender = function(category) {
<i className="icon fa-meh-o"></i> <span>{ translate('DASHBOARD.UNKNOWN') }</span>
</span>
);
} else if (category === 'self') {
return (
<span className="label label-info self-send">
<span>self</span>
</span>
);
}
};
@ -171,15 +177,17 @@ export const TxAmountRender = function(tx) {
return (
<span>
<span data-tip={ tx.amount * _amountNegative }>
{ formatValue(tx.amount) * _amountNegative || translate('DASHBOARD.UNKNOWN') }
{ Math.abs(tx.interest) !== Math.abs(tx.amount) ? (formatValue(tx.amount) * _amountNegative || translate('DASHBOARD.UNKNOWN')) : '' }
{ tx.interest &&
<span
className="tx-interest"
data-tip={ `${translate('DASHBOARD.SPV_CLAIMED_INTEREST')} ${formatValue(Math.abs(tx.interest))}` }>+{ formatValue(Math.abs(tx.interest)) }</span>
}
<ReactTooltip
effect="solid"
className="text-left" />
{ tx.interest &&
<ReactTooltip
effect="solid"
className="text-left" />
}
</span>
<ReactTooltip
effect="solid"
@ -190,15 +198,17 @@ export const TxAmountRender = function(tx) {
return (
<span>
{ tx.amount * _amountNegative || translate('DASHBOARD.UNKNOWN') }
{ Math.abs(tx.interest) !== Math.abs(tx.amount) ? (tx.amount * _amountNegative || translate('DASHBOARD.UNKNOWN')) : '' }
{ tx.interest &&
<span
className="tx-interest"
data-tip={ `${translate('DASHBOARD.SPV_CLAIMED_INTEREST')} ${Math.abs(tx.interest)}` }>+{ Math.abs(tx.interest) }</span>
}
<ReactTooltip
effect="solid"
className="text-left" />
{ tx.interest &&
<ReactTooltip
effect="solid"
className="text-left" />
}
</span>
);
};

9
react/src/components/dashboard/walletsData/walletsData.scss

@ -100,4 +100,13 @@
position: absolute;
right: 4px;
top: 3px;
}
.self-send {
background-color: #00bcd4;
border-color: #00bcd4;
font-size: 13px;
width: 44px;
display: block;
margin: 0 auto;
}

1
react/src/components/dashboard/walletsTxInfo/walletsTxInfo.render.js

@ -190,7 +190,6 @@ const WalletsTxInfoRender = function(txInfo) {
</div>
<div className="modal-footer">
{ this.state.txDetails &&
this.props.ActiveCoin.coin !== 'CHIPS' &&
explorerList[this.props.ActiveCoin.coin] &&
<button
type="button"

1
react/src/translate/en.js

@ -847,6 +847,7 @@ export const LANG_EN = {
'BTCH': 'BTCH (BTCH)',
'BEER': 'BEER (Test coin)',
'PIZZA': 'PIZZA (Test coin)',
'VOTE': 'VOTE (Notary Elections)',
},
'DEX': {
'GEN_NEW_PASSPHRASE': 'Generate a new passphrase',

4
react/src/util/coinHelper.js

@ -6,6 +6,10 @@ export function getCoinTitle(coin) {
let hideTitle = false;
switch (coin) {
case 'VOTE':
coinlogo = 'vote';
coinname = 'VOTE (Notary Elections)';
break;
case 'GRS':
coinlogo = 'grs';
coinname = 'Groestlcoin';

Loading…
Cancel
Save