Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement voting summary page - Closes #1972 #2048

Merged
merged 28 commits into from May 23, 2019
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
61294ad
:seedling: Create empty 'Voting summary' page
slaweet May 21, 2019
f1ff286
:seedling: Create generic transactionSummary component
slaweet May 21, 2019
4c14ce6
:seedling: Implement basic structure of votingSummary
slaweet May 21, 2019
214181a
:seedling: Implement "Go to Confirmation" in voting
slaweet May 21, 2019
8c279dd
:seedling: Implement layout of transactionSummary
slaweet May 21, 2019
2c900a3
:seedling: Implement vote lists in votingSummary
slaweet May 21, 2019
90fffe0
:seedling: Implement transaction fee tooltip in voting
slaweet May 21, 2019
831abf9
:seedling: Implement voteUrlProcessorV2
slaweet May 22, 2019
21d56bc
:seedling: Implement total fee in votingSummary
slaweet May 22, 2019
fbd3b03
:seedling: Add second passphrase to transactionSummary
slaweet May 22, 2019
0968e65
:bug: Fix "Edit voting" to preserve the votes
slaweet May 22, 2019
41c3a4f
:seedling: Implement guest mode for delegatesV2
slaweet May 22, 2019
f6cb0c7
:white_check_mark: Create unit tests for signInTooltipWrapper
slaweet May 22, 2019
9434fcb
:recycle: Rename votingV2 to delegatesV2
slaweet May 22, 2019
f55d8d2
:recycle: Rename votingSummary to votingV2
slaweet May 22, 2019
d660de9
:seedling: Create voting result step
slaweet May 22, 2019
3a09702
:seedling: Implement vote submission in votingSummaryV2
slaweet May 22, 2019
462f494
:seedling: Implement submitting votes with 2nd passphrase
slaweet May 22, 2019
bad2afc
:seedling: Implement illustration toolbox component
slaweet May 22, 2019
0100a5b
:seedling: Implement voting with hw wallet in new design
slaweet May 22, 2019
fa32cd0
:white_check_mark: Fix test coverage of illustration component
slaweet May 22, 2019
669a403
:white_check_mark: Create unit tests for transactionSummary
slaweet May 22, 2019
5fdda08
:white_check_mark: Create unit tests for votingV2
slaweet May 22, 2019
a0ac9ca
:white_check_mark: Create unit tests for voteUrlProcessorV2
slaweet May 22, 2019
fc11381
:nail_care: Remove extra empty lines to pass eslint
slaweet May 22, 2019
1efc49d
:white_check_mark: Fix test of delegatesV2
slaweet May 22, 2019
dacc38f
Merge branch 'development' into 1972-implement-voting-summary-page
slaweet May 23, 2019
31f08b3
:bug: Fix layout for too long content in voting
slaweet May 23, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions i18n/locales/en/common.json
Expand Up @@ -72,6 +72,7 @@
"Cancel": "Cancel",
"Cancel voting": "Cancel voting",
"Check for updates...": "Check for updates...",
"Check spelling – delegate name does not exist": "Check spelling – delegate name does not exist",
"Check spelling – name does not exist on mainnet": "Check spelling – name does not exist on mainnet",
"Choose": "Choose",
"Choose a name": "Choose a name",
Expand All @@ -88,8 +89,10 @@
"Confirm (Fee: {{fee}} LSK)": "Confirm (Fee: {{fee}} LSK)",
"Confirm on {{deviceModel}}": "Confirm on {{deviceModel}}",
"Confirm to register your second passphrase on the blockchain.": "Confirm to register your second passphrase on the blockchain.",
"Confirm transaction on your {{deviceModel}}": "Confirm transaction on your {{deviceModel}}",
"Confirm transaction on {{deviceModel}}": "Confirm transaction on {{deviceModel}}",
"Confirm vote on {{deviceModel}}": "Confirm vote on {{deviceModel}}",
"Confirm voting": "Confirm voting",
"Confirm your name": "Confirm your name",
"Confirm your passphrase": "Confirm your passphrase",
"Confirmation in the next step": "Confirmation in the next step",
Expand Down Expand Up @@ -153,6 +156,7 @@
"Each time you add or remove a vote it is counted as an action. There's {{fee}} LSK fee per every 33 actions.": "Each time you add or remove a vote it is counted as an action. There's {{fee}} LSK fee per every 33 actions.",
"Edit": "Edit",
"Edit transaction": "Edit transaction",
"Edit voting": "Edit voting",
"Enter URL of the *.js file with the extension": "Enter URL of the *.js file with the extension",
"Enter your 1st passphrase to confirm": "Enter your 1st passphrase to confirm",
"Enter your passphrase": "Enter your passphrase",
Expand All @@ -165,6 +169,7 @@
"Error retrieving convertion rates.": "Error retrieving convertion rates.",
"Error retrieving dynamic fees.": "Error retrieving dynamic fees.",
"Every transaction needs to be confirmed and forged into Lisks blockchain network. \n Such operations require hardware resources and because of that there is a small fee for processing those.": "Every transaction needs to be confirmed and forged into Lisks blockchain network. \n Such operations require hardware resources and because of that there is a small fee for processing those.",
"Every transaction needs to be confirmed and forged into Lisks blockchain network. \n Such operations require hardware resources and because of that there is a small fee for processing those.": "Every transaction needs to be confirmed and forged into Lisks blockchain network. \n Such operations require hardware resources and because of that there is a small fee for processing those.",
"Explain Blockchain Like I'm 5": "Explain Blockchain Like I'm 5",
"Explore as a Guest": "Explore as a Guest",
"Failed to connect to node": "Failed to connect to node",
Expand Down Expand Up @@ -213,6 +218,7 @@
"ID already added to bookmarks": "ID already added to bookmarks",
"If you’re not sure how to do this please follow the": "If you’re not sure how to do this please follow the",
"In": "In",
"In order to use this Lisk Hub feature you need to sign in to your Lisk account.": "In order to use this Lisk Hub feature you need to sign in to your Lisk account.",
"Include your operating system and screen resolution in your report": "Include your operating system and screen resolution in your report",
"Incoming": "Incoming",
"Incoming transactions": "Incoming transactions",
Expand Down Expand Up @@ -333,12 +339,14 @@
"Paste": "Paste",
"Pending...": "Pending...",
"Perfect! You’re all set.": "Perfect! You’re all set.",
"Please check if all the transaction details are correct.": "Please check if all the transaction details are correct.",
"Please check the address": "Please check the address",
"Please check the highlighted words": "Please check the highlighted words",
"Please click Next, then move around your mouse randomly to generate a random passphrase.": "Please click Next, then move around your mouse randomly to generate a random passphrase.",
"Please go back and check your passphrase again.": "Please go back and check your passphrase again.",
"Please keep it safe!": "Please keep it safe!",
"Please select the account you’d like to sign in to or": "Please select the account you’d like to sign in to or",
"Please sign in": "Please sign in",
"Please sign in with your passphrase": "Please sign in with your passphrase",
"Please sign in with your second passphrase": "Please sign in with your second passphrase",
"Please use only digits and dots": "Please use only digits and dots",
Expand All @@ -348,6 +356,7 @@
"Print more than one copy and store them in two separate secure places.": "Print more than one copy and store them in two separate secure places.",
"Privacy Policy": "Privacy Policy",
"Processing Speed": "Processing Speed",
"Processing...": "Processing...",
"Productivity": "Productivity",
"Provide a correct amount of {{token}}": "Provide a correct amount of {{token}}",
"Provide a correct wallet address or a name of a bookmarked account": "Provide a correct wallet address or a name of a bookmarked account",
Expand Down Expand Up @@ -520,8 +529,10 @@
"Voted delegates": "Voted delegates",
"Voter": "Voter",
"Votes": "Votes",
"Votes after confirmation": "Votes after confirmation",
"Votes submitted": "Votes submitted",
"Voting": "Voting",
"Voting summary": "Voting summary",
"Wallet": "Wallet",
"We recommend including date & time or a specific keyword.": "We recommend including date & time or a specific keyword.",
"Welcome back": "Welcome back",
Expand Down
2 changes: 0 additions & 2 deletions jest.config.js
Expand Up @@ -20,7 +20,6 @@ module.exports = {
'src/store/middlewares/socket.test.js',
'src/store/middlewares/peers.test.js',
'src/components/votingListViewV2/*',
'src/components/votingV2/*',
'src/components/registerV2/registerV2.test.js',
'src/components/headerV2/headerV2.test.js',
],
Expand Down Expand Up @@ -132,7 +131,6 @@ module.exports = {
'src/components/loginV2/loginV2.js',
'src/utils/hwWallet.js',
'src/components/votingListViewV2/*',
'src/components/votingV2/*',
'src/components/headerV2/headerV2.js',
'src/components/registerV2/registerV2.js',
],
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions src/components/delegatesV2/delegatesV2.js
@@ -0,0 +1,46 @@
import React from 'react';
import grid from 'flexboxgrid/dist/flexboxgrid.css';
import styles from './votingV2.css';
import VotingListViewV2 from '../votingListViewV2';
import VotingHeader from './votingHeader';
import { getTotalActions } from './../../utils/voting';

