merge with master branch

This commit is contained in:
viktor 2018-03-21 09:35:41 +03:00
commit f6214dd79e
25 changed files with 2028 additions and 1388 deletions

1585
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@
"mobx-react-router": "^4.0.1", "mobx-react-router": "^4.0.1",
"moment": "^2.20.1", "moment": "^2.20.1",
"node-sass-chokidar": "0.0.3", "node-sass-chokidar": "0.0.3",
"nodemon": "^1.14.12",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",
"object-assign": "4.1.1", "object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.2.0", "postcss-flexbugs-fixes": "3.2.0",
@ -65,8 +66,8 @@
"scripts": { "scripts": {
"predeploy": "npm run build", "predeploy": "npm run build",
"deploy": "gh-pages -d build -o origin", "deploy": "gh-pages -d build -o origin",
"build-css": "node-sass-chokidar src/assets/App.scss -o src/assets", "build-css": "node-sass-chokidar src/assets/App.scss -o src/assets --output-style=compressed",
"watch-css": "npm run build-css && node-sass-chokidar src/assets/App.scss -o src/assets/src/assets --watch", "watch-css": "nodemon -e scss -x \"npm run build-css\"",
"start-js": "node scripts/start.js", "start-js": "node scripts/start.js",
"start": "npm-run-all -p watch-css start-js", "start": "npm-run-all -p watch-css start-js",
"build-js": "node scripts/build.js", "build-js": "node scripts/build.js",

File diff suppressed because one or more lines are too long

View File

@ -14,6 +14,7 @@
@import 'stylesheets/settings'; @import 'stylesheets/settings';
@import 'stylesheets/socials'; @import 'stylesheets/socials';
@import 'stylesheets/vote-scale'; @import 'stylesheets/vote-scale';
@import 'stylesheets/ballot-types';
@import 'stylesheets/ballots/placeholders'; @import 'stylesheets/ballots/placeholders';
@import 'stylesheets/ballots/base'; @import 'stylesheets/ballots/base';
@import 'stylesheets/ballots/about'; @import 'stylesheets/ballots/about';
@ -23,4 +24,4 @@
@import 'stylesheets/select/menu'; @import 'stylesheets/select/menu';
@import 'stylesheets/select/mixins'; @import 'stylesheets/select/mixins';
@import 'stylesheets/select/multi'; @import 'stylesheets/select/multi';
@import 'stylesheets/select/spinner'; @import 'stylesheets/select/spinner';

View File

@ -0,0 +1,30 @@
.ballot-types {
border-bottom: 1px solid #e5eef9;
padding: 0 30px 10px;
&-i {
cursor: pointer;
position: relative;
margin-bottom: 20px;
&:before {
content: '';
position: absolute;
left: -30px;
top: 50%;
opacity: 0;
height: 30px;
width: 3px;
transform: translateY(-50%);
background-color: #08b3f2;
}
&_active {
color: #08b3f2;
&:before {
opacity: 1;
}
}
}
}

View File

@ -6,7 +6,8 @@ label {
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
} }
input { input,
textarea {
@extend %form-el; @extend %form-el;
&:focus { &:focus {
@ -18,6 +19,14 @@ input {
} }
} }
textarea {
width: 100%;
padding-top: 10px;
padding-bottom: 10px;
height: 70px;
resize: none;
}
select { select {
@include image-2x('./images/select@2x.png', 8px, 4px); @include image-2x('./images/select@2x.png', 8px, 4px);
@extend %form-el; @extend %form-el;

View File

@ -1,15 +1,54 @@
.info { .info {
@include image-2x('./images/info@2x.png', 32px, 32px);
display: flex;
align-items: center;
padding-left: 44px;
min-height: 32px;
background-image: url(./images/info.png);
background-repeat: no-repeat;
background-position: left center;
color: #8197a2; color: #8197a2;
.ballots & { .ballots & {
margin-bottom: 20px; @include image-2x('./images/info@2x.png', 32px, 32px);
display: flex;
align-items: center;
padding-left: 44px;
min-height: 32px;
background-image: url(./images/info.png);
background-repeat: no-repeat;
background-position: left center;
}
.new-form & {
padding: 30px;
}
&-title {
position: relative;
margin-bottom: 30px;
padding-left: 44px;
&:before {
@include image-2x('./images/info@2x.png', 32px, 32px);
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 32px;
height: 32px;
}
}
&-i {
position: relative;
margin-bottom: 10px;
padding-left: 12px;
line-height: 18px;
font-size: 12px;
&:before {
content: '';
position: absolute;
left: 0;
top: 7px;
width: 4px;
height: 4px;
border-radius: 50%;
background-color: #08b3f2;
}
} }
} }

View File

@ -1,15 +1,41 @@
.new { .new {
&-form { &-form {
@extend %white-block; @extend %white-block;
display: flex;
overflow: hidden; overflow: hidden;
padding: 0;
&-footer { @media screen and (max-width: $tablet-width) {
display: flex; display: block;
align-items: center; }
justify-content: space-between;
@media screen and (max-width: $mobile-width) { &-side {
flex-direction: column; padding-top: 30px;
padding-bottom: 30px;
box-sizing: border-box;
@media screen and (max-width: $tablet-width) {
width: 100% !important;
}
&_left {
width: 30%;
@media screen and (max-width: $tablet-width) {
padding-bottom: 0;
}
}
&_right {
width: 70%;
border-left: 1px solid #e5eef9;
padding-left: 30px;
padding-right: 30px;
@media screen and (max-width: $tablet-width) {
border: 0;
padding-top: 0;
}
} }
} }
} }

View File

@ -29,6 +29,7 @@ export class BallotCard extends React.Component {
displayValue: zeroTimeTo, displayValue: zeroTimeTo,
title: "To close" title: "To close"
}; };
@observable creatorMiningKey;
@observable creator; @observable creator;
@observable progress; @observable progress;
@observable totalVoters; @observable totalVoters;
@ -45,8 +46,15 @@ export class BallotCard extends React.Component {
return cls; return cls;
} }
@computed get finalizeDescription () {
const _finalizeDescription = this.isFinalized ? '' : constants.CARD_FINALIZE_DESCRIPTION;
return _finalizeDescription;
}
@computed get votesForNumber() { @computed get votesForNumber() {
let votes = (this.totalVoters + this.progress) / 2; let votes = (this.totalVoters + this.progress) / 2;
if (isNaN(votes))
votes = 0;
return votes; return votes;
} }
@ -56,11 +64,15 @@ export class BallotCard extends React.Component {
} }
let votesPercents = Math.round(this.votesForNumber / this.totalVoters * 100); let votesPercents = Math.round(this.votesForNumber / this.totalVoters * 100);
if (isNaN(votesPercents))
votesPercents = 0;
return votesPercents; return votesPercents;
} }
@computed get votesAgainstNumber() { @computed get votesAgainstNumber() {
let votes = (this.totalVoters - this.progress) / 2; let votes = (this.totalVoters - this.progress) / 2;
if (isNaN(votes))
votes = 0;
return votes; return votes;
} }
@ -70,20 +82,32 @@ export class BallotCard extends React.Component {
} }
let votesPercents = Math.round(this.votesAgainstNumber / this.totalVoters * 100); let votesPercents = Math.round(this.votesAgainstNumber / this.totalVoters * 100);
if (isNaN(votesPercents))
votesPercents = 0;
return votesPercents; return votesPercents;
} }
@action("Get start time of keys ballot") @action("Get start time of keys ballot")
getStartTime = async () => { getStartTime = async () => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
let startTime = await this.getContract(contractsStore, votingType).getStartTime(id); let startTime;
try {
startTime = await this.getContract(contractsStore, votingType).getStartTime(id);
} catch(e) {
console.log(e.message);
}
this.startTime = moment.utc(startTime * 1000).format(USDateTimeFormat); this.startTime = moment.utc(startTime * 1000).format(USDateTimeFormat);
} }
@action("Get end time of keys ballot") @action("Get end time of keys ballot")
getEndTime = async () => { getEndTime = async () => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
let endTime = await this.getContract(contractsStore, votingType).getEndTime(id); let endTime;
try {
endTime = await this.getContract(contractsStore, votingType).getEndTime(id);
} catch(e) {
console.log(e.message);
}
this.endTime = moment.utc(endTime * 1000).format(USDateTimeFormat); this.endTime = moment.utc(endTime * 1000).format(USDateTimeFormat);
} }
@ -96,12 +120,13 @@ export class BallotCard extends React.Component {
let msFinish = finish.diff(_now); let msFinish = finish.diff(_now);
if (msStart > 0) { if (msStart > 0) {
this.timeToStart.val = msStart; this.timeToStart.val = msStart + 5000;
this.timeToStart.displayValue = this.formatMs(msStart, ":mm:ss"); this.timeToStart.displayValue = this.formatMs(msStart, ":mm:ss");
return this.timeTo = this.timeToStart; return this.timeTo = this.timeToStart;
} }
if (msFinish > 0) { if (msFinish > 0) {
this.timeToStart.val = 0;
this.timeToFinish.val = msFinish; this.timeToFinish.val = msFinish;
this.timeToFinish.displayValue = this.formatMs(msFinish, ":mm:ss"); this.timeToFinish.displayValue = this.formatMs(msFinish, ":mm:ss");
return this.timeTo = this.timeToFinish; return this.timeTo = this.timeToFinish;
@ -131,55 +156,106 @@ export class BallotCard extends React.Component {
@action("Get creator") @action("Get creator")
getCreator = async () => { getCreator = async () => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
let votingState = await this.getContract(contractsStore, votingType).votingState(id); let votingState;
this.getValidatorFullname(votingState.creator); try {
votingState = await this.getContract(contractsStore, votingType).votingState(id);
} catch(e) {
console.log(e.message);
}
if (votingState) {
this.getValidatorFullname(votingState.creator);
}
} }
@action("Get progress") @action("Get progress")
getProgress = async () => { getProgress = async () => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
let progress = await this.getContract(contractsStore, votingType).getProgress(id); let progress;
this.progress = Number(progress); try {
progress = await this.getContract(contractsStore, votingType).getProgress(id);
} catch(e) {
console.log(e.message);
}
if (progress) {
this.progress = Number(progress);
}
} }
@action("Get total voters") @action("Get total voters")
getTotalVoters = async () => { getTotalVoters = async () => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
let totalVoters = await this.getContract(contractsStore, votingType).getTotalVoters(id); let totalVoters;
this.totalVoters = Number(totalVoters); try {
totalVoters = await this.getContract(contractsStore, votingType).getTotalVoters(id);
} catch(e) {
console.log(e.message);
}
if (totalVoters) {
this.totalVoters = Number(totalVoters);
}
} }
@action("Get isFinalized") @action("Get isFinalized")
getIsFinalized = async() => { getIsFinalized = async() => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
this.isFinalized = await this.getContract(contractsStore, votingType).getIsFinalized(id); let isFinalized;
try {
isFinalized = await this.getContract(contractsStore, votingType).getIsFinalized(id);
} catch(e) {
console.log(e.message);
}
this.isFinalized = isFinalized;
} }
@action("Get validator full name") @action("Get validator full name")
getValidatorFullname = async (_miningKey) => { getValidatorFullname = async (_miningKey) => {
const { contractsStore } = this.props; const { contractsStore } = this.props;
let validator = await contractsStore.validatorMetadata.validators(_miningKey); let validator;
let firstName = toAscii(validator.firstName); try {
let lastName = toAscii(validator.lastName); validator = await contractsStore.validatorMetadata.validators(_miningKey);
let fullName = `${firstName} ${lastName}`; } catch(e) {
console.log(e.message);
}
let firstName, lastName, fullName
if (validator) {
firstName = toAscii(validator.firstName);
lastName = toAscii(validator.lastName);
fullName = `${firstName} ${lastName}`;
}
this.creatorMiningKey = _miningKey;
this.creator = fullName ? fullName : _miningKey; this.creator = fullName ? fullName : _miningKey;
} }
isValidaVote = async () => { isValidVote = async () => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
let isValidVote = await this.getContract(contractsStore, votingType).isValidVote(id, contractsStore.votingKey); let _isValidVote;
return isValidVote; try {
_isValidVote = await this.getContract(contractsStore, votingType).isValidVote(id, contractsStore.votingKey);
} catch(e) {
console.log(e.message);
}
return _isValidVote;
} }
isActive = async () => { isActive = async () => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
let isActive = await this.getContract(contractsStore, votingType).isActive(id); let _isActive;
return isActive; try {
_isActive = await this.getContract(contractsStore, votingType).isActive(id);
} catch(e) {
console.log(e.message);
}
return _isActive;
} }
getMemo = async () => { getMemo = async () => {
const { contractsStore, id, votingType } = this.props; const { contractsStore, id, votingType } = this.props;
let memo = await this.getContract(contractsStore, votingType).getMemo(id); let memo;
try {
memo = await this.getContract(contractsStore, votingType).getMemo(id);
} catch(e) {
console.log(e.message);
}
this.memo = memo; this.memo = memo;
return memo; return memo;
} }
@ -196,7 +272,7 @@ export class BallotCard extends React.Component {
return; return;
} }
commonStore.showLoading(); commonStore.showLoading();
let isValidVote = await this.isValidaVote(); let isValidVote = await this.isValidVote();
if (!isValidVote) { if (!isValidVote) {
commonStore.hideLoading(); commonStore.hideLoading();
swal("Warning!", messages.INVALID_VOTE_MSG, "warning"); swal("Warning!", messages.INVALID_VOTE_MSG, "warning");
@ -309,8 +385,20 @@ export class BallotCard extends React.Component {
let { commonStore } = this.props; let { commonStore } = this.props;
if (commonStore.searchTerm) { if (commonStore.searchTerm) {
if (commonStore.searchTerm.length > 0) { if (commonStore.searchTerm.length > 0) {
const isCreatorPattern = String(this.creator).toLowerCase().includes(commonStore.searchTerm); const _isCreatorPattern = String(this.creator).toLowerCase().includes(commonStore.searchTerm);
return isCreatorPattern; const _isCreatorMiningKeyPattern = String(this.creatorMiningKey).toLowerCase().includes(commonStore.searchTerm);
return _isCreatorPattern || _isCreatorMiningKeyPattern;
}
}
return true;
}
isMemoPattern = () => {
let { commonStore } = this.props;
if (commonStore.searchTerm) {
if (commonStore.searchTerm.length > 0) {
const _isMemoPattern = String(this.memo).toLowerCase().includes(commonStore.searchTerm);
return _isMemoPattern;
} }
} }
return true; return true;
@ -332,7 +420,7 @@ export class BallotCard extends React.Component {
render () { render () {
let { contractsStore, votingType, children, isSearchPattern } = this.props; let { contractsStore, votingType, children, isSearchPattern } = this.props;
console.log(votingType); console.log(votingType);
let ballotClass = (this.showCard() && (this.isCreatorPattern() || isSearchPattern)) ? "ballots-i" : "ballots-i display-none"; let ballotClass = (this.showCard() && (this.isCreatorPattern() || this.isMemoPattern() || isSearchPattern)) ? "ballots-i" : "ballots-i display-none";
const threshold = this.getThreshold(contractsStore, votingType); const threshold = this.getThreshold(contractsStore, votingType);
return ( return (
<div className={ballotClass}> <div className={ballotClass}>
@ -349,7 +437,7 @@ export class BallotCard extends React.Component {
{children} {children}
<div className="ballots-about-i ballots-about-i_time"> <div className="ballots-about-i ballots-about-i_time">
<div className="ballots-about-td"> <div className="ballots-about-td">
<p className="ballots-about-i--title">Time</p> <p className="ballots-about-i--title">Ballot Time</p>
</div> </div>
<div className="ballots-about-td"> <div className="ballots-about-td">
<p className="ballots-i--time">{this.timeTo.displayValue}</p> <p className="ballots-i--time">{this.timeTo.displayValue}</p>
@ -391,11 +479,11 @@ export class BallotCard extends React.Component {
<div className="ballots-footer"> <div className="ballots-footer">
<div className="ballots-footer-left"> <div className="ballots-footer-left">
<button type="button" onClick={(e) => this.finalize(e)} className={this.finalizeButtonClass}>{this.finalizeButtonDisplayName}</button> <button type="button" onClick={(e) => this.finalize(e)} className={this.finalizeButtonClass}>{this.finalizeButtonDisplayName}</button>
<p>{constants.CARD_FINALIZE_DESCRIPTION}</p> <p>{this.finalizeDescription}</p>
</div> </div>
<div type="button" className="ballots-i--vote ballots-i--vote_no">{this.typeName(votingType)} Ballot ID: {this.props.id}</div> <div type="button" className="ballots-i--vote ballots-i--vote_no">{this.typeName(votingType)} Ballot ID: {this.props.id}</div>
</div> </div>
</div> </div>
); );
} }
} }

View File

@ -54,7 +54,12 @@ export class BallotKeysCard extends React.Component {
@action("Get ballot type of keys ballot") @action("Get ballot type of keys ballot")
getBallotType = async () => { getBallotType = async () => {
const { contractsStore, id } = this.props; const { contractsStore, id } = this.props;
let ballotType = await contractsStore.votingToChangeKeys.getBallotType(id); let ballotType;
try {
ballotType = await contractsStore.votingToChangeKeys.getBallotType(id);
} catch(e) {
console.log(e.message);
}
this.ballotType = ballotType; this.ballotType = ballotType;
this.getBallotTypeDisplayName(ballotType); this.getBallotTypeDisplayName(ballotType);
} }
@ -62,7 +67,12 @@ export class BallotKeysCard extends React.Component {
@action("Get affected key type of keys ballot") @action("Get affected key type of keys ballot")
getAffectedKeyType = async () => { getAffectedKeyType = async () => {
const { contractsStore, id } = this.props; const { contractsStore, id } = this.props;
let affectedKeyType = await contractsStore.votingToChangeKeys.getAffectedKeyType(id); let affectedKeyType;
try {
affectedKeyType = await contractsStore.votingToChangeKeys.getAffectedKeyType(id);
} catch(e) {
console.log(e.message);
}
this.affectedKeyType = affectedKeyType; this.affectedKeyType = affectedKeyType;
this.getAffectedKeyTypeDisplayName(affectedKeyType); this.getAffectedKeyTypeDisplayName(affectedKeyType);
} }
@ -71,15 +81,33 @@ export class BallotKeysCard extends React.Component {
@action("Get affected key of keys ballot") @action("Get affected key of keys ballot")
getAffectedKey = async () => { getAffectedKey = async () => {
const { contractsStore, id } = this.props; const { contractsStore, id } = this.props;
let affectedKey = await contractsStore.votingToChangeKeys.getAffectedKey(id); let affectedKey;
try {
affectedKey = await contractsStore.votingToChangeKeys.getAffectedKey(id);
} catch (e) {
console.log(e.message);
}
this.affectedKey = affectedKey; this.affectedKey = affectedKey;
} }
@action("Get mining key of keys ballot") @action("Get mining key of keys ballot")
getMiningKey = async () => { getMiningKey = async () => {
const { contractsStore, id } = this.props; const { contractsStore, id } = this.props;
let miningKey = await contractsStore.votingToChangeKeys.getMiningKey(id); let miningKey, metadata;
const metadata = await contractsStore.getValidatorMetadata(miningKey) try {
this.miningKey = `${metadata.lastName} ${miningKey}`; miningKey = await contractsStore.votingToChangeKeys.getMiningKey(id);
} catch(e) {
console.log(e.message);
}
try {
metadata = await contractsStore.getValidatorMetadata(miningKey);
} catch(e) {
console.log(e.message);
}
if (metadata) {
this.miningKey = `${metadata.lastName} ${miningKey}`;
} else {
this.miningKey = `${miningKey}`;
}
} }
constructor(props) { constructor(props) {
@ -93,10 +121,11 @@ export class BallotKeysCard extends React.Component {
isSearchPattern = () => { isSearchPattern = () => {
let { commonStore } = this.props; let { commonStore } = this.props;
if (commonStore.searchTerm) { if (commonStore.searchTerm) {
const isMiningKeyPattern = String(this.miningKey).toLowerCase().includes(commonStore.searchTerm);
const isAffectedKeyPattern = String(this.affectedKey).toLowerCase().includes(commonStore.searchTerm); const isAffectedKeyPattern = String(this.affectedKey).toLowerCase().includes(commonStore.searchTerm);
const isAffectedKeyTypeDisplayNamePattern = String(this.affectedKeyTypeDisplayName).toLowerCase().includes(commonStore.searchTerm); const isAffectedKeyTypeDisplayNamePattern = String(this.affectedKeyTypeDisplayName).toLowerCase().includes(commonStore.searchTerm);
const isBallotTypeDisplayNamePattern = String(this.ballotTypeDisplayName).toLowerCase().includes(commonStore.searchTerm); const isBallotTypeDisplayNamePattern = String(this.ballotTypeDisplayName).toLowerCase().includes(commonStore.searchTerm);
return (isAffectedKeyPattern || isAffectedKeyTypeDisplayNamePattern || isBallotTypeDisplayNamePattern); return (isMiningKeyPattern || isAffectedKeyPattern || isAffectedKeyTypeDisplayNamePattern || isBallotTypeDisplayNamePattern);
} }
return true; return true;
} }

View File

@ -26,10 +26,10 @@ export class BallotKeysMetadata extends React.Component {
</div> </div>
<div className="right"> <div className="right">
<div className="form-el"> <div className="form-el">
<label htmlFor="key">Mining Key</label> <label htmlFor="mining-key">Mining Key</label>
<Select.Creatable <Select.Creatable
name="form-field-name" name="form-field-name"
id="key" id="mining-key"
value={ballotStore.ballotKeys.miningKey} value={ballotStore.ballotKeys.miningKey}
onChange={ballotStore.setMiningKey} onChange={ballotStore.setMiningKey}
options={options} options={options}
@ -41,8 +41,8 @@ export class BallotKeysMetadata extends React.Component {
</div> </div>
<div className="left"> <div className="left">
<div className="form-el"> <div className="form-el">
<label htmlFor="key">Ballot End</label> <label htmlFor="datetime-local">Ballot End</label>
<input type="datetime-local" id="key" <input type="datetime-local" id="datetime-local"
value={ballotStore.endTime} value={ballotStore.endTime}
min={ballotStore.endTime} min={ballotStore.endTime}
onChange={e => ballotStore.changeBallotMetadata(e, "endTime")} onChange={e => ballotStore.changeBallotMetadata(e, "endTime")}

View File

@ -11,7 +11,12 @@ export class BallotMinThresholdCard extends React.Component {
@action("Get proposed value of min threshold ballot") @action("Get proposed value of min threshold ballot")
getProposedValue = async () => { getProposedValue = async () => {
const { contractsStore, id } = this.props; const { contractsStore, id } = this.props;
let proposedValue = await contractsStore.votingToChangeMinThreshold.getProposedValue(id); let proposedValue;
try {
proposedValue = await contractsStore.votingToChangeMinThreshold.getProposedValue(id);
} catch(e) {
console.log(e.message);
}
this.proposedValue = proposedValue; this.proposedValue = proposedValue;
} }

View File

@ -23,8 +23,8 @@ export class BallotMinThresholdMetadata extends React.Component {
</div> </div>
<div className="right"> <div className="right">
<div className="form-el"> <div className="form-el">
<label htmlFor="key">Ballot End</label> <label htmlFor="datetime-local">Ballot End</label>
<input type="datetime-local" id="key" <input type="datetime-local" id="datetime-local"
value={ballotStore.endTime} value={ballotStore.endTime}
onChange={e => ballotStore.changeBallotMetadata(e, "endTime")} onChange={e => ballotStore.changeBallotMetadata(e, "endTime")}
/> />

View File

@ -12,14 +12,24 @@ export class BallotProxyCard extends React.Component {
@action("Get proposed address of proxy ballot") @action("Get proposed address of proxy ballot")
getProposedAddress = async () => { getProposedAddress = async () => {
const { contractsStore, id } = this.props; const { contractsStore, id } = this.props;
let proposedAddress = await contractsStore.votingToChangeProxy.getProposedValue(id); let proposedAddress;
try {
proposedAddress = await contractsStore.votingToChangeProxy.getProposedValue(id);
} catch(e) {
console.log(e.message);
}
this.proposedAddress = proposedAddress; this.proposedAddress = proposedAddress;
} }
@action("Get contract type of proxy ballot") @action("Get contract type of proxy ballot")
getContractType = async () => { getContractType = async () => {
const { contractsStore, id } = this.props; const { contractsStore, id } = this.props;
let contractType = await contractsStore.votingToChangeProxy.getContractType(id); let contractType;
try {
contractType = await contractsStore.votingToChangeProxy.getContractType(id);
} catch(e) {
console.log(e.message);
}
this.contractType = contractType; this.contractType = contractType;
} }

View File

@ -45,8 +45,8 @@ export class BallotProxyMetadata extends React.Component {
</div> </div>
<div className="left"> <div className="left">
<div className="form-el"> <div className="form-el">
<label htmlFor="key">Ballot End</label> <label htmlFor="datetime-local">Ballot End</label>
<input type="datetime-local" id="key" <input type="datetime-local" id="datetime-local"
value={ballotStore.endTime} value={ballotStore.endTime}
onChange={e => ballotStore.changeBallotMetadata(e, "endTime")} onChange={e => ballotStore.changeBallotMetadata(e, "endTime")}
/> />

View File

@ -48,6 +48,11 @@ export class NewBallot extends React.Component {
if (ballotStore.isBallotForKey) { if (ballotStore.isBallotForKey) {
for (let ballotKeysProp in ballotStore.ballotKeys) { for (let ballotKeysProp in ballotStore.ballotKeys) {
if (!ballotStore.ballotKeys[ballotKeysProp]) {
swal("Warning!", `Ballot ${ballotKeysProp} is empty`, "warning");
commonStore.hideLoading();
return false;
}
if (ballotStore.ballotKeys[ballotKeysProp].length === 0) { if (ballotStore.ballotKeys[ballotKeysProp].length === 0) {
swal("Warning!", `Ballot ${ballotKeysProp} is empty`, "warning"); swal("Warning!", `Ballot ${ballotKeysProp} is empty`, "warning");
commonStore.hideLoading(); commonStore.hideLoading();
@ -99,6 +104,12 @@ export class NewBallot extends React.Component {
} }
} }
if (!ballotStore.isBallotForKey && !ballotStore.isBallotForMinThreshold && !ballotStore.isBallotForProxy) {
swal("Warning!", messages.BALLOT_TYPE_IS_EMPTY_MSG, "warning");
commonStore.hideLoading();
return false;
}
return true; return true;
} }
@ -107,8 +118,8 @@ export class NewBallot extends React.Component {
const inputToMethod = { const inputToMethod = {
startTime: curDateInSeconds, startTime: curDateInSeconds,
endTime: ballotStore.endTimeUnix, endTime: ballotStore.endTimeUnix,
affectedKey: ballotStore.ballotKeys.affectedKey, affectedKey: ballotStore.ballotKeys.affectedKey,
affectedKeyType: ballotStore.ballotKeys.keyType, affectedKeyType: ballotStore.ballotKeys.keyType,
miningKey: ballotStore.ballotKeys.miningKey.value, miningKey: ballotStore.ballotKeys.miningKey.value,
ballotType: ballotStore.ballotKeys.keysBallotType, ballotType: ballotStore.ballotKeys.keysBallotType,
sender: contractsStore.votingKey, sender: contractsStore.votingKey,
@ -123,7 +134,7 @@ export class NewBallot extends React.Component {
const inputToMethod = { const inputToMethod = {
startTime: curDateInSeconds, startTime: curDateInSeconds,
endTime: ballotStore.endTimeUnix, endTime: ballotStore.endTimeUnix,
proposedValue: ballotStore.ballotMinThreshold.proposedValue, proposedValue: ballotStore.ballotMinThreshold.proposedValue,
sender: contractsStore.votingKey, sender: contractsStore.votingKey,
memo: ballotStore.memo memo: ballotStore.memo
}; };
@ -136,7 +147,7 @@ export class NewBallot extends React.Component {
const inputToMethod = { const inputToMethod = {
startTime: curDateInSeconds, startTime: curDateInSeconds,
endTime: ballotStore.endTimeUnix, endTime: ballotStore.endTimeUnix,
proposedValue: ballotStore.ballotProxy.proposedAddress, proposedValue: ballotStore.ballotProxy.proposedAddress,
contractType: ballotStore.ballotProxy.contractType, contractType: ballotStore.ballotProxy.contractType,
sender: contractsStore.votingKey, sender: contractsStore.votingKey,
memo: ballotStore.memo memo: ballotStore.memo
@ -159,8 +170,8 @@ export class NewBallot extends React.Component {
if (isFormValid) { if (isFormValid) {
if (ballotStore.ballotType === ballotStore.BallotType.keys) { if (ballotStore.ballotType === ballotStore.BallotType.keys) {
const inputToAreBallotParamsValid = { const inputToAreBallotParamsValid = {
affectedKey: ballotStore.ballotKeys.affectedKey, affectedKey: ballotStore.ballotKeys.affectedKey,
affectedKeyType: ballotStore.ballotKeys.keyType, affectedKeyType: ballotStore.ballotKeys.keyType,
miningKey: ballotStore.ballotKeys.miningKey.value, miningKey: ballotStore.ballotKeys.miningKey.value,
ballotType: ballotStore.ballotKeys.keysBallotType ballotType: ballotStore.ballotKeys.keysBallotType
}; };
@ -173,19 +184,19 @@ export class NewBallot extends React.Component {
let methodToCreateBallot; let methodToCreateBallot;
switch (ballotStore.ballotType) { switch (ballotStore.ballotType) {
case ballotStore.BallotType.keys: case ballotStore.BallotType.keys:
methodToCreateBallot = this.createBallotForKeys; methodToCreateBallot = this.createBallotForKeys;
break; break;
case ballotStore.BallotType.minThreshold: case ballotStore.BallotType.minThreshold:
methodToCreateBallot = this.createBallotForMinThreshold; methodToCreateBallot = this.createBallotForMinThreshold;
break; break;
case ballotStore.BallotType.proxy: case ballotStore.BallotType.proxy:
methodToCreateBallot = this.createBallotForProxy; methodToCreateBallot = this.createBallotForProxy;
break; break;
default: default:
break; break;
} }
let curDateInSeconds = moment.utc().add(5, 'minute').unix(); let curDateInSeconds = moment.utc().add(5, 'minutes').unix();
methodToCreateBallot(curDateInSeconds) methodToCreateBallot(curDateInSeconds)
.on("receipt", (tx) => { .on("receipt", (tx) => {
commonStore.hideLoading(); commonStore.hideLoading();
@ -205,6 +216,15 @@ export class NewBallot extends React.Component {
} }
} }
menuItemActive = (ballotType) => {
const { ballotStore } = this.props;
if (ballotType == ballotStore.ballotType) {
return 'ballot-types-i ballot-types-i_active';
} else {
return 'ballot-types-i';
}
}
render() { render() {
const { contractsStore, ballotStore } = this.props; const { contractsStore, ballotStore } = this.props;
let validator = ballotStore.isNewValidatorPersonalData ? <Validator />: ""; let validator = ballotStore.isNewValidatorPersonalData ? <Validator />: "";
@ -212,15 +232,15 @@ export class NewBallot extends React.Component {
let metadata let metadata
let minThreshold = 0; let minThreshold = 0;
switch (ballotStore.ballotType) { switch (ballotStore.ballotType) {
case ballotStore.BallotType.keys: case ballotStore.BallotType.keys:
metadata = <BallotKeysMetadata />; metadata = <BallotKeysMetadata />;
minThreshold = contractsStore.keysBallotThreshold; minThreshold = contractsStore.keysBallotThreshold;
break; break;
case ballotStore.BallotType.minThreshold: case ballotStore.BallotType.minThreshold:
metadata = <BallotMinThresholdMetadata />; metadata = <BallotMinThresholdMetadata />;
minThreshold = contractsStore.minThresholdBallotThreshold; minThreshold = contractsStore.minThresholdBallotThreshold;
break; break;
case ballotStore.BallotType.proxy: case ballotStore.BallotType.proxy:
metadata = <BallotProxyMetadata />; metadata = <BallotProxyMetadata />;
minThreshold = contractsStore.proxyBallotThreshold; minThreshold = contractsStore.proxyBallotThreshold;
break; break;
@ -231,67 +251,99 @@ export class NewBallot extends React.Component {
<section className="container new"> <section className="container new">
<h1 className="title">New Ballot</h1> <h1 className="title">New Ballot</h1>
<form action="" className="new-form"> <form action="" className="new-form">
<div className="hidden"> <div className="new-form-side new-form-side_left">
<div className="left"> <div className="ballot-types">
<div className="radio-container"> <div
<input type="radio" name="ballot-type" id="ballot-for-validators" className={this.menuItemActive(ballotStore.BallotType.keys)}
value={ballotStore.BallotType.keys} onClick={(e) => ballotStore.changeBallotType(e, ballotStore.BallotType.keys)}
checked={ballotStore.isBallotForKey} >
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.keys)} Validator Management Ballot
/> </div>
<label htmlFor="ballot-for-validators" className="radio">Validator Management Ballot</label> <div
<p className="hint"> className={this.menuItemActive(ballotStore.BallotType.minThreshold)}
Ballot to add, remove or swap any type of key for existing or new validators. onClick={(e) => ballotStore.changeBallotType(e, ballotStore.BallotType.minThreshold)}
</p> >
Consenus Thershold Ballot
</div>
<div
className={this.menuItemActive(ballotStore.BallotType.proxy)}
onClick={(e) => ballotStore.changeBallotType(e, ballotStore.BallotType.proxy)}
>
Modify Proxy Contract Ballot
</div> </div>
</div> </div>
<div className="right">
<div className="radio-container">
<input type="radio" name="ballot-type" id="ballot-for-consensus"
value={ballotStore.BallotType.minThreshold}
checked={ballotStore.isBallotForMinThreshold}
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.minThreshold)}
/>
<label htmlFor="ballot-for-consensus" className="radio">Consenus Threshold Ballot</label>
<p className="hint">
Ballot to change the minimum threshold for consensus to vote for keys.
</p>
</div>
</div>
<div className="left">
<div className="radio-container">
<input type="radio" name="ballot-type" id="ballot-for-proxy"
value={ballotStore.BallotType.proxy}
checked={ballotStore.isBallotForProxy}
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.proxy)}
/>
<label htmlFor="ballot-for-proxy" className="radio">Modify Proxy Contract Ballot</label>
<p className="hint">
Ballot to change one of the proxy contracts.
</p>
</div>
</div>
</div>
<hr />
{validator}
{keysTypes}
{metadata}
<div className="form-el">
<label>Description of the ballot</label>
<div>
<textarea rows="4"
value={ballotStore.memo}
onChange={(e) => ballotStore.setMemo(e)}
></textarea>
</div>
</div>
<div className="new-form-footer">
<div className="info"> <div className="info">
Minimum {minThreshold} from {contractsStore.validatorsLength} validators required to pass the proposal<br /> <p className="info-title">Information of the ballot</p>
You can create {contractsStore.validatorLimits.keys} ballot for keys<br /> <div className="info-i">
You can create {contractsStore.validatorLimits.minThreshold} ballot for consensus<br /> Minimum {minThreshold} from {contractsStore.validatorsLength} validators required to pass the proposal<br />
You can create {contractsStore.validatorLimits.proxy} ballot for proxy<br /> </div>
<div className="info-i">
You can create {contractsStore.validatorLimits.keys} ballot for keys<br />
</div>
<div className="info-i">
You can create {contractsStore.validatorLimits.minThreshold} ballot for consensus<br />
</div>
<div className="info-i">
You can create {contractsStore.validatorLimits.proxy} ballot for proxy<br />
</div>
</div> </div>
</div>
<div className="new-form-side new-form-side_right">
<div className="form-el">
<label>Description of the ballot</label>
<div>
<textarea rows="4"
value={ballotStore.memo}
onChange={(e) => ballotStore.setMemo(e)}
></textarea>
</div>
</div>
<hr />
<div className="hidden">
<div className="left">
<div className="radio-container">
<input type="radio" name="ballot-type" id="ballot-for-validators"
value={ballotStore.BallotType.keys}
checked={ballotStore.isBallotForKey}
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.keys)}
/>
<label htmlFor="ballot-for-validators" className="radio">Validator Management Ballot</label>
<p className="hint">
Ballot to add, remove or swap any type of key for existing or new validators.
</p>
</div>
</div>
<div className="right">
<div className="radio-container">
<input type="radio" name="ballot-type" id="ballot-for-consensus"
value={ballotStore.BallotType.minThreshold}
checked={ballotStore.isBallotForMinThreshold}
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.minThreshold)}
/>
<label htmlFor="ballot-for-consensus" className="radio">Consenus Threshold Ballot</label>
<p className="hint">
Ballot to change the minimum threshold for consensus to vote for keys.
</p>
</div>
</div>
<div className="left">
<div className="radio-container">
<input type="radio" name="ballot-type" id="ballot-for-proxy"
value={ballotStore.BallotType.proxy}
checked={ballotStore.isBallotForProxy}
onChange={e => ballotStore.changeBallotType(e, ballotStore.BallotType.proxy)}
/>
<label htmlFor="ballot-for-proxy" className="radio">Modify Proxy Contract Ballot</label>
<p className="hint">
Ballot to change one of the proxy contracts.
</p>
</div>
</div>
</div>
<hr />
{validator}
{keysTypes}
{metadata}
<button type="button" className="add-ballot" onClick={e => this.onClick(e)}>Add ballot</button> <button type="button" className="add-ballot" onClick={e => this.onClick(e)}>Add ballot</button>
</div> </div>
</form> </form>

View File

@ -1,5 +1,5 @@
import Web3 from 'web3'; import Web3 from 'web3';
import networkAddresses from './addresses'; import { networkAddresses } from './addresses';
import helpers from "./helpers"; import helpers from "./helpers";
export default class BallotsStorage { export default class BallotsStorage {

View File

@ -1,5 +1,5 @@
import Web3 from 'web3'; import Web3 from 'web3';
import networkAddresses from './addresses'; import { networkAddresses } from './addresses';
import helpers from "./helpers"; import helpers from "./helpers";
export default class POAConsensus { export default class POAConsensus {

View File

@ -1,6 +1,6 @@
import Web3 from 'web3'; import Web3 from 'web3';
import moment from 'moment'; import moment from 'moment';
import networkAddresses from './addresses'; import { networkAddresses } from './addresses';
import helpers from "./helpers"; import helpers from "./helpers";
var toAscii = function(hex) { var toAscii = function(hex) {

View File

@ -1,5 +1,5 @@
import Web3 from 'web3'; import Web3 from 'web3';
import networkAddresses from './addresses'; import { networkAddresses } from './addresses';
import helpers from "./helpers"; import helpers from "./helpers";
export default class VotingToChangeKeys { export default class VotingToChangeKeys {

View File

@ -1,5 +1,5 @@
import Web3 from 'web3'; import Web3 from 'web3';
import networkAddresses from './addresses'; import { networkAddresses } from './addresses';
import helpers from "./helpers"; import helpers from "./helpers";
export default class VotingToChangeMinThreshold { export default class VotingToChangeMinThreshold {

View File

@ -1,5 +1,5 @@
import Web3 from 'web3'; import Web3 from 'web3';
import networkAddresses from './addresses'; import { networkAddresses } from './addresses';
import helpers from "./helpers"; import helpers from "./helpers";
export default class VotingToChangeProxy { export default class VotingToChangeProxy {

View File

@ -1,6 +1,4 @@
import { messages } from "../messages";
import { addressesURL, wrongRepoAlert } from "./helpers"; import { addressesURL, wrongRepoAlert } from "./helpers";
import swal from 'sweetalert2';
// const local = { // const local = {
// VOTING_TO_CHANGE_KEYS_ADDRESS: '0xecdbe3937cf6ff27f70480855cfe03254f915b48', // VOTING_TO_CHANGE_KEYS_ADDRESS: '0xecdbe3937cf6ff27f70480855cfe03254f915b48',
// VOTING_TO_CHANGE_MIN_THRESHOLD_ADDRESS: '0x5ae30d4c8892292e0d8164f87a2e12dff9dc99e1', // VOTING_TO_CHANGE_MIN_THRESHOLD_ADDRESS: '0x5ae30d4c8892292e0d8164f87a2e12dff9dc99e1',
@ -13,31 +11,31 @@ import swal from 'sweetalert2';
let SOKOL_ADDRESSES = {}; let SOKOL_ADDRESSES = {};
let CORE_ADDRESSES = {}; let CORE_ADDRESSES = {};
function getContractsAddresses(branch) { async function getContractsAddresses(branch) {
let addr = addressesURL(branch); let addr = addressesURL(branch);
fetch(addr).then(function(response) { let response;
return response.json(); try {
}).then(function(contracts) { response = await fetch(addr);
switch (branch) { } catch(e) {
case 'core': return wrongRepoAlert(addr);
CORE_ADDRESSES = contracts; }
break;
case 'sokol': let contracts = await response.json();
SOKOL_ADDRESSES = contracts;
break; switch (branch) {
default: case 'core':
CORE_ADDRESSES = contracts; CORE_ADDRESSES = contracts;
break; break;
} case 'sokol':
}).catch(function(err) { SOKOL_ADDRESSES = contracts;
wrongRepoAlert(addr); break;
}); default:
CORE_ADDRESSES = contracts;
break;
}
} }
getContractsAddresses('core'); function getAddresses(netId) {
getContractsAddresses('sokol');
module.exports = (netId) => {
switch (netId) { switch (netId) {
case '77': case '77':
return SOKOL_ADDRESSES return SOKOL_ADDRESSES
@ -48,4 +46,7 @@ module.exports = (netId) => {
} }
} }
module.exports = {
getContractsAddresses: getContractsAddresses,
networkAddresses: getAddresses
}

View File

@ -10,6 +10,7 @@ import validatorStore from './stores/ValidatorStore';
import ballotStore from './stores/BallotStore'; import ballotStore from './stores/BallotStore';
import ballotsStore from './stores/BallotsStore'; import ballotsStore from './stores/BallotsStore';
import contractsStore from './stores/ContractsStore'; import contractsStore from './stores/ContractsStore';
import { getContractsAddresses } from './contracts/addresses';
import swal from 'sweetalert2'; import swal from 'sweetalert2';
import getWeb3 from './getWeb3'; import getWeb3 from './getWeb3';
import "babel-polyfill"; import "babel-polyfill";
@ -32,6 +33,9 @@ class AppMainRouter extends Component {
commonStore.showLoading(); commonStore.showLoading();
getWeb3().then(async (web3Config) => { getWeb3().then(async (web3Config) => {
await getContractsAddresses('sokol');
await getContractsAddresses('core');
await contractsStore.setWeb3Instance(web3Config); await contractsStore.setWeb3Instance(web3Config);
await contractsStore.setPoaConsensus(web3Config); await contractsStore.setPoaConsensus(web3Config);
await contractsStore.setBallotsStorage(web3Config); await contractsStore.setBallotsStorage(web3Config);
@ -39,13 +43,15 @@ class AppMainRouter extends Component {
await contractsStore.setVotingToChangeMinThreshold(web3Config); await contractsStore.setVotingToChangeMinThreshold(web3Config);
await contractsStore.setVotingToChangeProxy(web3Config); await contractsStore.setVotingToChangeProxy(web3Config);
await contractsStore.setValidatorMetadata(web3Config); await contractsStore.setValidatorMetadata(web3Config);
await contractsStore.getAllKeysBallots();
await contractsStore.getAllMinThresholdBallots();
await contractsStore.getAllProxyBallots();
contractsStore.getValidatorsLength(); contractsStore.getValidatorsLength();
contractsStore.getKeysBallotThreshold(); contractsStore.getKeysBallotThreshold();
contractsStore.getMinThresholdBallotThreshold(); contractsStore.getMinThresholdBallotThreshold();
contractsStore.getProxyBallotThreshold(); contractsStore.getProxyBallotThreshold();
contractsStore.getAllKeysBallots();
contractsStore.getAllMinThresholdBallots();
contractsStore.getAllProxyBallots();
contractsStore.setVotingKey(web3Config); contractsStore.setVotingKey(web3Config);
await contractsStore.setMiningKey(web3Config); await contractsStore.setMiningKey(web3Config);
contractsStore.getValidatorActiveBallots(); contractsStore.getValidatorActiveBallots();
@ -78,4 +84,4 @@ class AppMainRouter extends Component {
} }
ReactDOM.render(<AppMainRouter />, document.getElementById('root')); ReactDOM.render(<AppMainRouter />, document.getElementById('root'));
registerServiceWorker(); registerServiceWorker();

View File

@ -12,6 +12,7 @@ messages.AFFECTED_KEY_IS_NOT_ADDRESS_MSG = "Ballot affectedKey isn't address";
messages.MINING_KEY_IS_NOT_ADDRESS_MSG = "Ballot miningKey isn't address"; messages.MINING_KEY_IS_NOT_ADDRESS_MSG = "Ballot miningKey isn't address";
messages.PROPOSED_ADDRESS_IS_NOT_ADDRESS_MSG = "Ballot proposedAddress isn't address"; messages.PROPOSED_ADDRESS_IS_NOT_ADDRESS_MSG = "Ballot proposedAddress isn't address";
messages.END_TIME_SHOULD_BE_GREATER_THAN_NOW_MSG = "Ballot end time should be greater than now"; messages.END_TIME_SHOULD_BE_GREATER_THAN_NOW_MSG = "Ballot end time should be greater than now";
messages.BALLOT_TYPE_IS_EMPTY_MSG = "Ballot type is empty";
messages.NO_METAMASK_MSG = `You haven't chosen any account in MetaMask. messages.NO_METAMASK_MSG = `You haven't chosen any account in MetaMask.
Please, choose your voting key in MetaMask and reload the page. Please, choose your voting key in MetaMask and reload the page.
Check POA Network <a href='https://github.com/poanetwork/wiki' target='blank'>wiki</a> for more info.`; Check POA Network <a href='https://github.com/poanetwork/wiki' target='blank'>wiki</a> for more info.`;