Gracefully handle pending changes for contributions #159
@@ -45,7 +45,10 @@
|
|||||||
{{#unless contribution.vetoed}}
|
{{#unless contribution.vetoed}}
|
||||||
{{#unless (is-confirmed-contribution contribution)}}
|
{{#unless (is-confirmed-contribution contribution)}}
|
||||||
<p class="voting">
|
<p class="voting">
|
||||||
<button {{action "veto" contribution.id}} class="small danger">veto</button>
|
{{input type="button" class="button small danger"
|
||||||
|
click=(action "veto" contribution.id)
|
||||||
|
disabled=contribution.hasPendingChanges
|
||||||
|
value="veto"}}
|
||||||
</p>
|
</p>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default Component.extend({
|
|||||||
|
|
||||||
userHasEthereumWallet: computed(function() {
|
userHasEthereumWallet: computed(function() {
|
||||||
return isPresent(window.ethereum);
|
return isPresent(window.ethereum);
|
||||||
}).volatile(),
|
}),
|
||||||
|
|
||||||
showConnectButton: computed('userHasEthereumWallet',
|
showConnectButton: computed('userHasEthereumWallet',
|
||||||
'kredits.hasAccounts', function() {
|
'kredits.hasAccounts', function() {
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ export default Controller.extend({
|
|||||||
|
|
||||||
ipfsGatewayUrl: computed(function() {
|
ipfsGatewayUrl: computed(function() {
|
||||||
return config.ipfs.gatewayUrl;
|
return config.ipfs.gatewayUrl;
|
||||||
}).volatile()
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ export default Controller.extend({
|
|||||||
|
|
||||||
ipfsGatewayUrl: computed(function() {
|
ipfsGatewayUrl: computed(function() {
|
||||||
return config.ipfs.gatewayUrl;
|
return config.ipfs.gatewayUrl;
|
||||||
}).volatile()
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,13 +11,23 @@ export default Helper.extend({
|
|||||||
compute([contribution]) {
|
compute([contribution]) {
|
||||||
this.setupRecompute(contribution);
|
this.setupRecompute(contribution);
|
||||||
|
|
||||||
|
let status = [];
|
||||||
|
|
||||||
if (contribution.vetoed) {
|
if (contribution.vetoed) {
|
||||||
return 'vetoed';
|
status.push('vetoed');
|
||||||
} else if (contribution.confirmedAt > this.currentBlock) {
|
} else if (contribution.confirmedAt > this.currentBlock) {
|
||||||
return 'unconfirmed';
|
status.push('unconfirmed');
|
||||||
} else {
|
} else {
|
||||||
return 'confirmed'
|
status.push('confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contribution.hasPendingChanges) {
|
||||||
|
status.push('pending');
|
||||||
|
}
|
||||||
|
|
||||||
|
status.push('pending');
|
||||||
|
|
||||||
|
return status.join(' ');
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy () {
|
destroy () {
|
||||||
@@ -31,11 +41,13 @@ export default Helper.extend({
|
|||||||
contribution.addObserver('vetoed' , this, this.triggerRecompute);
|
contribution.addObserver('vetoed' , this, this.triggerRecompute);
|
||||||
contribution.addObserver('confirmedAt' , this, this.triggerRecompute);
|
contribution.addObserver('confirmedAt' , this, this.triggerRecompute);
|
||||||
contribution.addObserver('currentBlock' , this, this.triggerRecompute);
|
contribution.addObserver('currentBlock' , this, this.triggerRecompute);
|
||||||
|
contribution.addObserver('hasPendingChanges' , this, this.triggerRecompute);
|
||||||
|
|
||||||
this.teardown = () => {
|
this.teardown = () => {
|
||||||
contribution.removeObserver('vetoed', this, this.triggerRecompute);
|
contribution.removeObserver('vetoed', this, this.triggerRecompute);
|
||||||
contribution.removeObserver('confirmedAt', this, this.triggerRecompute);
|
contribution.removeObserver('confirmedAt', this, this.triggerRecompute);
|
||||||
contribution.removeObserver('currentBlock', this, this.triggerRecompute);
|
contribution.removeObserver('currentBlock', this, this.triggerRecompute);
|
||||||
|
contribution.removeObserver('hadPendingChanges', this, this.triggerRecompute);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import EmberObject, { computed } from '@ember/object';
|
import EmberObject, { computed } from '@ember/object';
|
||||||
import { isEmpty } from '@ember/utils';
|
import { isEmpty, isPresent } from '@ember/utils';
|
||||||
import bignumber from 'kredits-web/utils/cps/bignumber';
|
import bignumber from 'kredits-web/utils/cps/bignumber';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
@@ -24,6 +24,8 @@ export default EmberObject.extend({
|
|||||||
time: null,
|
time: null,
|
||||||
ipfsData: '',
|
ipfsData: '',
|
||||||
|
|
||||||
|
pendingTx: null,
|
||||||
|
|
||||||
init () {
|
init () {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
if (isEmpty(this.details)) this.set('details', {});
|
if (isEmpty(this.details)) this.set('details', {});
|
||||||
@@ -35,6 +37,10 @@ export default EmberObject.extend({
|
|||||||
|
|
||||||
jsDate: computed('iso8601Date', function() {
|
jsDate: computed('iso8601Date', function() {
|
||||||
return moment(this.iso8601Date).toDate();
|
return moment(this.iso8601Date).toDate();
|
||||||
|
}),
|
||||||
|
|
||||||
|
hasPendingChanges: computed('pendingTx', function() {
|
||||||
|
return isPresent(this.pendingTx);
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -210,8 +210,8 @@ export default Service.extend({
|
|||||||
|
|
||||||
getContributors () {
|
getContributors () {
|
||||||
return this.kredits.Contributor.all()
|
return this.kredits.Contributor.all()
|
||||||
.then((contributors) => {
|
.then(contributors => {
|
||||||
return contributors.map((contributor) => {
|
return contributors.map(contributor => {
|
||||||
return Contributor.create(contributor);
|
return Contributor.create(contributor);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -225,6 +225,7 @@ export default Service.extend({
|
|||||||
console.debug('[kredits] add contribution response', data);
|
console.debug('[kredits] add contribution response', data);
|
||||||
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
|
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
|
||||||
const contribution = Contribution.create(attributes);
|
const contribution = Contribution.create(attributes);
|
||||||
|
contribution.set('pendingTx', data);
|
||||||
contribution.set('confirmedAtBlock', data.blockNumber + 40320);
|
contribution.set('confirmedAtBlock', data.blockNumber + 40320);
|
||||||
this.contributions.pushObject(contribution);
|
this.contributions.pushObject(contribution);
|
||||||
return contribution;
|
return contribution;
|
||||||
@@ -278,10 +279,12 @@ export default Service.extend({
|
|||||||
|
|
||||||
veto (contributionId) {
|
veto (contributionId) {
|
||||||
console.debug('[kredits] veto against', contributionId);
|
console.debug('[kredits] veto against', contributionId);
|
||||||
|
const contribution = this.contributions.findBy('id', contributionId);
|
||||||
|
|
||||||
return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
|
return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.debug('[kredits] veto response', data);
|
console.debug('[kredits] veto response', data);
|
||||||
|
contribution.set('pendingTx', data);
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -367,6 +370,7 @@ export default Service.extend({
|
|||||||
|
|
||||||
if (contribution) {
|
if (contribution) {
|
||||||
contribution.set('vetoed', true);
|
contribution.set('vetoed', true);
|
||||||
|
contribution.set('pendingTx', null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ button, input[type=submit], .button {
|
|||||||
padding: 0.2rem 0.8rem;
|
padding: 0.2rem 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.danger {
|
&.danger:not(:disabled) {
|
||||||
color: $red;
|
color: $red;
|
||||||
background-color: rgba(40, 21, 21, 0.6);
|
background-color: rgba(40, 21, 21, 0.6);
|
||||||
border-color: rgba(40, 21, 21, 1);
|
border-color: rgba(40, 21, 21, 1);
|
||||||
@@ -45,7 +45,7 @@ button, input[type=submit], .button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.green {
|
&.green:not(:disabled) {
|
||||||
color: $green;
|
color: $green;
|
||||||
background-color: rgba(21, 40, 21, 0.6);
|
background-color: rgba(21, 40, 21, 0.6);
|
||||||
border-color: rgba(21, 40, 21, 1);
|
border-color: rgba(21, 40, 21, 1);
|
||||||
|
|||||||
@@ -24,4 +24,13 @@ module('Unit | Model | contribution', function(hooks) {
|
|||||||
assert.ok(model.jsDate instanceof Date);
|
assert.ok(model.jsDate instanceof Date);
|
||||||
assert.equal(model.jsDate.toISOString(), '2019-09-10T09:33:00.141Z');
|
assert.equal(model.jsDate.toISOString(), '2019-09-10T09:33:00.141Z');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('hasPendingChanges', function(assert) {
|
||||||
|
const model = Contribution.create({});
|
||||||
|
assert.equal(model.hasPendingChanges, false);
|
||||||
|
|
||||||
|
model.set('pendingTx', { hash: 'abcdef123456' });
|
||||||
|
assert.equal(model.hasPendingChanges, true);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user