diff --git a/app/components/add-contribution/component.js b/app/components/add-contribution/component.js new file mode 100644 index 0000000..4b16e65 --- /dev/null +++ b/app/components/add-contribution/component.js @@ -0,0 +1,70 @@ +import Component from '@ember/component'; +import { computed } from '@ember/object'; +import { and, notEmpty } from '@ember/object/computed'; + +export default Component.extend({ + + attributes: null, + contributors: Object.freeze([]), + + isValidContributor: notEmpty('contributorId'), + isValidKind: notEmpty('kind'), + isValidAmount: computed('amount', function() { + return parseInt(this.amount, 10) > 0; + }), + isValidDescription: notEmpty('description'), + isValidUrl: notEmpty('url'), + isValid: and('isValidContributor', + 'isValidKind', + 'isValidAmount', + 'isValidDescription'), + + init () { + this._super(...arguments); + this.set('defaultDate', new Date()); + + // Default attributes used by reset + this.set('attributes', { + contributorId: null, + kind: null, + date: [new Date()], + amount: null, + description: null, + url: null, + }); + + this.reset(); + }, + + reset () { + this.setProperties(this.attributes); + }, + + actions: { + + submit () { + if (!this.isValid) { + alert('Invalid data. Please review and try again.'); + return; + } + + const attributes = this.getProperties(Object.keys(this.attributes)); + const [ date/* , time */ ] = attributes.date[0].toISOString().split('T'); + attributes.date = date; + + this.set('inProgress', true); + + this.save(attributes) + .then((/*contribution*/) => { + this.reset(); + }, err => { + console.warn(err); + 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 new file mode 100644 index 0000000..ef69051 --- /dev/null +++ b/app/components/add-contribution/template.hbs @@ -0,0 +1,58 @@ +
+

+ +

+

+ +

+

+ {{ember-flatpickr + allowInput=false + altFormat="F j, Y" + altInput=true + altInputClass="date-alt" + date=date + dateFormat="Y-m-d" + defaultDate=defaultDate + maxDate=defaultDate + onChange=(action (mut date)) + }} +

+

+ {{input type="text" + placeholder="500" + value=amount + class=(if isValidAmount "valid" "")}} +

+

+ {{input type="text" + placeholder="Description" + value=description + class=(if isValidDescription "valid" "")}} +

+

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

+

+ {{input type="submit" + disabled=inProgress + value=(if inProgress "Processing" "Save")}} +

+
+ diff --git a/app/components/add-contributor/component.js b/app/components/add-contributor/component.js index 7e3b821..ac9cb57 100644 --- a/app/components/add-contributor/component.js +++ b/app/components/add-contributor/component.js @@ -3,6 +3,7 @@ import { and, notEmpty } from '@ember/object/computed'; import { inject as service } from '@ember/service'; export default Component.extend({ + kredits: service(), attributes: null, @@ -36,10 +37,7 @@ export default Component.extend({ gitea_username: null, wiki_username: null }); - }, - didInsertElement() { - this._super(...arguments); this.reset(); }, @@ -48,7 +46,8 @@ export default Component.extend({ }, actions: { - submit() { + + submit () { if (!this.isValid) { alert('Invalid data. Please review and try again.'); return; @@ -61,14 +60,14 @@ export default Component.extend({ this.save(contributor).then(() => { this.reset(); - window.scroll(0,0); }).catch(err => { - console.log(err); + console.warn(err); window.alert('Something went wrong. Please check the browser console.'); }).finally(() => { this.set('inProgress', false); }); } + } }); diff --git a/app/controllers/contributions/new.js b/app/controllers/contributions/new.js new file mode 100644 index 0000000..75e00c6 --- /dev/null +++ b/app/controllers/contributions/new.js @@ -0,0 +1,30 @@ +import Controller from '@ember/controller'; +import { alias, filterBy, sort } from '@ember/object/computed'; +import { inject as service } from '@ember/service'; + +export default Controller.extend({ + + kredits: service(), + + contributors: alias('kredits.contributors'), + minedContributors: filterBy('contributors', 'id'), + + contributorsSorting: Object.freeze(['name:asc']), + sortedContributors: sort('minedContributors', 'contributorsSorting'), + + actions: { + + save (contribution) { + const contributor = this.contributors.findBy('id', contribution.contributorId); + contribution.contributorIpfsHash = contributor.ipfsHash; + + return this.kredits.addContribution(contribution) + .then(contribution => { + this.transitionToRoute('index'); + return contribution; + }); + } + + } + +}); diff --git a/app/controllers/contributors/new.js b/app/controllers/contributors/new.js new file mode 100644 index 0000000..ed7a1f6 --- /dev/null +++ b/app/controllers/contributors/new.js @@ -0,0 +1,23 @@ +import Controller from '@ember/controller'; +import { alias } from '@ember/object/computed'; +import { inject as service } from '@ember/service'; + +export default Controller.extend({ + + kredits: service(), + + contributors: alias('kredits.contributors'), + + actions: { + + save (contributor) { + return this.kredits.addContributor(contributor) + .then(contributor => { + this.transitionToRoute('index'); + return contributor; + }); + } + + } + +}); diff --git a/app/controllers/index.js b/app/controllers/index.js index 9c614c7..dd7bb56 100644 --- a/app/controllers/index.js +++ b/app/controllers/index.js @@ -37,14 +37,6 @@ export default Controller.extend({ this.kredits.vote(proposalId).then(transaction => { console.debug('[controllers:index] Vote submitted to Ethereum blockhain: '+transaction.hash); }); - }, - - save (contributor) { - return this.kredits.addContributor(contributor) - .then(contributor => { - this.contributors.pushObject(contributor); - return contributor; - }); } } diff --git a/app/router.js b/app/router.js index 53708e0..afa8660 100644 --- a/app/router.js +++ b/app/router.js @@ -10,6 +10,12 @@ Router.map(function() { this.route('proposals', function() { this.route('new'); }); + this.route('contributions', function() { + this.route('new'); + }); + this.route('contributors', function() { + this.route('new'); + }); }); export default Router; diff --git a/app/services/kredits.js b/app/services/kredits.js index 2eee5c0..8eb6bbb 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -190,7 +190,9 @@ export default Service.extend({ return this.kredits.Contributor.add(attributes, { gasLimit: 350000 }) .then(data => { console.debug('[kredits] add contributor response', data); - return Contributor.create(attributes); + const contributor = Contributor.create(attributes); + this.contributors.pushObject(contributor); + return contributor; }); }, @@ -203,6 +205,21 @@ export default Service.extend({ }); }, + addContribution(attributes) { + console.debug('[kredits] add contribution', attributes); + + return this.kredits.Contribution.addContribution(attributes, { gasLimit: 300000 }) + .then(data => { + 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); diff --git a/app/styles/_buttons.scss b/app/styles/_buttons.scss index 8a6956a..41780e2 100644 --- a/app/styles/_buttons.scss +++ b/app/styles/_buttons.scss @@ -1,4 +1,4 @@ -button, input[type=submit] { +button, input[type=submit], .button { display: inline-block; padding: 0.6rem 2rem; background-color: rgba(22, 21, 40, 0.6); @@ -6,6 +6,7 @@ button, input[type=submit] { border-radius: 3px; color: $primary-color; font-weight: 500; + text-decoration: none; text-transform: uppercase; cursor: pointer; letter-spacing: 0.1em; @@ -22,9 +23,20 @@ button, input[type=submit] { &.danger { color: $red; background-color: rgba(40, 21, 21, 0.6); + border-color: rgba(40, 21, 21, 1); &:hover { background-color: rgba(40, 21, 21, 0.8); } } + + &.green { + color: $green; + background-color: rgba(21, 40, 21, 0.6); + border-color: rgba(21, 40, 21, 1); + + &:hover { + background-color: rgba(21, 40, 21, 0.8); + } + } } diff --git a/app/styles/components/_add-contributor.scss b/app/styles/_forms.scss similarity index 93% rename from app/styles/components/_add-contributor.scss rename to app/styles/_forms.scss index c39f8b9..6a8debd 100644 --- a/app/styles/components/_add-contributor.scss +++ b/app/styles/_forms.scss @@ -1,12 +1,14 @@ -section#add-contributor, section#add-proposal { +section#add-contributor, +section#add-contribution, +section#add-proposal { form { p { - margin-bottom: 1rem; + margin-bottom: 1.5rem; &.actions { - padding-top: 1rem; + padding-top: 1.5rem; text-align: center; a { color: $primary-color; diff --git a/app/styles/_layout.scss b/app/styles/_layout.scss index 2655bdc..ec0e401 100644 --- a/app/styles/_layout.scss +++ b/app/styles/_layout.scss @@ -1,9 +1,9 @@ -#topbar { - height: 3rem; -} - main { - padding: 1rem; + padding: 1rem 2rem; + + @include media-max(small) { + padding: 1rem; + } &#index { width: 100%; @@ -13,6 +13,21 @@ main { "stats" "contributions"; } + + &.center-column { + display: flex; + flex-direction: column; + align-items: center; + + section { + width: 600px; + max-width: 100%; + + header { + text-align: center; + } + } + } } @media (min-width: 550px) { @@ -39,11 +54,29 @@ main section { } header { - padding-bottom: 3rem; - text-align: center; + margin-bottom: 3rem; + + &.with-nav { + display: grid; + grid-template-columns: auto 5rem; + grid-template-areas: + "title" "actions"; + } + + h2 { + display: inline-block; + // padding-left: 1.2rem; + } + + nav { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-end; + } @include media-max(small) { - padding-bottom: 2rem; + margin-bottom: 2rem; } } } diff --git a/app/styles/app.scss b/app/styles/app.scss index d5e0f28..cac8311 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -96,10 +96,10 @@ section { } @import "buttons"; +@import "forms"; @import "components/topbar"; @import "components/loading-spinner"; @import "components/contributor-list"; -@import "components/add-contributor"; @import "components/proposal-list"; @import "components/contribution-list"; @import "components/user-avatar"; diff --git a/app/styles/components/_contribution-list.scss b/app/styles/components/_contribution-list.scss index 71367b9..0e0a938 100644 --- a/app/styles/components/_contribution-list.scss +++ b/app/styles/components/_contribution-list.scss @@ -15,7 +15,7 @@ ul.contribution-list { display: grid; grid-template-columns: auto 5rem 5rem; grid-row-gap: 0.5rem; - padding: 1rem 1.2rem; + padding: 0.8rem 1.2rem; background-color: rgba(255,255,255,0.1); font-size: 1.2rem; border-bottom: 1px solid rgba(255,255,255,0.2); @@ -80,8 +80,7 @@ ul.contribution-list { } .symbol { - font-size: 1rem; - font-weight: 500; + font-size: 0.8rem; padding-left: 0.2rem; } diff --git a/app/styles/components/_contributor-list.scss b/app/styles/components/_contributor-list.scss index fa5216b..0a94414 100644 --- a/app/styles/components/_contributor-list.scss +++ b/app/styles/components/_contributor-list.scss @@ -16,7 +16,11 @@ table.contributor-list { &.metadata { height: 0; - transition: all 0.2s ease-out; + visibility: hidden; + + &:not(.visible) { + border-bottom: none; + } td { padding: 0 1.2rem; @@ -34,7 +38,6 @@ table.contributor-list { display: block; overflow: hidden; height: 0; - transition: all 0.2s ease-out; li { display: inline; @@ -46,6 +49,7 @@ table.contributor-list { &.visible { height: auto; + visibility: visible; ul { height: auto; } @@ -54,11 +58,11 @@ table.contributor-list { td { padding: 0 1.2rem; - line-height: 4.2rem; + line-height: 3.6rem; &.person { text-align: left; - font-size: 1.4rem; + font-size: 1.2rem; img.avatar { margin-right: 0.2rem; @@ -68,10 +72,11 @@ table.contributor-list { &.kredits { text-align: right; .amount { - font-size: 1.4rem; + font-size: 1.2rem; + font-weight: 500; } .symbol { - font-size: 1rem; + font-size: 0.8rem; padding-left: 0.2rem; } } diff --git a/app/styles/components/_topbar.scss b/app/styles/components/_topbar.scss index 48ed6c1..43e931a 100644 --- a/app/styles/components/_topbar.scss +++ b/app/styles/components/_topbar.scss @@ -1,8 +1,15 @@ #topbar { padding: 0 1rem; + height: 3rem; line-height: 3rem; background-color: rgba(0,0,0,.3); + @include media-min(medium) { + padding: 0 2rem; + height: 4rem; + line-height: 4rem; + } + h1 { display: inline-block; text-transform: uppercase; diff --git a/app/templates/contributions/new.hbs b/app/templates/contributions/new.hbs new file mode 100644 index 0000000..c7b5ffb --- /dev/null +++ b/app/templates/contributions/new.hbs @@ -0,0 +1,13 @@ +
+ +
+
+

Submit a contribution

+
+ +
+ {{add-contribution contributors=sortedContributors save=(action "save")}} +
+
+ +
diff --git a/app/templates/contributors/new.hbs b/app/templates/contributors/new.hbs new file mode 100644 index 0000000..8351f57 --- /dev/null +++ b/app/templates/contributors/new.hbs @@ -0,0 +1,13 @@ +
+ +
+
+

Add contributor profile

+
+ +
+ {{add-contributor contributors=contributors save=(action "save")}} +
+
+ +
diff --git a/app/templates/index.hbs b/app/templates/index.hbs index 726e927..58fc3f0 100644 --- a/app/templates/index.hbs +++ b/app/templates/index.hbs @@ -2,8 +2,13 @@
-
+

Contributors

+ {{#if kredits.hasAccounts}} + + {{/if}}
{{contributor-list contributorList=kreditsToplist @@ -33,8 +38,13 @@
{{#if contributionsUnconfirmed}}
-
+

Latest Contributions

+ {{#if kredits.hasAccounts}} + + {{/if}}
{{!-- TODO: We need a better naming for kredits.hasAccounts --}} @@ -53,30 +63,7 @@ {{contribution-list contributions=contributionsConfirmedSorted vetoContribution=(action "vetoContribution")}}
- - {{!-- TODO: We need a better naming --}} - {{#if kredits.hasAccounts}} -

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

- {{/if}}
- {{#if kredits.hasAccounts}} -
-
-

Add Contributor

-
- -
- {{#if kredits.currentUser.isCore}} - {{add-contributor contributors=contributors save=(action "save")}} - {{else}} - Only core team members can add new contributors. Please ask someone to set you up. - {{/if}} -
-
- {{/if}} - diff --git a/package-lock.json b/package-lock.json index cc8d49b..bb54c5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6515,6 +6515,38 @@ "semver": "^5.3.0" } }, + "ember-diff-attrs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ember-diff-attrs/-/ember-diff-attrs-0.2.2.tgz", + "integrity": "sha512-dziQ8G8QVRMqSFMg2l9E+Te19kcwk7+Aad7Q8lOci2b3EAiU7s0IFB3Z8rRed0JRJ3e6mPJyRmNbyUuNoyCM8g==", + "dev": true, + "requires": { + "ember-cli-babel": "^6.16.0" + }, + "dependencies": { + "ember-cli-babel": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz", + "integrity": "sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA==", + "dev": true, + "requires": { + "amd-name-resolver": "1.2.0", + "babel-plugin-debug-macros": "^0.2.0-beta.6", + "babel-plugin-ember-modules-api-polyfill": "^2.6.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.0", + "babel-polyfill": "^6.26.0", + "babel-preset-env": "^1.7.0", + "broccoli-babel-transpiler": "^6.5.0", + "broccoli-debug": "^0.6.4", + "broccoli-funnel": "^2.0.0", + "broccoli-source": "^1.1.0", + "clone": "^2.0.0", + "ember-cli-version-checker": "^2.1.2", + "semver": "^5.5.0" + } + } + } + }, "ember-export-application-global": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz", @@ -6547,6 +6579,19 @@ } } }, + "ember-flatpickr": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/ember-flatpickr/-/ember-flatpickr-2.14.0.tgz", + "integrity": "sha512-YId4mRiVVYm74TWVaoKeWK0Ma8QY46dloZura9gkG3n+HADTTCerRvqZv5l6J7XaLzTC7bwXkf+4wOz3sYXmUQ==", + "dev": true, + "requires": { + "ember-cli-babel": "^7.1.2", + "ember-cli-node-assets": "^0.2.2", + "ember-diff-attrs": "^0.2.2", + "fastboot-transform": "^0.1.3", + "flatpickr": "4.5.2" + } + }, "ember-load-initializers": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz", @@ -8392,6 +8437,12 @@ "integrity": "sha1-Hxik2TgVLUlZZfnJWNkjqy3WabQ=", "dev": true }, + "flatpickr": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.5.2.tgz", + "integrity": "sha512-jDy4QYGpmiy7+Qk8QvKJ4spjDdxcx9cxMydmq1x427HkKWBw0qizLYeYM2F6tMcvvqGjU5VpJS55j4LnsaBblA==", + "dev": true + }, "follow-redirects": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", diff --git a/package.json b/package.json index bf43f95..6486fc2 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "ember-cli-uglify": "^2.1.0", "ember-cli-update": "^0.21.2", "ember-export-application-global": "^2.0.0", + "ember-flatpickr": "^2.14.0", "ember-load-initializers": "^1.1.0", "ember-macro-helpers": "0.17.0", "ember-maybe-import-regenerator": "^0.1.6", diff --git a/tests/unit/components/chart-contributions-by-type-test.js b/tests/unit/components/chart-contributions-by-type-test.js index 99ae79c..9a4c674 100644 --- a/tests/unit/components/chart-contributions-by-type-test.js +++ b/tests/unit/components/chart-contributions-by-type-test.js @@ -14,6 +14,7 @@ module('Unit | Component | chart-contributions-by-type', function(hooks) { { kind: 'community' , amount: 5000 , vetoed: false }, { kind: 'docs' , amount: 500 , vetoed: true }, { kind: 'docs' , amount: 500 , vetoed: false }, + { kind: 'special' , amount: 9999 , vetoed: false }, { kind: 'docs' , amount: 500 , vetoed: false } ];