From 969ef8d1ed853e29c73cf508b477eda713fc061a Mon Sep 17 00:00:00 2001 From: Garret Alfert Date: Wed, 3 May 2017 11:50:05 +0200 Subject: [PATCH 1/2] Add proposal form Closes #6 Form can be prefilled using query params on the route. The params are `recipient`, `amount`, `url` and `ipfsHash`. --- app/components/add-proposal/component.js | 60 +++++++++++++++++++ app/components/add-proposal/template.hbs | 31 ++++++++++ app/controllers/proposals/new.js | 27 +++++++++ app/router.js | 3 + app/routes/proposals/new.js | 15 +++++ app/services/kredits.js | 17 ++++++ app/styles/app.scss | 16 +++++ app/styles/components/_add-contributor.scss | 6 +- app/templates/index.hbs | 8 +++ app/templates/proposals/new.hbs | 10 ++++ package.json | 1 + .../components/add-proposal/component-test.js | 16 +++++ tests/unit/controllers/proposals/new-test.js | 12 ++++ tests/unit/routes/proposals/new-test.js | 11 ++++ 14 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 app/components/add-proposal/component.js create mode 100644 app/components/add-proposal/template.hbs create mode 100644 app/controllers/proposals/new.js create mode 100644 app/routes/proposals/new.js create mode 100644 app/templates/proposals/new.hbs create mode 100644 tests/integration/components/add-proposal/component-test.js create mode 100644 tests/unit/controllers/proposals/new-test.js create mode 100644 tests/unit/routes/proposals/new-test.js diff --git a/app/components/add-proposal/component.js b/app/components/add-proposal/component.js new file mode 100644 index 0000000..70a990a --- /dev/null +++ b/app/components/add-proposal/component.js @@ -0,0 +1,60 @@ +import Ember from 'ember'; + +const { + Component, + inject: { + service + }, + computed +} = Ember; + +export default Component.extend({ + + kredits: service(), + + proposal: null, + inProgress: false, + + isValidRecipient: computed('proposal.recipientAddress', function() { + return this.get('kredits.web3Instance').isAddress(this.get('proposal.recipientAddress')); + }), + + isValidAmount: computed('proposal.amount', function() { + // TODO + return true; + }), + + isValidUrl: computed('proposal.url', function() { + // TODO + return true; + }), + + isValidIpfsHash: computed('proposal.ipfsHash', function() { + // TODO + return true; + }), + + isValid: computed.and('isValidRecipient', 'isValidAmount', 'isValidUrl', + 'isValidIpfsHash'), + + actions: { + save() { + if (this.get('isValid')) { + this.set('inProgress', true); + + this.get('kredits').addProposal(this.get('proposal')) + .then(() => { + this.attrs.onSave(); + }).catch((error) => { + Ember.Logger.error('Error creating the proposal', error); + alert('Something went wrong.'); + }).finally(() => { + this.set('inProgress', false); + }); + } else { + alert('Invalid data. Please review and try again.'); + } + } + } + +}); diff --git a/app/components/add-proposal/template.hbs b/app/components/add-proposal/template.hbs new file mode 100644 index 0000000..636b34f --- /dev/null +++ b/app/components/add-proposal/template.hbs @@ -0,0 +1,31 @@ +
+

