Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
6a72a5b418
|
|||
|
d90ddd464a
|
|||
|
2626543f3e
|
|||
| 088db24534 | |||
| f7b7daa024 | |||
| bb11e2267b | |||
| 7cd023a21b | |||
|
1095bf0218
|
|||
|
138cec0389
|
|||
|
a93be41e08
|
|||
|
89f6fa0b5c
|
|||
|
e2a80eafd1
|
|||
|
662e76979b
|
|||
|
6c7de97e38
|
|||
|
fe27b010da
|
|||
|
ff716c68ea
|
|||
|
84dded2f10
|
|||
|
ee664c06c1
|
|||
|
62b618b657
|
|||
| 348dc03429 | |||
|
d159fca816
|
|||
|
a582f41fde
|
|||
|
2082b51c5b
|
|||
|
e543708b42
|
|||
|
0b0dea095f
|
|||
|
c7eb81450c
|
|||
|
ca1ccf6d93
|
|||
| 0b79d48be9 | |||
|
f8cc453d7e
|
|||
|
f86190030f
|
@@ -48,6 +48,12 @@ module.exports = {
|
|||||||
"no-action"
|
"no-action"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"moduleId": "app/components/expense-list/template",
|
||||||
|
"only": [
|
||||||
|
"no-invalid-role"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"moduleId": "app/components/topbar-account-panel/template",
|
"moduleId": "app/components/topbar-account-panel/template",
|
||||||
"only": [
|
"only": [
|
||||||
|
|||||||
@@ -63,7 +63,10 @@ export default class AddExpenseItemComponent extends Component {
|
|||||||
|
|
||||||
let dateInput = (this.date instanceof Array) ?
|
let dateInput = (this.date instanceof Array) ?
|
||||||
this.date[0] : this.date;
|
this.date[0] : this.date;
|
||||||
const [ date ] = dateInput.toISOString().split('T');
|
|
||||||
|
const [ date ] = moment(dateInput).utcOffset(0, true)
|
||||||
|
.toISOString()
|
||||||
|
.split('T');
|
||||||
|
|
||||||
const isValid = this.validateForm();
|
const isValid = this.validateForm();
|
||||||
if (!isValid) return false;
|
if (!isValid) return false;
|
||||||
@@ -78,7 +81,9 @@ export default class AddExpenseItemComponent extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPresent(this.tags)) {
|
if (isPresent(this.tags)) {
|
||||||
expense.tags = this.tags.split(',').map(t => t.trim());
|
expense.tags = this.tags.split(',')
|
||||||
|
.map(t => t.trim())
|
||||||
|
.filter(t => t.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.args.addExpenseItem(expense);
|
this.args.addExpenseItem(expense);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { action } from '@ember/object';
|
|||||||
import { A } from '@ember/array';
|
import { A } from '@ember/array';
|
||||||
import { scheduleOnce } from '@ember/runloop';
|
import { scheduleOnce } from '@ember/runloop';
|
||||||
import isValidAmount from 'kredits-web/utils/is-valid-amount';
|
import isValidAmount from 'kredits-web/utils/is-valid-amount';
|
||||||
|
import readFileContent from 'kredits-web/utils/read-file-content';
|
||||||
import config from 'kredits-web/config/environment';
|
import config from 'kredits-web/config/environment';
|
||||||
|
|
||||||
export default class AddReimbursementComponent extends Component {
|
export default class AddReimbursementComponent extends Component {
|
||||||
@@ -84,6 +85,23 @@ export default class AddReimbursementComponent extends Component {
|
|||||||
this.total = btcAmount.toFixed(8);
|
this.total = btcAmount.toFixed(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO use ember-concurrency here
|
||||||
|
// https://github.com/67P/kredits-web/pull/209#discussion_r1064234421
|
||||||
|
@action
|
||||||
|
async addExpensesFromFile (evt) {
|
||||||
|
const content = await readFileContent(evt.target.files[0]);
|
||||||
|
const expenses = JSON.parse(content);
|
||||||
|
|
||||||
|
if (expenses instanceof Array) {
|
||||||
|
for (const item of expenses) {
|
||||||
|
this.addExpenseItem(item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("Expenses in file must be a list of items:");
|
||||||
|
console.debug(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
updateContributor (event) {
|
updateContributor (event) {
|
||||||
this.recipientId = event.target.value;
|
this.recipientId = event.target.value;
|
||||||
|
|||||||
@@ -44,26 +44,10 @@
|
|||||||
|
|
||||||
<h3>Expense items</h3>
|
<h3>Expense items</h3>
|
||||||
{{#if this.expenses}}
|
{{#if this.expenses}}
|
||||||
<ul class="expense-list">
|
<ExpenseList @expenses={{this.expenses}}
|
||||||
{{#each this.expenses as |expense|}}
|
@removeExpenseItem={{this.removeExpenseItem}}
|
||||||
<li>
|
@deletable={{true}} />
|
||||||
<div class="description" rowspan="2">
|
|
||||||
<h4>
|
|
||||||
<span class="date">{{expense.date}}:</span>
|
|
||||||
<span class="title">{{expense.title}}</span>
|
|
||||||
</h4>
|
|
||||||
<p class="description">{{expense.description}}</p>
|
|
||||||
</div>
|
|
||||||
<div class="amount">
|
|
||||||
{{fmt-fiat-currency expense.amount expense.currency}}
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<button {{on "click" (fn this.removeExpenseItem expense)}}
|
|
||||||
class="danger small" type="button">delete</button>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
<p class="actions">
|
<p class="actions">
|
||||||
<button {{on "click" this.showExpenseForm}}
|
<button {{on "click" this.showExpenseForm}}
|
||||||
class="green small" type="button">+ Add another item</button>
|
class="green small" type="button">+ Add another item</button>
|
||||||
@@ -87,3 +71,9 @@
|
|||||||
<AddExpenseItem @addExpenseItem={{fn this.addExpenseItem}} />
|
<AddExpenseItem @addExpenseItem={{fn this.addExpenseItem}} />
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</form>
|
</form>
|
||||||
|
<form id="add-expenses-from-file">
|
||||||
|
<h3>Add expense items from file</h3>
|
||||||
|
<input type="file" multiple="false"
|
||||||
|
onchange={{fn this.addExpensesFromFile}}
|
||||||
|
accept="application/json" />
|
||||||
|
</form>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { inject as service } from '@ember/service';
|
|||||||
import { alias } from '@ember/object/computed';
|
import { alias } from '@ember/object/computed';
|
||||||
|
|
||||||
export default class BudgetBalancesComponent extends Component {
|
export default class BudgetBalancesComponent extends Component {
|
||||||
@service communityFunds
|
@service communityFunds;
|
||||||
@alias('communityFunds.balances') balances;
|
@alias('communityFunds.balances') balances;
|
||||||
|
|
||||||
get loading () {
|
get loading () {
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
get isConfirmed () {
|
||||||
|
return this.confirmedInBlocks <= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{{#unless this.isConfirmed}}
|
||||||
|
Confirming in <strong>{{this.confirmedInBlocks}}</strong> blocks (~ {{this.confirmedInHumanTime}})
|
||||||
|
{{/unless}}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import Component from '@glimmer/component';
|
||||||
|
|
||||||
|
export default class ExpenseListComponent extends Component {
|
||||||
|
|
||||||
|
get showDeleteButton () {
|
||||||
|
return !!this.args.deletable;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<ul class="expense-list">
|
||||||
|
{{#each @expenses as |expense|}}
|
||||||
|
<li class="expense-item">
|
||||||
|
<h4>
|
||||||
|
<span class="date">{{fmt-date-localized expense.date}}:</span>
|
||||||
|
<span class="title">{{expense.title}}</span>
|
||||||
|
</h4>
|
||||||
|
<div class="amount">
|
||||||
|
{{fmt-fiat-currency expense.amount expense.currency}}
|
||||||
|
</div>
|
||||||
|
<p class="description">
|
||||||
|
{{expense.description}}
|
||||||
|
</p>
|
||||||
|
<p class="tags">
|
||||||
|
{{#each expense.tags as |tag|}}
|
||||||
|
<button type="button" class="small yellow" role="none">
|
||||||
|
<IconTag />{{tag}}
|
||||||
|
</button>
|
||||||
|
{{/each}}
|
||||||
|
</p>
|
||||||
|
{{#if this.showDeleteButton}}
|
||||||
|
<div class="actions">
|
||||||
|
<button {{on "click" (fn @removeExpenseItem expense)}}
|
||||||
|
class="danger small" type="button">delete</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
@@ -1,7 +1,23 @@
|
|||||||
import Component from '@glimmer/component';
|
import Component from '@glimmer/component';
|
||||||
import { sort } from '@ember/object/computed';
|
import { sort } from '@ember/object/computed';
|
||||||
|
import { action } from '@ember/object';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
import config from 'kredits-web/config/environment';
|
||||||
|
|
||||||
export default class ReimbursementListComponent extends Component {
|
export default class ReimbursementListComponent extends Component {
|
||||||
|
@service kredits;
|
||||||
|
|
||||||
itemSorting = Object.freeze(['pendingStatus:asc', 'id:desc']);
|
itemSorting = Object.freeze(['pendingStatus:asc', 'id:desc']);
|
||||||
@sort('args.items', 'itemSorting') itemsSorted;
|
@sort('args.items', 'itemSorting') itemsSorted;
|
||||||
|
|
||||||
|
get ipfsGatewayUrl () {
|
||||||
|
return config.ipfs.gatewayUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
veto (id) {
|
||||||
|
this.kredits.vetoReimbursement(id).then(transaction => {
|
||||||
|
console.debug('[controllers:budget] Veto submitted to chain: '+transaction.hash);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,29 +3,36 @@
|
|||||||
<li data-reimbursement-id={{reimbursement.id}}
|
<li data-reimbursement-id={{reimbursement.id}}
|
||||||
class="{{item-status reimbursement}}">
|
class="{{item-status reimbursement}}">
|
||||||
<p class="meta">
|
<p class="meta">
|
||||||
<span class="recipient"><UserAvatar @contributor={{reimbursement.contributor}} /></span>
|
<span class="recipient">
|
||||||
<span class="title">Expenses covered by {{reimbursement.contributor.name}}</span>
|
<UserAvatar @contributor={{reimbursement.contributor}} />
|
||||||
|
</span>
|
||||||
|
<span class="title">
|
||||||
|
Expenses covered by {{reimbursement.contributor.name}}
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="token-amount">
|
<p class="token-amount">
|
||||||
<span class="amount">
|
<span class="amount">
|
||||||
{{sats-to-btc reimbursement.amount}}</span> <span class="symbol">BTC</span>
|
{{sats-to-btc reimbursement.amount}}</span> <span class="symbol">BTC</span>
|
||||||
</p>
|
</p>
|
||||||
<ul class="expense-list">
|
|
||||||
{{#each reimbursement.expenses as |expense|}}
|
<ExpenseList @expenses={{reimbursement.expenses}} />
|
||||||
<li>
|
|
||||||
<div class="description" rowspan="2">
|
<div class="meta">
|
||||||
<h4>
|
<p class="confirmation-eta">
|
||||||
<span class="date">{{expense.date}}:</span>
|
<ConfirmedIn @confirmedAtBlock={{reimbursement.confirmedAt}} />
|
||||||
<span class="title">{{expense.title}}</span>
|
</p>
|
||||||
</h4>
|
<p class="actions">
|
||||||
<p class="description">{{expense.description}}</p>
|
<a href="{{this.ipfsGatewayUrl}}/{{reimbursement.ipfsHash}}"
|
||||||
</div>
|
class="button small" target="_blank" rel="noopener noreferrer">
|
||||||
<div class="amount">
|
Inspect IPFS data
|
||||||
{{fmt-fiat-currency expense.amount expense.currency}}
|
</a>
|
||||||
|
{{#if this.kredits.currentUserIsCore}}
|
||||||
|
<button {{on "click" (fn this.veto reimbursement.id)}}
|
||||||
|
disabled={{reimbursement.vetoed}}
|
||||||
|
class="button small danger" type="button">veto</button>
|
||||||
|
{{/if}}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Controller from '@ember/controller';
|
import Controller from '@ember/controller';
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import { alias, not, sort } from '@ember/object/computed';
|
import { alias, gt, not, sort } from '@ember/object/computed';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
@@ -33,6 +33,8 @@ export default Controller.extend({
|
|||||||
showQuickFilterUnconfirmed: false,
|
showQuickFilterUnconfirmed: false,
|
||||||
showQuickFilterConfirmed: false,
|
showQuickFilterConfirmed: false,
|
||||||
|
|
||||||
|
showFullContributionSync: gt('kredits.missingHistoricContributionsCount', 0),
|
||||||
|
|
||||||
showIntroText: computed('kredits.{hasAccounts,currentUser}', function(){
|
showIntroText: computed('kredits.{hasAccounts,currentUser}', function(){
|
||||||
return (!this.kredits.hasAccounts || !this.kredits.currentUser);
|
return (!this.kredits.hasAccounts || !this.kredits.currentUser);
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
@@ -11,8 +11,11 @@ export default class DashboardRoute extends Route {
|
|||||||
schedule('afterRender', this.kredits.syncContributions,
|
schedule('afterRender', this.kredits.syncContributions,
|
||||||
this.kredits.syncContributions.perform);
|
this.kredits.syncContributions.perform);
|
||||||
}
|
}
|
||||||
schedule('afterRender', this.kredits.fetchMissingContributions,
|
// TODO fetch automatically under a certain threshold
|
||||||
this.kredits.fetchMissingContributions.perform);
|
// The browser might delete cached data and we don't need manual re-syncs
|
||||||
|
// depending on how little is missing
|
||||||
|
// schedule('afterRender', this.kredits.fetchMissingContributions,
|
||||||
|
// this.kredits.fetchMissingContributions.perform);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-21
@@ -48,6 +48,8 @@ export default Service.extend({
|
|||||||
contributionsNeedSync: false,
|
contributionsNeedSync: false,
|
||||||
reimbursementsNeedSync: false,
|
reimbursementsNeedSync: false,
|
||||||
|
|
||||||
|
missingHistoricContributionsCount: 0,
|
||||||
|
|
||||||
init () {
|
init () {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.set('contributors', []);
|
this.set('contributors', []);
|
||||||
@@ -118,9 +120,12 @@ export default Service.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
await kredits.init();
|
await kredits.init();
|
||||||
|
|
||||||
this.set('kredits', kredits);
|
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) {
|
if (this.currentUserAccounts && this.currentUserAccounts.length > 0) {
|
||||||
this.getCurrentUser.then(contributorData => {
|
this.getCurrentUser.then(contributorData => {
|
||||||
@@ -227,12 +232,20 @@ export default Service.extend({
|
|||||||
await this.loadObjectsFromCache('Contribution');
|
await this.loadObjectsFromCache('Contribution');
|
||||||
this.set('contributionsNeedSync', true);
|
this.set('contributionsNeedSync', true);
|
||||||
} else {
|
} else {
|
||||||
await this.fetchContributions({ page: { size: 30 } });
|
await this.fetchContributions({ page: { size: 40 } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.updateMissingHistoricContributionsCount();
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async updateMissingHistoricContributionsCount () {
|
||||||
|
const contributionsCount = await this.kredits.Contribution.count;
|
||||||
|
this.set('missingHistoricContributionsCount', contributionsCount - this.contributions.length);
|
||||||
|
console.debug(`Missing ${this.missingHistoricContributionsCount} historic contributions (out of ${contributionsCount} overall)`)
|
||||||
|
},
|
||||||
|
|
||||||
addContributor (attributes) {
|
addContributor (attributes) {
|
||||||
if (attributes.github_uid) {
|
if (attributes.github_uid) {
|
||||||
const uidInt = parseInt(attributes.github_uid);
|
const uidInt = parseInt(attributes.github_uid);
|
||||||
@@ -368,11 +381,12 @@ export default Service.extend({
|
|||||||
syncContributions: task(function * () {
|
syncContributions: task(function * () {
|
||||||
yield this.fetchNewContributions.perform();
|
yield this.fetchNewContributions.perform();
|
||||||
yield this.syncUnconfirmedContributions.perform();
|
yield this.syncUnconfirmedContributions.perform();
|
||||||
|
yield this.updateMissingHistoricContributionsCount();
|
||||||
this.set('contributionsNeedSync', false);
|
this.set('contributionsNeedSync', false);
|
||||||
}).group('contributionTasks'),
|
}).group('contributionTasks'),
|
||||||
|
|
||||||
fetchNewContributions: task(function * () {
|
fetchNewContributions: task(function * () {
|
||||||
const count = yield this.kredits.Contribution.functions.contributionsCount();
|
const count = yield this.kredits.Contribution.count;
|
||||||
const lastKnownContributionId = Math.max.apply(null, this.contributions.mapBy('id'));
|
const lastKnownContributionId = Math.max.apply(null, this.contributions.mapBy('id'));
|
||||||
const toFetch = count - lastKnownContributionId;
|
const toFetch = count - lastKnownContributionId;
|
||||||
|
|
||||||
@@ -389,7 +403,7 @@ export default Service.extend({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
fetchMissingContributions: task(function * () {
|
fetchMissingContributions: task(function * () {
|
||||||
const count = yield this.kredits.Contribution.functions.contributionsCount();
|
const count = yield this.kredits.Contribution.count;
|
||||||
const allIds = [...Array(count+1).keys()];
|
const allIds = [...Array(count+1).keys()];
|
||||||
allIds.shift(); // remove first item, which is 0
|
allIds.shift(); // remove first item, which is 0
|
||||||
const loadedContributions = new Set(this.contributions.mapBy('id'));
|
const loadedContributions = new Set(this.contributions.mapBy('id'));
|
||||||
@@ -617,6 +631,18 @@ export default Service.extend({
|
|||||||
yield this.fetchMissingObjects.perform('Reimbursement');
|
yield this.fetchMissingObjects.perform('Reimbursement');
|
||||||
}).group('syncTaskGroup'),
|
}).group('syncTaskGroup'),
|
||||||
|
|
||||||
|
vetoReimbursement (id) {
|
||||||
|
console.debug('[kredits] veto against reimbursement', id);
|
||||||
|
const reimbursement = this.reimbursements.findBy('id', id);
|
||||||
|
|
||||||
|
return this.kredits.Reimbursement.functions.veto(id, { gasLimit: 300000 })
|
||||||
|
.then(data => {
|
||||||
|
console.debug('[kredits] veto response', data);
|
||||||
|
reimbursement.set('pendingTx', data);
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
//
|
//
|
||||||
// Contract events
|
// Contract events
|
||||||
//
|
//
|
||||||
@@ -676,7 +702,7 @@ export default Service.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async handleContributionVetoed (contributionId) {
|
async handleContributionVetoed (contributionId) {
|
||||||
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
|
console.debug('[kredits] ContributionVetoed event received for #', contributionId);
|
||||||
const c = this.contributions.findBy('id', contributionId);
|
const c = this.contributions.findBy('id', contributionId);
|
||||||
|
|
||||||
if (c) {
|
if (c) {
|
||||||
@@ -687,9 +713,6 @@ export default Service.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
//
|
|
||||||
// TODO test when reimbursement txs are successful
|
|
||||||
//
|
|
||||||
async handleReimbursementAdded (id, addedByAccount, amount) {
|
async handleReimbursementAdded (id, addedByAccount, amount) {
|
||||||
console.debug('[kredits] ReimbursementAdded event received', { id, addedByAccount, amount });
|
console.debug('[kredits] ReimbursementAdded event received', { id, addedByAccount, amount });
|
||||||
|
|
||||||
@@ -703,20 +726,19 @@ export default Service.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await this.kredits.Reimbursement.getById(id);
|
const data = await this.kredits.Reimbursement.getById(id);
|
||||||
this.loadReimbursementFromData(data);
|
const r = this.loadReimbursementFromData(data);
|
||||||
|
this.browserCache.reimbursements.setItem(r.id.toString(), r.serialize());
|
||||||
},
|
},
|
||||||
|
|
||||||
//
|
async handleReimbursementVetoed (id) {
|
||||||
// TODO test when reimbursement txs are successful and veto is implemented
|
console.debug(`[kredits] ReimbursementVetoed received for #${id}`);
|
||||||
//
|
const r = this.reimbursements.findBy('id', id);
|
||||||
handleReimbursementVetoed (id) {
|
console.debug('[kredits] reimbursement', r);
|
||||||
console.debug('[kredits] ReimbursementVetoed received for ', id);
|
|
||||||
const reimbursement = this.reimbursements.findBy('id', id);
|
|
||||||
console.debug('[kredits] reimbursement', this.reimbursement);
|
|
||||||
|
|
||||||
if (reimbursement) {
|
if (r) {
|
||||||
reimbursement.set('vetoed', true);
|
r.set('vetoed', true);
|
||||||
reimbursement.set('pendingTx', null);
|
r.set('pendingTx', null);
|
||||||
|
this.browserCache.reimbursements.setItem(r.id.toString(), r.serialize());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -730,5 +752,5 @@ export default Service.extend({
|
|||||||
this.contributors
|
this.contributors
|
||||||
.findBy('address', to)
|
.findBy('address', to)
|
||||||
.incrementProperty('balance', value);
|
.incrementProperty('balance', value);
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+32
-11
@@ -31,32 +31,53 @@ button, input[type=submit], .button {
|
|||||||
&.small {
|
&.small {
|
||||||
font-size: 0.86rem;
|
font-size: 0.86rem;
|
||||||
padding: 0.2rem 0.8rem;
|
padding: 0.2rem 0.8rem;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 0.4rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.danger:not(:disabled) {
|
&.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);
|
||||||
|
&:hover { background-color: rgba(40, 21, 21, 0.8); }
|
||||||
&:hover {
|
&:focus, &:active, &.active { border-color: $red; }
|
||||||
background-color: rgba(40, 21, 21, 0.8);
|
|
||||||
}
|
|
||||||
&:focus, &:active, &.active {
|
|
||||||
border-color: $red;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.green:not(:disabled) {
|
&.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);
|
||||||
|
&:hover { background-color: rgba(21, 40, 21, 0.8); }
|
||||||
|
&:focus, &:active, &.active { border-color: $green; }
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&.pink:not(:disabled) {
|
||||||
background-color: rgba(21, 40, 21, 0.8);
|
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; }
|
||||||
}
|
}
|
||||||
&:focus, &:active, &.active {
|
|
||||||
border-color: $green;
|
&.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 {
|
&.icon {
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ section#signup {
|
|||||||
p {
|
p {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
|
|
||||||
&.mg-bottom-md {
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.label {
|
&.label {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
|||||||
@@ -62,15 +62,12 @@ main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove after switch to Tailwind CSS
|
||||||
&.text-center {
|
&.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
&.mg-bottom-md {
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.actions {
|
&.actions {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-top: 2rem;
|
padding-top: 2rem;
|
||||||
@@ -177,4 +174,9 @@ main section {
|
|||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Remove after switch to Tailwind CSS
|
||||||
|
.mb-4 { margin-bottom: 1rem; }
|
||||||
|
.mb-8 { margin-bottom: 2rem; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
h4 {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
.amount {
|
||||||
line-height: 2rem;
|
justify-self: end;
|
||||||
|
}
|
||||||
|
|
||||||
&.description {
|
.description {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
|
grid-column-start: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
button {
|
||||||
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ ul.reimbursement-list {
|
|||||||
grid-row-gap: 0.5rem;
|
grid-row-gap: 0.5rem;
|
||||||
padding-top: 1.6rem;
|
padding-top: 1.6rem;
|
||||||
|
|
||||||
|
&.vetoed {
|
||||||
|
text-decoration: line-through;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
.token-amount {
|
.token-amount {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
||||||
@@ -26,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-tag"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"></path><line x1="7" y1="7" x2="7.01" y2="7"></line></svg>
|
||||||
|
After Width: | Height: | Size: 355 B |
@@ -105,6 +105,32 @@
|
|||||||
@showQuickFilter={{this.showQuickFilterConfirmed}} />
|
@showQuickFilter={{this.showQuickFilterConfirmed}} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{{#if this.showFullContributionSync}}
|
||||||
|
<section id="sync-all-contributions">
|
||||||
|
{{#if this.kredits.fetchMissingContributions.isIdle}}
|
||||||
|
<p class="mb-4">
|
||||||
|
There are
|
||||||
|
<strong>{{this.kredits.missingHistoricContributionsCount}}</strong>
|
||||||
|
earlier contributions, which are not currently loaded/displayed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
You can fetch all historic data in one go, and have it stored locally in
|
||||||
|
your browser:
|
||||||
|
<button type="button" {{on "click" (perform this.kredits.fetchMissingContributions)}} class="small">
|
||||||
|
fetch all data
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
{{else}}
|
||||||
|
<p class="mb-4">
|
||||||
|
Syncing data. Please be patient...
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
(You can leave this website anytime and sync missing data when you come back.)
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</section>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="details">
|
<div id="details">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<h2>Complete your contributor profile</h2>
|
<h2>Complete your contributor profile</h2>
|
||||||
</header>
|
</header>
|
||||||
<div class="content text-lg">
|
<div class="content text-lg">
|
||||||
<p class="mg-bottom-md">
|
<p class="mb-8">
|
||||||
Kredits allow you to take part in project governance, and to earn rewards for
|
Kredits allow you to take part in project governance, and to earn rewards for
|
||||||
your contributions. For both, you will need an Ethereum wallet/account.
|
your contributions. For both, you will need an Ethereum wallet/account.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export default function() {
|
||||||
|
return (navigator.languages && navigator.languages.length) ?
|
||||||
|
navigator.languages[0] :
|
||||||
|
navigator.language;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export default function (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
reader.onload = event => resolve(event.target.result)
|
||||||
|
reader.onerror = error => reject(error)
|
||||||
|
reader.readAsText(file)
|
||||||
|
})
|
||||||
|
}
|
||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "kredits-web",
|
"name": "kredits-web",
|
||||||
"version": "2.0.0-beta.1",
|
"version": "2.0.0-beta.3",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "kredits-web",
|
"name": "kredits-web",
|
||||||
"version": "2.0.0-beta.1",
|
"version": "2.0.0-beta.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/eslint-parser": "^7.19.1",
|
"@babel/eslint-parser": "^7.19.1",
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "kredits-web",
|
"name": "kredits-web",
|
||||||
"version": "2.0.0-beta.1",
|
"version": "2.0.0-beta.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Contribution dashboard of the Kosmos project",
|
"description": "Contribution dashboard of the Kosmos project",
|
||||||
"repository": "https://github.com/67P/kredits-web",
|
"repository": "https://github.com/67P/kredits-web",
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
"build-prod": "rm -rf release/* && ember build -prod --output-path release",
|
"build-prod": "rm -rf release/* && ember build -prod --output-path release",
|
||||||
"preversion": "npm test",
|
"preversion": "npm test",
|
||||||
"version": "npm run build-prod && git add release/",
|
"version": "npm run build-prod && git add release/",
|
||||||
"postversion": "git push origin master",
|
|
||||||
"deploy": "git push 5apps master"
|
"deploy": "git push 5apps master"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+159
-85
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3
-3
@@ -8,10 +8,10 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
|
||||||
|
|
||||||
<meta name="kredits-web/config/environment" content="%7B%22modulePrefix%22%3A%22kredits-web%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_DEFAULT_ASYNC_OBSERVERS%22%3Atrue%2C%22_JQUERY_INTEGRATION%22%3Afalse%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%222.0.0-0%2B7c8ca45b%22%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frsk-testnet.kosmos.org%22%2C%22web3RequiredChainId%22%3A31%2C%22web3RequiredNetworkName%22%3A%22RSK%20Testnet%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fgithub%22%2C%22ipfs%22%3A%7B%22host%22%3A%22ipfs.kosmos.org%22%2C%22port%22%3A%225444%22%2C%22protocol%22%3A%22https%22%2C%22gatewayUrl%22%3A%22https%3A%2F%2Fipfs.kosmos.org%2Fipfs%22%7D%2C%22tokens%22%3A%7B%22BTC%22%3A%220x2260fac5e5542a773aa44fbcfedf7c193bc2c599%22%7D%2C%22btcBalanceAPI%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fkredits%2Fonchain_btc_balance%22%2C%22corsProxy%22%3A%22https%3A%2F%2Fcors.5apps.com%2F%3Furi%3D%22%2C%22exportApplicationGlobal%22%3Afalse%7D" />
|
<meta name="kredits-web/config/environment" content="%7B%22modulePrefix%22%3A%22kredits-web%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_DEFAULT_ASYNC_OBSERVERS%22%3Atrue%2C%22_JQUERY_INTEGRATION%22%3Afalse%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%222.0.0-beta.3%2Bd90ddd46%22%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frsk-testnet.kosmos.org%22%2C%22web3RequiredChainId%22%3A31%2C%22web3RequiredNetworkName%22%3A%22RSK%20Testnet%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fgithub%22%2C%22ipfs%22%3A%7B%22host%22%3A%22ipfs.kosmos.org%22%2C%22port%22%3A%225444%22%2C%22protocol%22%3A%22https%22%2C%22gatewayUrl%22%3A%22https%3A%2F%2Fipfs.kosmos.org%2Fipfs%22%7D%2C%22tokens%22%3A%7B%22BTC%22%3A%220x2260fac5e5542a773aa44fbcfedf7c193bc2c599%22%7D%2C%22btcBalanceAPI%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fkredits%2Fonchain_btc_balance%22%2C%22corsProxy%22%3A%22https%3A%2F%2Fcors.5apps.com%2F%3Furi%3D%22%2C%22exportApplicationGlobal%22%3Afalse%7D" />
|
||||||
|
|
||||||
<link integrity="" rel="stylesheet" href="/assets/vendor-ca96b2e19fc9f356e3dbad90c9f3f323.css">
|
<link integrity="" rel="stylesheet" href="/assets/vendor-ca96b2e19fc9f356e3dbad90c9f3f323.css">
|
||||||
<link integrity="" rel="stylesheet" href="/assets/kredits-web-bdbc10028be8d48749a246964068e561.css">
|
<link integrity="" rel="stylesheet" href="/assets/kredits-web-f21602587acec9a1744c244385a83592.css">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<script src="/assets/vendor-4ee536ded971436a83d35253df25f2cb.js" integrity="sha256-yb+pC9iuZ8WcQwk9VuDNhSlWguL7BEABsEOEhBpwUC0= sha512-50LApx5XqeKHu/FMaljzqhAMPgkqSiy2rDhUcViYBcXWBBYmilFirup/iWvLiNCdfr5ct9wk7+tU9iShdSgDww==" ></script>
|
<script src="/assets/vendor-4ee536ded971436a83d35253df25f2cb.js" integrity="sha256-yb+pC9iuZ8WcQwk9VuDNhSlWguL7BEABsEOEhBpwUC0= sha512-50LApx5XqeKHu/FMaljzqhAMPgkqSiy2rDhUcViYBcXWBBYmilFirup/iWvLiNCdfr5ct9wk7+tU9iShdSgDww==" ></script>
|
||||||
<script src="/assets/kredits-web-597bd2c84f295cea39c51678944cb39f.js" integrity="sha256-Ctb96mli0/Rkuej7AJB6wLegTJElHqGYpBOiKkB3spw= sha512-pwHfdUGsokaPO3vAZV4qYG+ljL+5ceExlHARAoyTsd15+yCDCbKsmJzuwLXnagNn/O1IzkDlEN0wed5l3FbuhQ==" ></script>
|
<script src="/assets/kredits-web-89113e4d5c371829e3d1b05e86cbab9b.js" integrity="sha256-aabl6JZt69T2BZIv4yXcRFfmhWCyEhVA2V4g1ZzkZ6s= sha512-aD0s+kWNsXdHJFxIkgncvwNZVhtARosjjKnbLE0w1ihSrvRoptWXV1SgySdZIHKxFgbNmJGA2oQOzhBKIoqvVg==" ></script>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
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');
|
||||||
|
})
|
||||||
|
|
||||||
|
test('#isConfirmed', function(assert) {
|
||||||
|
const kredits = this.owner.lookup('service:kredits');
|
||||||
|
kredits.set('currentBlock', 430000);
|
||||||
|
let component = createComponent('component:confirmed-in');
|
||||||
|
component.args.confirmedAtBlock = 420000;
|
||||||
|
|
||||||
|
assert.ok(component.isConfirmed);
|
||||||
|
})
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user