diff --git a/app/components/add-contribution/component.js b/app/components/add-contribution/component.js index 0c25c85..b9533f8 100644 --- a/app/components/add-contribution/component.js +++ b/app/components/add-contribution/component.js @@ -1,6 +1,7 @@ import Component from '@ember/component'; import { computed } from '@ember/object'; import { and, notEmpty } from '@ember/object/computed'; +import { isEmpty } from '@ember/utils'; import moment from 'moment'; export default Component.extend({ @@ -25,14 +26,17 @@ export default Component.extend({ this.set('defaultDate', moment().startOf('hour').toDate()); // Default attributes used by reset - this.set('attributes', { - contributorId: null, - kind: null, - date: this.defaultDate, - amount: null, - description: null, - url: null, - }); + if (isEmpty(this.attributes)) { + this.set('attributes', { + contributorId: null, + kind: null, + date: this.defaultDate, + amount: null, + description: null, + url: null, + details: null + }); + } this.reset(); }, @@ -67,7 +71,6 @@ export default Component.extend({ window.alert('Something went wrong. Check the browser console for details.'); }) .finally(() => this.set('inProgress', false)); - } } diff --git a/app/components/add-contribution/template.hbs b/app/components/add-contribution/template.hbs index 2d2751f..2174967 100644 --- a/app/components/add-contribution/template.hbs +++ b/app/components/add-contribution/template.hbs @@ -63,6 +63,17 @@
+ {{#if details}} + + {{/if}} +
{{input type="submit"
disabled=inProgress
diff --git a/app/components/icon-warning/component.js b/app/components/icon-warning/component.js
new file mode 100644
index 0000000..6858137
--- /dev/null
+++ b/app/components/icon-warning/component.js
@@ -0,0 +1,5 @@
+import Component from '@ember/component';
+
+export default Component.extend({
+ tagName: ""
+});
diff --git a/app/components/icon-warning/template.hbs b/app/components/icon-warning/template.hbs
new file mode 100644
index 0000000..d4d53d6
--- /dev/null
+++ b/app/components/icon-warning/template.hbs
@@ -0,0 +1,15 @@
+
diff --git a/app/controllers/contributions/resubmit.js b/app/controllers/contributions/resubmit.js
new file mode 100644
index 0000000..ed37ace
--- /dev/null
+++ b/app/controllers/contributions/resubmit.js
@@ -0,0 +1,7 @@
+import ContributionsNewController from 'kredits-web/controllers/contributions/new';
+
+export default ContributionsNewController.extend({
+
+ attributes: null,
+
+});
diff --git a/app/controllers/dashboard/contributions/show.js b/app/controllers/dashboard/contributions/show.js
new file mode 100644
index 0000000..ef7f280
--- /dev/null
+++ b/app/controllers/dashboard/contributions/show.js
@@ -0,0 +1,12 @@
+
+import Controller from '@ember/controller';
+import { computed } from '@ember/object';
+import config from 'kredits-web/config/environment';
+
+export default Controller.extend({
+
+ ipfsGatewayUrl: computed(function() {
+ return config.ipfs.gatewayUrl;
+ }).volatile()
+
+});
diff --git a/app/models/contribution.js b/app/models/contribution.js
index a19c341..c6985fa 100644
--- a/app/models/contribution.js
+++ b/app/models/contribution.js
@@ -1,5 +1,7 @@
import EmberObject, { computed } from '@ember/object';
+import { isEmpty } from '@ember/utils';
import bignumber from 'kredits-web/utils/cps/bignumber';
+import moment from 'moment';
export default EmberObject.extend({
@@ -24,11 +26,15 @@ export default EmberObject.extend({
init () {
this._super(...arguments);
- this.set('details', {});
+ if (isEmpty(this.details)) this.set('details', {});
},
iso8601Date: computed('date', 'time', function() {
return this.time ? `${this.date}T${this.time}` : this.date;
+ }),
+
+ jsDate: computed('iso8601Date', function() {
+ return moment(this.iso8601Date).toDate();
})
});
diff --git a/app/router.js b/app/router.js
index e2c6349..014dbc8 100644
--- a/app/router.js
+++ b/app/router.js
@@ -21,6 +21,7 @@ Router.map(function() {
});
this.route('contributions', function() {
this.route('new');
+ this.route('resubmit', { path: ':id/resubmit' });
});
this.route('contributors', function() {
this.route('new');
diff --git a/app/routes/contributions/resubmit.js b/app/routes/contributions/resubmit.js
new file mode 100644
index 0000000..2de1d5a
--- /dev/null
+++ b/app/routes/contributions/resubmit.js
@@ -0,0 +1,25 @@
+import Route from '@ember/routing/route';
+import { inject as service } from '@ember/service';
+
+export default Route.extend({
+
+ kredits: service(),
+
+ model(params) {
+ const contribution = this.kredits.contributions.findBy('id', parseInt(params.id));
+ contribution.contributorId = contribution.contributorId.toString();
+
+ return contribution;
+ },
+
+ setupController (controller, model) {
+ this._super(controller, model);
+
+ controller.set('attributes', model.getProperties([
+ 'kind', 'amount', 'description', 'url', 'details'
+ ]));
+ controller.set('attributes.contributorId', model.contributorId.toString());
+ controller.set('attributes.date', model.jsDate);
+ }
+
+});
diff --git a/app/services/kredits.js b/app/services/kredits.js
index e651336..3fc96d3 100644
--- a/app/services/kredits.js
+++ b/app/services/kredits.js
@@ -225,33 +225,36 @@ export default Service.extend({
console.debug('[kredits] add contribution response', data);
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
const contribution = Contribution.create(attributes);
- // TODO receive from wrapper
contribution.set('confirmedAtBlock', data.blockNumber + 40320);
this.contributions.pushObject(contribution);
return contribution;
});
},
- addProposal (attributes) {
- console.debug('[kredits] add proposal', attributes);
+ //
+ // TODO Implement proposals with voting
+ //
- return this.kredits.Proposal.addProposal(attributes)
- .then((data) => {
- console.debug('[kredits] add proposal response', data);
- attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
- return Proposal.create(attributes);
- });
- },
+ // addProposal (attributes) {
+ // console.debug('[kredits] add proposal', attributes);
+ //
+ // return this.kredits.Proposal.addProposal(attributes)
+ // .then((data) => {
+ // console.debug('[kredits] add proposal response', data);
+ // attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
+ // return Proposal.create(attributes);
+ // });
+ // },
- getProposals () {
- return this.kredits.Proposal.all()
- .then((proposals) => {
- return proposals.map((proposal) => {
- proposal.contributor = this.contributors.findBy('id', proposal.contributorId.toString());
- return Proposal.create(proposal);
- });
- });
- },
+ // getProposals () {
+ // return this.kredits.Proposal.all()
+ // .then(proposals => {
+ // return proposals.map(proposal => {
+ // proposal.contributor = this.contributors.findBy('id', proposal.contributorId.toString());
+ // return Proposal.create(proposal);
+ // });
+ // });
+ // },
getContributions () {
return this.kredits.Contribution.all({page: {size: 200}})
@@ -311,6 +314,7 @@ export default Service.extend({
.on('ContributorAdded', this.handleContributorChange.bind(this))
this.kredits.Contribution
+ .on('ContributionAdded', this.handleContributionAdded.bind(this))
.on('ContributionVetoed', this.handleContributionVetoed.bind(this))
this.kredits.Proposal
@@ -338,6 +342,24 @@ export default Service.extend({
this.contributors.pushObject(newContributor);
},
+ async handleContributionAdded (id, contributorId, amount) {
+ console.debug('[kredits] ContributionAdded event received', { id, contributorId, amount });
+
+ const pendingContribution = this.contributions.find(c => {
+ return (c.id === null) &&
+ (c.contributorId.toString() === contributorId.toString()) &&
+ (c.amount.toString() === amount.toString());
+ });
+
+ if (pendingContribution) {
+ const attributes = await this.kredits.Contribution.getById(id);
+ attributes.contributor = this.contributors.findBy('id', attributes.contributorId.toString());
+ const newContribution = Contribution.create(attributes);
+ this.contributions.addObject(newContribution);
+ this.contributions.removeObject(pendingContribution);
+ }
+ },
+
handleContributionVetoed (contributionId) {
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
const contribution = this.contributions.findBy('id', contributionId);
diff --git a/app/styles/components/_contribution-details.scss b/app/styles/components/_contribution-details.scss
index d10e146..80c04b6 100644
--- a/app/styles/components/_contribution-details.scss
+++ b/app/styles/components/_contribution-details.scss
@@ -41,7 +41,7 @@ section#contribution-details {
}
}
- a {
+ a:not(.button) {
color: $primary-color;
text-decoration: none;
@@ -54,4 +54,35 @@ section#contribution-details {
.actions {
text-align: center;
}
+
+ &.vetoed {
+ .content {
+ h3 {
+ text-decoration: line-through;
+ }
+ }
+ }
+
+ .hint.vetoed {
+ overflow: auto;
+ margin-top: 2rem;
+ padding-top: 2rem;
+ border-top: 1px solid rgba(255,255,255,0.2);
+ font-size: 1.2rem;
+
+ .icon {
+ display: inline-block;
+ width: 40px;
+ height: 40px;
+ float: left;
+ margin-right: 1rem;
+ margin-bottom: 1rem;
+
+ svg {
+ width: 100%;
+ height: auto;
+ }
+ }
+ }
+
}
diff --git a/app/templates/contributions/resubmit.hbs b/app/templates/contributions/resubmit.hbs
new file mode 100644
index 0000000..79f9a46
--- /dev/null
+++ b/app/templates/contributions/resubmit.hbs
@@ -0,0 +1,13 @@
+Re-submit contribution #{{model.id}}
+ Contribution #{{model.id}}
+ This contribution has been vetoed, meaning no + kredits will be issued. +
++ {{link-to "Re-submit contribution …" "contributions.resubmit" model class="button small green"}}. +
+{{#if model.ipfsHash}} - Inspect IPFS data diff --git a/tests/unit/models/contribution-test.js b/tests/unit/models/contribution-test.js new file mode 100644 index 0000000..4dc28a1 --- /dev/null +++ b/tests/unit/models/contribution-test.js @@ -0,0 +1,27 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import Contribution from 'kredits-web/models/contribution'; + +module('Unit | Model | contribution', function(hooks) { + setupTest(hooks); + + test('iso8601Date', function(assert) { + const model = Contribution.create({ + date: '2019-09-10' + }); + assert.equal(model.iso8601Date, '2019-09-10'); + + model.set('time', '09:33:00.141Z'); + assert.equal(model.iso8601Date, '2019-09-10T09:33:00.141Z'); + }); + + test('jsDate', function(assert) { + const model = Contribution.create({ + date: '2019-09-10', + time: '09:33:00.141Z' + }); + + assert.ok(model.jsDate instanceof Date); + assert.equal(model.jsDate.toISOString(), '2019-09-10T09:33:00.141Z'); + }); +}); diff --git a/tests/unit/routes/contributions/resubmit-test.js b/tests/unit/routes/contributions/resubmit-test.js new file mode 100644 index 0000000..3d3c75d --- /dev/null +++ b/tests/unit/routes/contributions/resubmit-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | contributions/resubmit', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:contributions/resubmit'); + assert.ok(route); + }); +}); diff --git a/warning.svg b/warning.svg new file mode 100644 index 0000000..73231ed --- /dev/null +++ b/warning.svg @@ -0,0 +1,71 @@ + +