diff --git a/app/components/add-reimbursement/template.hbs b/app/components/add-reimbursement/template.hbs
index 43235b3..0e6a74c 100644
--- a/app/components/add-reimbursement/template.hbs
+++ b/app/components/add-reimbursement/template.hbs
@@ -44,26 +44,10 @@
Expense items
{{#if this.expenses}}
-
+
+
diff --git a/app/components/confirmed-in/component.js b/app/components/confirmed-in/component.js
new file mode 100644
index 0000000..487419b
--- /dev/null
+++ b/app/components/confirmed-in/component.js
@@ -0,0 +1,20 @@
+import Component from '@glimmer/component';
+import { inject as service } from '@ember/service';
+import moment from 'moment';
+
+export default class ConfirmedInComponent extends Component {
+ @service kredits;
+
+ get confirmedInBlocks () {
+ return this.args.confirmedAtBlock - this.kredits.currentBlock;
+ }
+
+ get confirmedInSeconds () {
+ // A new block is mined every 30 seconds on average
+ return this.confirmedInBlocks * 30;
+ }
+
+ get confirmedInHumanTime () {
+ return moment.duration(this.confirmedInSeconds, "seconds").humanize();
+ }
+}
diff --git a/app/components/confirmed-in/template.hbs b/app/components/confirmed-in/template.hbs
new file mode 100644
index 0000000..1529053
--- /dev/null
+++ b/app/components/confirmed-in/template.hbs
@@ -0,0 +1 @@
+Confirming in {{this.confirmedInBlocks}} blocks (~ {{this.confirmedInHumanTime}})
diff --git a/app/components/expense-list/component.js b/app/components/expense-list/component.js
new file mode 100644
index 0000000..640d820
--- /dev/null
+++ b/app/components/expense-list/component.js
@@ -0,0 +1,9 @@
+import Component from '@glimmer/component';
+
+export default class ExpenseListComponent extends Component {
+
+ get showDeleteButton () {
+ return !!this.args.deletable;
+ }
+
+}
diff --git a/app/components/expense-list/template.hbs b/app/components/expense-list/template.hbs
new file mode 100644
index 0000000..3633663
--- /dev/null
+++ b/app/components/expense-list/template.hbs
@@ -0,0 +1,29 @@
+
+ {{#each @expenses as |expense|}}
+ -
+
+ {{fmt-date-localized expense.date}}:
+ {{expense.title}}
+
+
+ {{fmt-fiat-currency expense.amount expense.currency}}
+
+
+ {{expense.description}}
+
+
+ {{#each expense.tags as |tag|}}
+
+ {{/each}}
+
+ {{#if this.showDeleteButton}}
+
+
+
+ {{/if}}
+
+ {{/each}}
+
diff --git a/app/components/reimbursement-list/template.hbs b/app/components/reimbursement-list/template.hbs
index b904207..50dcedf 100644
--- a/app/components/reimbursement-list/template.hbs
+++ b/app/components/reimbursement-list/template.hbs
@@ -3,44 +3,36 @@
-
- Expenses covered by {{reimbursement.contributor.name}}
-
+
+ Expenses covered by {{reimbursement.contributor.name}}
+
{{sats-to-btc reimbursement.amount}} BTC
-
- {{#if this.kredits.currentUserIsCore}}
-
+
+
+
+
{{/each}}
\ No newline at end of file
diff --git a/app/helpers/fmt-date-localized.js b/app/helpers/fmt-date-localized.js
new file mode 100644
index 0000000..a27bb28
--- /dev/null
+++ b/app/helpers/fmt-date-localized.js
@@ -0,0 +1,8 @@
+import { helper } from '@ember/component/helper';
+import getLocale from 'kredits-web/utils/get-locale';
+
+export default helper(function(dateStr) {
+ const date = new Date(dateStr);
+ const locale = getLocale();
+ return new Intl.DateTimeFormat(locale).format(date);
+});
diff --git a/app/services/kredits.js b/app/services/kredits.js
index dc62d47..12a58eb 100644
--- a/app/services/kredits.js
+++ b/app/services/kredits.js
@@ -118,9 +118,12 @@ export default Service.extend({
});
await kredits.init();
-
this.set('kredits', kredits);
- this.set('currentBlock', await kredits.provider.getBlockNumber());
+ this.set('currentBlock', await this.kredits.provider.getBlockNumber());
+ this.kredits.provider.on('block', blockNumber => {
+ console.debug('[kredits] New block mined:', blockNumber);
+ this.set('currentBlock', blockNumber)
+ });
if (this.currentUserAccounts && this.currentUserAccounts.length > 0) {
this.getCurrentUser.then(contributorData => {
@@ -738,5 +741,5 @@ export default Service.extend({
this.contributors
.findBy('address', to)
.incrementProperty('balance', value);
- },
+ }
});
diff --git a/app/styles/_buttons.scss b/app/styles/_buttons.scss
index eb0c2ff..db5a8bc 100644
--- a/app/styles/_buttons.scss
+++ b/app/styles/_buttons.scss
@@ -31,32 +31,53 @@ button, input[type=submit], .button {
&.small {
font-size: 0.86rem;
padding: 0.2rem 0.8rem;
+
+ svg {
+ width: 1em;
+ height: 1em;
+ vertical-align: middle;
+ margin-right: 0.4rem;
+ }
}
&.danger:not(:disabled) {
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);
- }
- &:focus, &:active, &.active {
- border-color: $red;
- }
+ &:hover { background-color: rgba(40, 21, 21, 0.8); }
+ &:focus, &:active, &.active { border-color: $red; }
}
&.green:not(:disabled) {
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); }
+ &:focus, &:active, &.active { border-color: $green; }
+ }
- &:hover {
- background-color: rgba(21, 40, 21, 0.8);
- }
- &:focus, &:active, &.active {
- border-color: $green;
- }
+ &.pink:not(:disabled) {
+ color: $pink;
+ background-color: rgba(40, 21, 40, 0.6);
+ border-color: rgba(40, 21, 40, 1);
+ &:hover { background-color: rgba(40, 21, 40, 0.8); }
+ &:focus, &:active, &.active { border-color: $pink; }
+ }
+
+ &.purple:not(:disabled) {
+ color: $purple;
+ background-color: rgba(24, 21, 40, 0.6);
+ border-color: rgba(24, 21, 40, 1);
+ &:hover { background-color: rgba(24, 21, 40, 0.8); }
+ &:focus, &:active, &.active { border-color: $purple; }
+ }
+
+ &.yellow:not(:disabled) {
+ color: $yellow;
+ background-color: rgba(40, 40, 21, 0.6);
+ border-color: rgba(40, 40, 21, 1);
+ &:hover { background-color: rgba(40, 40, 21, 0.8); }
+ &:focus, &:active, &.active { border-color: $yellow; }
}
&.icon {
diff --git a/app/styles/components/_expense-list.scss b/app/styles/components/_expense-list.scss
index b369f5f..b5a9650 100644
--- a/app/styles/components/_expense-list.scss
+++ b/app/styles/components/_expense-list.scss
@@ -17,32 +17,30 @@ ul.expense-list {
}
}
- .description {
- grid-row-start: 1;
- grid-row-end: 3;
- }
-
- .amount {
- justify-self: end;
- // font-weight: normal;
- }
-
- .actions {
- justify-self: end;
- }
-
h4 {
font-size: 1.2rem;
font-weight: normal;
line-height: 2rem;
}
- p {
- line-height: 2rem;
+ .amount {
+ justify-self: end;
+ }
- &.description {
- font-size: 1rem;
- opacity: 0.7;
+ .description {
+ font-size: 1rem;
+ opacity: 0.7;
+ grid-column-start: span 2;
+ }
+
+ .tags {
+ button {
+ margin-left: 0;
}
}
+
+ .actions {
+ justify-self: end;
+ }
+
}
diff --git a/app/styles/components/_reimbursement-list.scss b/app/styles/components/_reimbursement-list.scss
index dfbb5d8..556f69a 100644
--- a/app/styles/components/_reimbursement-list.scss
+++ b/app/styles/components/_reimbursement-list.scss
@@ -31,4 +31,24 @@ ul.reimbursement-list {
}
}
}
+
+ div.meta {
+ grid-column-start: 1;
+ grid-column-end: 3;
+ margin-top: 0.6rem;
+ border-top: 1px solid $item-border-color;
+ display: flex;
+
+ p {
+ flex: 1;
+ padding: 1.6rem 0 1rem 0;
+
+ &.confirmation-eta {
+ }
+
+ &.actions {
+ text-align: right;
+ }
+ }
+ }
}
diff --git a/app/templates/components/icon-tag.hbs b/app/templates/components/icon-tag.hbs
new file mode 100644
index 0000000..7219b15
--- /dev/null
+++ b/app/templates/components/icon-tag.hbs
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/utils/get-locale.js b/app/utils/get-locale.js
new file mode 100644
index 0000000..f80eb77
--- /dev/null
+++ b/app/utils/get-locale.js
@@ -0,0 +1,5 @@
+export default function() {
+ return (navigator.languages && navigator.languages.length) ?
+ navigator.languages[0] :
+ navigator.language;
+}
diff --git a/tests/unit/components/confirmed-in-test.js b/tests/unit/components/confirmed-in-test.js
new file mode 100644
index 0000000..7f1831c
--- /dev/null
+++ b/tests/unit/components/confirmed-in-test.js
@@ -0,0 +1,40 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+import createComponent from 'kredits-web/tests/helpers/create-component';
+// import moment from 'moment';
+
+module('Unit | Component | confirmed-in', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let component = createComponent('component:confirmed-in');
+ assert.ok(component);
+ });
+
+ test('#confirmedInBlocks', function(assert) {
+ const kredits = this.owner.lookup('service:kredits');
+ kredits.set('currentBlock', 419550);
+ let component = createComponent('component:confirmed-in');
+ component.args.confirmedAtBlock = 420000;
+
+ assert.equal(component.confirmedInBlocks, 450);
+ })
+
+ test('#confirmedInSeconds', function(assert) {
+ const kredits = this.owner.lookup('service:kredits');
+ kredits.set('currentBlock', 419550);
+ let component = createComponent('component:confirmed-in');
+ component.args.confirmedAtBlock = 420000;
+
+ assert.equal(component.confirmedInSeconds, 13500);
+ })
+
+ test('#confirmedInHumanTime', function(assert) {
+ const kredits = this.owner.lookup('service:kredits');
+ kredits.set('currentBlock', 419550);
+ let component = createComponent('component:confirmed-in');
+ component.args.confirmedAtBlock = 420000;
+
+ assert.equal(component.confirmedInHumanTime, '4 hours');
+ })
+});