Feature: Batch voting #62

Closed
fsmanuel wants to merge 3 commits from feature/batch-voting into master
8 changed files with 103 additions and 33 deletions
+17 -7
View File
@@ -1,20 +1,30 @@
import Component from '@ember/component';
import { inject } from '@ember/service';
import { empty } from '@ember/object/computed';
export default Component.extend({
kredits: inject(),
tagName: 'ul',
classNames: ['proposal-list'],
selectedProposals: [],
submitButtonDisabled: empty('selectedProposals'),
actions: {
confirm() {
this.confirmProposals(this.selectedProposals)
.then(() => {
this.selectedProposals = [];
});
},
confirm(proposalId) {
if (this.contractInteractionEnabled) {
this.confirmProposal(proposalId);
toggleSelect(proposalId, selected) {
if (selected) {
this.selectedProposals.removeObject(proposalId);
} else {
window.alert('Only members can vote on proposals. Please ask someone to set you up.');
this.selectedProposals.addObject(proposalId);
}
}
},
}
});
@@ -0,0 +1,29 @@
import Component from '@ember/component';
import tag from 'ember-awesome-macros/tag';
import { computed } from '@ember/object';
import { reads } from '@ember/object/computed';
import { inject } from '@ember/service';
export default Component.extend({
kredits: inject(),
tagName: 'li',
classNames: ['proposal-list-item'],
attributeBindings: ['data-proposal-id', 'title'],
title: tag`(${'proposal.kind'}) ${'proposal.description'}`,
'data-proposal-id': reads('proposal.id'),
canBeVoted: computed('voterIds.[]', 'kredits.currentUser', function() {
let { isExecuted, voterIds } = this.proposal;
let { currentUser } = this.kredits;
voterIds = voterIds.map((id) => id.toString());
return currentUser.isCore && !isExecuted && !voterIds.includes(currentUser.id);
}),
selected: computed('selectedProposals.[]', function() {
return this.selectedProposals.includes(this.proposal.id);
})
});
@@ -0,0 +1,8 @@
<span class="category {{proposal.kind}}">♥</span>
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
for <span class="recipient">{{proposal.contributor.name}}</span>
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
{{#if canBeVoted}}
<button {{action toggleSelect proposal.id selected}} class="{{if selected 'selected' ''}}">+1</button>
{{/if}}
+13 -10
View File
@@ -1,12 +1,15 @@
{{#each proposals as |proposal|}}
<li data-proposal-id={{proposal.id}} title="({{proposal.kind}}) {{proposal.description}}">
<span class="category {{proposal.kind}}">♥</span>
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
for <span class="recipient">{{proposal.contributor.name}}</span>
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
{{#unless proposal.isExecuted}}
<button {{action "confirm" proposal.id}}>+1</button>
{{/unless}}
</li>
{{proposal-list/item
proposal=proposal
selectedProposals=selectedProposals
toggleSelect=(action 'toggleSelect')
}}
{{/each}}
{{#if confirmProposals}}
<center>
<button disabled={{submitButtonDisabled}} {{action 'confirm'}}>
Submit selected
</button>
</center>
{{/if}}
+12 -4
View File
@@ -1,6 +1,7 @@
import Controller from '@ember/controller';
import { alias, filter, filterBy, sort } from '@ember/object/computed';
import { inject as injectService } from '@ember/service';
import RSVP from 'rsvp';
export default Controller.extend({
kredits: injectService(),
@@ -20,10 +21,17 @@ export default Controller.extend({
proposalsOpenSorted: sort('proposalsOpen', 'proposalsSorting'),
actions: {
confirmProposal(proposalId) {
this.kredits.vote(proposalId).then(transaction => {
window.confirm('Vote submitted to Ethereum blockhain: '+transaction.hash);
});
confirmProposals(proposalIds) {
if (this.kredits.currentUser.isCore) {
return this.kredits.batchVote(proposalIds)
.then((transaction) => {
window.confirm('Vote submitted to Ethereum blockhain: '+transaction.hash);
return transaction;
});
} else {
window.alert('Only members can vote on proposals. Please ask someone to set you up.');
return RSVP.reject();
}
},
save(contributor) {
+6 -7
View File
@@ -4,7 +4,7 @@ import RSVP from 'rsvp';
import Service from '@ember/service';
import { computed } from '@ember/object';
import { alias, notEmpty } from '@ember/object/computed';
import { notEmpty } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';
import config from 'kredits-web/config/environment';
@@ -16,8 +16,6 @@ export default Service.extend({
currentUserAccounts: null, // default to not having an account. this is the wen web3 is loaded.
currentUser: null,
currentUserIsContributor: notEmpty('currentUser'),
currentUserIsCore: alias('currentUser.isCore'),
hasAccounts: notEmpty('currentUserAccounts'),
accountNeedsUnlock: computed('currentUserAccounts', function() {
return this.currentUserAccounts && isEmpty(this.currentUserAccounts);
@@ -68,7 +66,7 @@ export default Service.extend({
if (this.currentUserAccounts && this.currentUserAccounts.length > 0) {
this.getCurrentUser.then((contributorData) => {
this.set('currentUser', contributorData);
this.set('currentUser', Contributor.create(contributorData));
});
}
return kredits;
@@ -130,10 +128,11 @@ export default Service.extend({
});
},
vote(proposalId) {
console.debug('[kredits] vote for', proposalId);
batchVote(proposalIds) {
proposalIds = proposalIds.map((id) => parseInt(id))
console.debug('[kredits] vote for', proposalIds);
return this.kredits.Operator.functions.vote(proposalId)
return this.kredits.Operator.functions.batchVote(proposalIds)
.then((data) => {
console.debug('[kredits] vote response', data);
return data;
+15
View File
@@ -46,7 +46,22 @@ ul.proposal-list {
height: 2rem;
line-height: 2rem;
padding: 0 0.6rem;
&.selected {
background-color: rgba(224,104,251, 0.6);
}
}
}
button {
margin-top: 1.1rem;
height: 2rem;
line-height: 2rem;
padding: 0 0.6rem;
&:disabled {
cursor: not-allowed;
color: rgba(204,204,204, 0.6);
}
}
}
+3 -5
View File
@@ -2,7 +2,7 @@
<section id="user-account">
{{#if kredits.currentUser }}
{{ kredits.currentUser.name }}
{{#if kredits.currentUserIsCore }}
{{#if kredits.currentUser.isCore }}
(core)
{{/if}}
Account: {{kredits.currentUser.account}}
@@ -32,8 +32,7 @@
<div class="content">
{{!-- TODO: We need a better naming for kredits.hasAccounts --}}
{{proposal-list proposals=proposalsOpenSorted
confirmProposal=(action "confirmProposal")
contractInteractionEnabled=kredits.hasAccounts}}
confirmProposals=(action 'confirmProposals')}}
{{!-- TODO: We need a better naming --}}
{{#if kredits.hasAccounts}}
1
@@ -50,8 +49,7 @@
<h2>Closed Proposals</h2>
</header>
<div class="content">
{{proposal-list proposals=proposalsClosedSorted
confirmProposal=(action "confirmProposal")}}
{{proposal-list proposals=proposalsClosedSorted}}
{{!-- TODO: We need a better naming --}}
{{#if kredits.hasAccounts}}