+ {{input type="text" + placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4" + value=proposal.recipientAddress + class=(if isValidRecipient 'valid' '')}} +

+

+ {{input type="text" + placeholder="100" + value=proposal.amount + class=(if isValidAmount 'valid' '')}} +

+

+ {{input type="text" + placeholder="URL" + value=proposal.url + class=(if isValidUrl 'valid' '')}} +

+

+ {{input type="text" + placeholder="IPFS Hash" + value=proposal.ipfsHash + class=(if isValidIpfsHash 'valid' '')}} +

+

+ {{input type="submit" value=(if inProgress 'Processing' 'Save') disabled=inProgress}} + {{#link-to 'index'}}Back{{/link-to}} +

+
+ diff --git a/app/controllers/proposals/new.js b/app/controllers/proposals/new.js new file mode 100644 index 0000000..a557d7c --- /dev/null +++ b/app/controllers/proposals/new.js @@ -0,0 +1,27 @@ +import Ember from 'ember'; +import QueryParams from 'ember-parachute'; + +export const queryParams = new QueryParams({ + recipient: { + defaultValue: '' + }, + amount: { + defaultValue: '' + }, + url: { + defaultValue: '' + }, + ipfsHash: { + defaultValue: '' + } +}); + +export default Ember.Controller.extend(queryParams.Mixin, { + + actions: { + onSave() { + this.transitionToRoute('index'); + } + } + +}); diff --git a/app/router.js b/app/router.js index 23c14c6..7f9f715 100644 --- a/app/router.js +++ b/app/router.js @@ -8,6 +8,9 @@ const Router = Ember.Router.extend({ Router.map(function() { this.route('spinner'); + this.route('proposals', function() { + this.route('new'); + }); }); export default Router; diff --git a/app/routes/proposals/new.js b/app/routes/proposals/new.js new file mode 100644 index 0000000..3326e8d --- /dev/null +++ b/app/routes/proposals/new.js @@ -0,0 +1,15 @@ +import Ember from 'ember'; +import Proposal from 'kredits-web/models/proposal'; + +export default Ember.Route.extend({ + + model(params) { + return Proposal.create({ + recipientAddress: params.recipient, + amount: params.amount, + url: params.url, + ipfsHash: params.ipfsHash + }); + } + +}); diff --git a/app/services/kredits.js b/app/services/kredits.js index 4019441..cf876ff 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -164,6 +164,23 @@ export default Ember.Service.extend({ }); }, + addProposal(proposal) { + return new Ember.RSVP.Promise((resolve, reject) => { + const { + recipientAddress, + amount, + url, + ipfsHash + } = proposal.getProperties('recipientAddress', 'amount', 'url', 'ipfsHash'); + + this.get('kreditsContract').addProposal(recipientAddress, amount, url, ipfsHash, (err, data) => { + if (err) { reject(err); return; } + Ember.Logger.debug('[kredits] add proposal response', data); + resolve(); + }); + }); + }, + logKreditsContract: function() { Ember.Logger.debug('[kredits] kreditsContract', this.get('kreditsContract')); }.on('init') diff --git a/app/styles/app.scss b/app/styles/app.scss index 9fa25b3..d8f2e8a 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -65,6 +65,22 @@ section { } } } + + &#proposals-open, &#proposals-closed { + .actions { + padding-top: 3rem; + font-size: 1rem; + color: lightblue; + text-align: center; + @include media($mobile) { + padding-top: 2rem; + } + + a { + color: lightblue; + } + } + } } button, input[type=submit] { diff --git a/app/styles/components/_add-contributor.scss b/app/styles/components/_add-contributor.scss index 8a12a31..bb974f2 100644 --- a/app/styles/components/_add-contributor.scss +++ b/app/styles/components/_add-contributor.scss @@ -1,4 +1,4 @@ -section#add-contributor { +section#add-contributor, section#add-proposal { form { @@ -8,6 +8,10 @@ section#add-contributor { &.actions { padding-top: 1rem; text-align: center; + a { + color: lightblue; + margin-left: 1rem; + } } } diff --git a/app/templates/index.hbs b/app/templates/index.hbs index b4e0bb6..d995bbf 100644 --- a/app/templates/index.hbs +++ b/app/templates/index.hbs @@ -22,6 +22,10 @@ {{proposal-list proposals=proposalsOpenSorted confirmAction="confirmProposal" contractInteractionEnabled=contractInteractionEnabled}} + +

+ {{#link-to 'proposals.new'}}Create new proposal{{/link-to}} +

{{/if}} @@ -33,6 +37,10 @@
{{proposal-list proposals=proposalsClosedSorted confirmAction="confirmProposal"}} + +

+ {{#link-to 'proposals.new'}}Create new proposal{{/link-to}} +

diff --git a/app/templates/proposals/new.hbs b/app/templates/proposals/new.hbs new file mode 100644 index 0000000..3319d38 --- /dev/null +++ b/app/templates/proposals/new.hbs @@ -0,0 +1,10 @@ +
+
+

Add Proposal

+
+ +
+ {{add-proposal proposal=model onSave=(action 'onSave')}} +
+
+ diff --git a/package.json b/package.json index 354fbe7..0632418 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "ember-cli-uglify": "^1.2.0", "ember-export-application-global": "^1.0.5", "ember-load-initializers": "^0.5.1", + "ember-parachute": "0.1.0", "ember-resolver": "^2.0.3", "ipfs-api": "^12.1.7", "kredits-contracts": "67P/kredits-contracts", diff --git a/tests/integration/components/add-proposal/component-test.js b/tests/integration/components/add-proposal/component-test.js new file mode 100644 index 0000000..b942b64 --- /dev/null +++ b/tests/integration/components/add-proposal/component-test.js @@ -0,0 +1,16 @@ +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('add-proposal', 'Integration | Component | add proposal', { + integration: true +}); + +test('it renders', function(assert) { + + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... }); + + this.render(hbs`{{add-proposal}}`); + + assert.equal(this.$('.actions a').text().trim(), 'Back'); +}); diff --git a/tests/unit/controllers/proposals/new-test.js b/tests/unit/controllers/proposals/new-test.js new file mode 100644 index 0000000..d3f8745 --- /dev/null +++ b/tests/unit/controllers/proposals/new-test.js @@ -0,0 +1,12 @@ +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('controller:proposals/new', 'Unit | Controller | proposals/new', { + // Specify the other units that are required for this test. + // needs: ['controller:foo'] +}); + +// Replace this with your real tests. +test('it exists', function(assert) { + let controller = this.subject(); + assert.ok(controller); +}); diff --git a/tests/unit/routes/proposals/new-test.js b/tests/unit/routes/proposals/new-test.js new file mode 100644 index 0000000..ad8366e --- /dev/null +++ b/tests/unit/routes/proposals/new-test.js @@ -0,0 +1,11 @@ +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('route:proposals/new', 'Unit | Route | proposals/new', { + // Specify the other units that are required for this test. + // needs: ['controller:foo'] +}); + +test('it exists', function(assert) { + let route = this.subject(); + assert.ok(route); +}); From 642015700eab0b3b8a5ff6c70857f9452b04c990 Mon Sep 17 00:00:00 2001 From: Garret Alfert Date: Wed, 3 May 2017 11:53:21 +0200 Subject: [PATCH 2/2] Don't resolve promises after rejecting them --- app/services/kredits.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/services/kredits.js b/app/services/kredits.js index cf876ff..0100572 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -54,7 +54,7 @@ export default Ember.Service.extend({ getValueFromContract(contractMethod, ...args) { return new Ember.RSVP.Promise((resolve, reject) => { this.get('kreditsContract')[contractMethod](...args, (err, data) => { - if (err) { reject(err); } + if (err) { reject(err); return; } resolve(data); }); }); @@ -132,7 +132,7 @@ export default Ember.Service.extend({ Ember.Logger.debug('[kredits] vote for', proposalId); return new Ember.RSVP.Promise((resolve, reject) => { this.get('kreditsContract').vote(proposalId, (err, data) => { - if (err) { reject(err); } + if (err) { reject(err); return; } Ember.Logger.debug('[kredits] vote response', data); resolve(data); }); @@ -156,7 +156,7 @@ export default Ember.Service.extend({ contributor.set('ipfsHash', ipfsHash); console.debug('ADD', address, name, ipfsHash, isCore, id); this.get('kreditsContract').addContributor(address, name, ipfsHash, isCore, id, (err, data) => { - if (err) { reject(err); } + if (err) { reject(err); return; } Ember.Logger.debug('[kredits] add contributor response', data); resolve(contributor); });