class DelegatesV2 extends React.Component {
constructor({ votes }) {
super();

this.state = {
votingModeEnabled: getTotalActions(votes) > 0,
};

this.toggleVotingMode = this.toggleVotingMode.bind(this);
}

toggleVotingMode() {
if (this.state.votingModeEnabled) {
this.props.clearVotes();
}
this.setState({ votingModeEnabled: !this.state.votingModeEnabled });
}

render() {
const { t, votes } = this.props;
const { votingModeEnabled } = this.state;
return (
<div className={`${grid.row} ${styles.wrapper}`} ref={(el) => { this.root = el; }}>
<VotingHeader
t={t}
votingModeEnabled={votingModeEnabled}
toggleVotingMode={this.toggleVotingMode}
votes={votes}/>
<section className={`${grid['col-sm-12']} ${grid['col-md-12']} ${styles.votingBox} ${styles.votes}`}>
<VotingListViewV2
votingModeEnabled={votingModeEnabled}
/>
</section>
</div>
);
}
}

export default DelegatesV2;
69 changes: 69 additions & 0 deletions src/components/delegatesV2/delegatesV2.test.js
@@ -0,0 +1,69 @@
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import PropTypes from 'prop-types';
import thunk from 'redux-thunk';
import { BrowserRouter as Router } from 'react-router-dom';
import { prepareStore } from '../../../test/unit-test-utils/applicationInit';
import peersReducer from '../../store/reducers/peers';
import accountReducer from '../../store/reducers/account';
import votingReducer from '../../store/reducers/voting';
import DelegatesV2 from './delegatesV2';
import history from '../../history';
import i18n from '../../i18n';

