Cleanup controller, templates and service #41
@@ -2,9 +2,11 @@
|
||||
<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.recipientName}}</span>
|
||||
for <span class="recipient">{{proposal.contributor.name}}</span>
|
||||
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
|
||||
|
||||
{{#unless proposal.executed}}<button {{action "confirm" proposal.id}}>+1</button>{{/unless}}
|
||||
{{#unless proposal.isExecuted}}
|
||||
<button {{action "confirm" proposal.id}}>+1</button>
|
||||
{{/unless}}
|
||||
</li>
|
||||
{{/each}}
|
||||
|
||||
+59
-84
@@ -1,51 +1,10 @@
|
||||
import Ember from 'ember';
|
||||
import Proposal from 'kredits-web/models/proposal';
|
||||
import Controller from 'ember-controller';
|
||||
import computed, { alias, filter, filterBy, sort } from 'ember-computed';
|
||||
import injectService from 'ember-service/inject';
|
||||
|
||||
const {
|
||||
computed,
|
||||
inject: {
|
||||
service
|
||||
}
|
||||
} = Ember;
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
|
||||
kredits: service(),
|
||||
|
||||
contractInteractionEnabled: computed.alias('kredits.hasAccounts'),
|
||||
|
||||
proposalsOpen: function() {
|
||||
let proposals = this.get('model.proposals')
|
||||
.filterBy('executed', false)
|
||||
.map(p => {
|
||||
p.set('recipientName', this.get('model.contributors').findBy('id', p.get('recipientId')).name);
|
||||
return p;
|
||||
});
|
||||
return proposals;
|
||||
}.property('model.proposals.[]', 'model.proposals.@each.executed', 'model.contributors.[]'),
|
||||
|
||||
proposalsClosed: function() {
|
||||
let proposals = this.get('model.proposals')
|
||||
.filterBy('executed', true)
|
||||
.map(p => {
|
||||
p.set('recipientName', this.get('model.contributors').findBy('id', p.get('recipientId')).name);
|
||||
return p;
|
||||
});
|
||||
return proposals;
|
||||
}.property('model.proposals.[]', 'model.proposals.@each.executed', 'model.contributors.[]'),
|
||||
|
||||
proposalsSorting: ['id:desc'],
|
||||
proposalsClosedSorted: Ember.computed.sort('proposalsClosed', 'proposalsSorting'),
|
||||
proposalsOpenSorted: Ember.computed.sort('proposalsOpen', 'proposalsSorting'),
|
||||
|
||||
contributorsWithKredits: function() {
|
||||
return this.get('model.contributors').filter(c => {
|
||||
return c.get('balance') !== 0;
|
||||
});
|
||||
}.property('model.contributors.@each.balance'),
|
||||
|
||||
contributorsSorting: ['balance:desc'],
|
||||
contributorsSorted: Ember.computed.sort('contributorsWithKredits', 'contributorsSorting'),
|
||||
export default Controller.extend({
|
||||
kredits: injectService(),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
@@ -58,60 +17,76 @@ export default Ember.Controller.extend({
|
||||
});
|
||||
|
|
||||
},
|
||||
|
||||
_handleProposalCreated(proposalId, creatorAddress, recipientAddress, amount) {
|
||||
if (Ember.isPresent(this.get('model.proposals')
|
||||
.findBy('id', proposalId.toNumber()))) {
|
||||
contributors: alias('model.contributors'),
|
||||
contributorsWithKredits: filter('contributors', function(contributor) {
|
||||
return contributor.get('balance') !== 0;
|
||||
}),
|
||||
contributorsSorting: ['balance:desc'],
|
||||
contributorsSorted: sort('contributorsWithKredits', 'contributorsSorting'),
|
||||
|
||||
proposals: computed('model.proposals.[]', 'contributors.[]', function() {
|
||||
return this.get('model.proposals')
|
||||
.map((proposal) => {
|
||||
let contributor = this.get('contributors')
|
||||
.findBy('id', proposal.get('recipientId'));
|
||||
|
||||
proposal.set('contributor', contributor);
|
||||
|
||||
return proposal;
|
||||
});
|
||||
}),
|
||||
proposalsOpen: filterBy('proposals', 'isExecuted', false),
|
||||
proposalsClosed: filterBy('proposals', 'isExecuted', true),
|
||||
proposalsSorting: ['id:desc'],
|
||||
proposalsClosedSorted: sort('proposalsClosed', 'proposalsSorting'),
|
||||
proposalsOpenSorted: sort('proposalsOpen', 'proposalsSorting'),
|
||||
|
||||
_handleProposalCreated(proposalId) {
|
||||
// TODO: check if proposalId is already a string
|
||||
let proposal = this.get('proposals')
|
||||
.findBy('id', proposalId.toString());
|
||||
if (proposal) {
|
||||
Ember.Logger.debug('[index] proposal exists, not adding from event');
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
let proposal = Proposal.create({
|
||||
id: proposalId.toNumber(),
|
||||
creatorAddress: creatorAddress,
|
||||
recipientAddress: recipientAddress,
|
||||
recipientName: null,
|
||||
votesCount: 0,
|
||||
votesNeeded: 2,
|
||||
amount: amount.toNumber(),
|
||||
executed: false
|
||||
});
|
||||
|
||||
this.get('model.proposals').pushObject(proposal);
|
||||
proposal = this.get('kredits').getProposalById(proposalId);
|
||||
this.get('proposals').pushObject(proposal);
|
||||
},
|
||||
|
||||
_handleProposalExecuted(proposalId, recipientId, amount) {
|
||||
if (this.get('model.proposals')
|
||||
.findBy('id', recipientId.toNumber())
|
||||
.get('executed')) {
|
||||
// TODO: check if proposalId is already a string
|
||||
let proposal = this.get('proposals')
|
||||
.findBy('id', proposalId.toString());
|
||||
|
||||
if (proposal.get('isExecuted')) {
|
||||
Ember.Logger.debug('[index] proposal already executed, not adding from event');
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.get('model.proposals')
|
||||
.findBy('id', recipientId.toNumber())
|
||||
.setProperties({
|
||||
'executed': true,
|
||||
'votesCount': 2 // TODO use real count
|
||||
});
|
||||
proposal.setProperties({
|
||||
'executed': true,
|
||||
});
|
||||
|
||||
this.get('model.contributors')
|
||||
.findBy('id', recipientId)
|
||||
this.get('contributors')
|
||||
.findBy('id', recipientId.toString())
|
||||
.incrementProperty('balance', amount.toNumber());
|
||||
},
|
||||
|
||||
_handleProposalVoted(proposalId, voter, totalVotes) {
|
||||
this.get('model.proposals')
|
||||
.findBy('id', proposalId.toNumber())
|
||||
this.get('proposals')
|
||||
.findBy('id', proposalId.toString())
|
||||
.setProperties({ 'votesCount': totalVotes });
|
||||
},
|
||||
|
||||
_handleTransfer(data) {
|
||||
this.get('model.contributors')
|
||||
.findBy('address', data.args.from)
|
||||
.incrementProperty('balance', - data.args.value.toNumber());
|
||||
this.get('model.contributors')
|
||||
.findBy('address', data.args.to)
|
||||
.incrementProperty('balance', data.args.value.toNumber());
|
||||
_handleTransfer(from, to, value) {
|
||||
value = value.toNumber();
|
||||
this.get('contributors')
|
||||
.findBy('address', from)
|
||||
.decrementProperty('balance', value);
|
||||
this.get('contributors')
|
||||
.findBy('address', to)
|
||||
.incrementProperty('balance', value);
|
||||
},
|
||||
|
||||
|
||||
@@ -125,7 +100,7 @@ export default Ember.Controller.extend({
|
||||
save(contributor) {
|
||||
return this.get('kredits').addContributor(contributor)
|
||||
.then((contributor) => {
|
||||
this.get('model.contributors').pushObject(contributor);
|
||||
this.get('contributors').pushObject(contributor);
|
||||
return contributor;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import EmberObject from 'ember-object';
|
||||
import { alias } from 'ember-computed';
|
||||
|
||||
export default EmberObject.extend({
|
||||
// Contract
|
||||
@@ -11,6 +12,9 @@ export default EmberObject.extend({
|
||||
executed: null,
|
||||
ipfsHash: null,
|
||||
|
||||
// Shortcuts
|
||||
isExecuted: alias('executed'),
|
||||
|
||||
// IPFS
|
||||
kind: null,
|
||||
description: null,
|
||||
@@ -18,10 +22,6 @@ export default EmberObject.extend({
|
||||
url: null,
|
||||
ipfsData: '',
|
||||
|
||||
// Deprecated
|
||||
recipientAddress: null,
|
||||
recipientName: null,
|
||||
recipientProfile: null,
|
||||
|
||||
// TODO: add contributor relation
|
||||
// Relationships
|
||||
contributor: null,
|
||||
});
|
||||
|
||||
+20
-20
@@ -109,24 +109,22 @@ export default Service.extend({
|
||||
});
|
||||
},
|
||||
|
||||
// TODO: Should be part of the service
|
||||
buildContributor(attributes) {
|
||||
debug('[kredits] buildContributor', attributes);
|
||||
buildModel(name, attributes) {
|
||||
debug('[kredits] build', name, attributes);
|
||||
let model = getOwner(this).lookup(`model:${name}`);
|
||||
|
||||
let contributor = getOwner(this).lookup('model:contributor');
|
||||
contributor.setProperties(attributes);
|
||||
return contributor;
|
||||
},
|
||||
// coerce id to string
|
||||
if (attributes.id) {
|
||||
attributes.id = attributes.id.toString();
|
||||
}
|
||||
|
||||
buildProposal(attributes) {
|
||||
debug('[kredits] buildProposal', attributes);
|
||||
|
||||
let proposal = getOwner(this).lookup('model:proposal');
|
||||
proposal.setProperties(attributes);
|
||||
return proposal;
|
||||
model.setProperties(attributes);
|
||||
return model;
|
||||
},
|
||||
|
||||
getContributorById(id) {
|
||||
id = ethers.utils.bigNumberify(id);
|
||||
|
||||
return this.get('contributorsContract')
|
||||
.then((contract) => contract.getContributorById(id))
|
||||
.then(this.reassembleIpfsHash)
|
||||
@@ -135,7 +133,7 @@ export default Service.extend({
|
||||
let isCurrentUser = this.get('currentUserAccounts').includes(address);
|
||||
|
||||
return {
|
||||
id: id.toString(),
|
||||
id: id,
|
||||
address,
|
||||
balance: balance.toNumber(),
|
||||
ipfsHash,
|
||||
@@ -148,7 +146,7 @@ export default Service.extend({
|
||||
return this.fetchAndMergeIpfsData(data, ContributorSerializer);
|
||||
})
|
||||
.then((attributes) => {
|
||||
return this.buildContributor(attributes);
|
||||
return this.buildModel('contributor', attributes);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -203,6 +201,8 @@ export default Service.extend({
|
||||
},
|
||||
|
||||
getProposalById(id) {
|
||||
id = ethers.utils.bigNumberify(id);
|
||||
|
||||
return this.get('kreditsContract')
|
||||
.then((contract) => contract.proposals(id))
|
||||
.then(this.reassembleIpfsHash)
|
||||
@@ -217,9 +217,9 @@ export default Service.extend({
|
||||
ipfsHash,
|
||||
}) => {
|
||||
return {
|
||||
id: id.toString(),
|
||||
id: id,
|
||||
creatorAddress,
|
||||
recipientId: recipientId.toNumber(),
|
||||
recipientId: recipientId.toString(),
|
||||
votesCount: votesCount.toNumber(),
|
||||
votesNeeded: votesNeeded.toNumber(),
|
||||
amount: amount.toNumber(),
|
||||
@@ -232,7 +232,7 @@ export default Service.extend({
|
||||
return this.fetchAndMergeIpfsData(data, ContributionSerializer);
|
||||
})
|
||||
.then((attributes) => {
|
||||
return this.buildProposal(attributes);
|
||||
return this.buildModel('proposal', attributes);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -296,7 +296,7 @@ export default Service.extend({
|
||||
})
|
||||
.then((data) => {
|
||||
debug('[kredits] add contributor response', data);
|
||||
return this.buildContributor(attributes);
|
||||
return this.buildModel('contributor', attributes);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -333,7 +333,7 @@ export default Service.extend({
|
||||
})
|
||||
.then((data) => {
|
||||
debug('[kredits] add proposal response', data);
|
||||
return this.buildProposal(attributes);
|
||||
return this.buildModel('proposal', attributes);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
+10
-8
@@ -30,11 +30,13 @@
|
||||
<h2>Open Proposals</h2>
|
||||
</header>
|
||||
<div class="content">
|
||||
{{!-- TODO: We need a better naming for kredits.hasAccounts --}}
|
||||
{{proposal-list proposals=proposalsOpenSorted
|
||||
confirmAction="confirmProposal"
|
||||
contractInteractionEnabled=contractInteractionEnabled}}
|
||||
contractInteractionEnabled=kredits.hasAccounts}}
|
||||
|
||||
{{#if contractInteractionEnabled}}
|
||||
{{!-- TODO: We need a better naming --}}
|
||||
{{#if kredits.hasAccounts}}
|
||||
<p class="actions">
|
||||
{{#link-to 'proposals.new'}}Create new proposal{{/link-to}}
|
||||
</p>
|
||||
@@ -51,7 +53,8 @@
|
||||
{{proposal-list proposals=proposalsClosedSorted
|
||||
confirmAction="confirmProposal"}}
|
||||
|
||||
{{#if contractInteractionEnabled}}
|
||||
{{!-- TODO: We need a better naming --}}
|
||||
{{#if kredits.hasAccounts}}
|
||||
<p class="actions">
|
||||
{{#link-to 'proposals.new'}}Create new proposal{{/link-to}}
|
||||
</p>
|
||||
@@ -65,11 +68,10 @@
|
||||
</header>
|
||||
|
||||
<div class="content">
|
||||
{{!--
|
||||
TODO:
|
||||
only show the form if currentUser.isCore else show:
|
||||
{{#if currentUser.isCore}}
|
||||
{{add-contributor contributors=model.contributors save=(action 'save')}}
|
||||
{{else}}
|
||||
Only core team members can add new contributors. Please ask someone to set you up.
|
||||
--}}
|
||||
{{add-contributor contributors=model.contributors save=(action 'save')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -7,7 +7,6 @@ module('Serializers contribution');
|
||||
|
||||
test('#serialize returns a valid JSON-LD representation', function(assert) {
|
||||
let serialized = ContributionSerializer.serialize({
|
||||
recipientAddress: '0xd4a64570b12da659ee4bbd41c3509b7b1f9c51ac',
|
||||
kind: 'design',
|
||||
description: 'New logo design',
|
||||
url: 'http://opensourcedesign.org',
|
||||
|
||||
Reference in New Issue
Block a user
we should reuse the
getProposalByIdfunction here to load all the proposal data.adds another call but makes sure we have all the proposal data (and not only the data from the event)