describe('DelegatesV2', () => {
let wrapper;
const votes = {
username1: { confirmed: true, unconfirmed: true, publicKey: 'sample_key' },
};
const store = prepareStore({
peers: peersReducer,
account: accountReducer,
voting: votingReducer,
}, [thunk]);

const delegates = [
{
address: 'address 1',
username: 'username1',
publicKey: 'sample_key',
serverPublicKey: 'sample_key',
rank: 12,
},
{
address: 'address 2',
username: 'username2',
publicKey: 'sample_key',
serverPublicKey: 'sample_key',
rank: 23,
},
];
const props = {
refreshDelegates: false,
delegates,
totalDelegates: 10,
votes,
t: key => key,
history: { location: { search: '' } },
clearVotes: jest.fn(),
};
const options = {
context: { store, history, i18n },
childContextTypes: {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
i18n: PropTypes.object.isRequired,
},
};

it('should allow to enable and disable voting mode', () => {
wrapper = mount(<Router><DelegatesV2 {...props} /></Router>, options);
wrapper.find('.start-voting-button').at(0).simulate('click');
expect(wrapper.find('.addedVotes')).to.have.lengthOf(1);

wrapper.find('.cancel-voting-button').at(0).simulate('click');
expect(wrapper.find('.addedVotes')).to.have.lengthOf(0);
});
});

15 changes: 15 additions & 0 deletions src/components/delegatesV2/index.js
@@ -0,0 +1,15 @@
/* istanbul ignore file */
import { connect } from 'react-redux';
import { translate } from 'react-i18next';
import DelegatesV2 from './delegatesV2';
import { clearVotes } from '../../actions/voting';

const mapStateToProps = state => ({
votes: state.voting.votes,
});

const mapDispatchToProps = {
clearVotes,
};

export default connect(mapStateToProps, mapDispatchToProps)(translate()(DelegatesV2));
Expand Up @@ -6,6 +6,10 @@
justify-content: space-between;
width: 100%;
margin-bottom: 25px;

& > * {
display: flex;
}
}

.box,
Expand Down
Expand Up @@ -2,12 +2,14 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { SecondaryButtonV2, PrimaryButtonV2 } from '../toolbox/buttons/button';
import Tooltip from '../toolbox/tooltip/tooltip';
import SignInTooltipWrapper from '../signInTooltipWrapper';
import routes from './../../constants/routes';
import votingConst from '../../constants/voting';
import {
getTotalVotesCount,
getVoteList,
getUnvoteList,
getTotalActions,
} from './../../utils/voting';

import styles from './votingHeader.css';
Expand All @@ -22,14 +24,11 @@ class VotingHeader extends React.Component {
} = this.props;
const voteList = getVoteList(votes);
const unvoteList = getUnvoteList(votes);
const totalActions = getTotalActions(votes);
const {
maxCountOfVotesInOneTurn,
maxCountOfVotes,
fee,
} = votingConst;
const totalActions = Math.ceil((
voteList.length + unvoteList.length
) / maxCountOfVotesInOneTurn);
return (
<div className={`${styles.wrapper}`}>
<span>
Expand Down Expand Up @@ -64,22 +63,28 @@ class VotingHeader extends React.Component {
</span>
{ votingModeEnabled ?
<span>
<SecondaryButtonV2 onClick={toggleVotingMode} className={styles.btn}>
<SecondaryButtonV2 onClick={toggleVotingMode} className={`cancel-voting-button ${styles.btn}`}>
{t('Cancel voting')}
</SecondaryButtonV2>
<PrimaryButtonV2 className={styles.btn} disabled={totalActions === 0}>
{t('Go to Confirmation')}
</PrimaryButtonV2>
<Link to={routes.voting.path} >
<PrimaryButtonV2 className={styles.btn} disabled={totalActions === 0}>
{t('Go to Confirmation')}
</PrimaryButtonV2>
</Link>
</span> :
<span>
<Link to={routes.registerDelegate.path} >
<SecondaryButtonV2 className={`register-delegate ${styles.btn}`}>
{t('Register as a Delegate')}
</SecondaryButtonV2>
</Link>
<PrimaryButtonV2 onClick={toggleVotingMode} className={styles.btn}>
{t('Start voting')}
</PrimaryButtonV2>
<SignInTooltipWrapper>
<Link to={routes.registerDelegate.path} >
<SecondaryButtonV2 className={`register-delegate ${styles.btn}`}>
{t('Register as a Delegate')}
</SecondaryButtonV2>
</Link>
</SignInTooltipWrapper>
<SignInTooltipWrapper>
<PrimaryButtonV2 onClick={toggleVotingMode} className={`start-voting-button ${styles.btn}`}>
{t('Start voting')}
</PrimaryButtonV2>
</SignInTooltipWrapper>
</span>
}
</div>
Expand Down