Compare commits

...

3 Commits

7 changed files with 100 additions and 49 deletions
@@ -0,0 +1,31 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import config from 'kredits-web/config/environment';
export default class ReimbursementItemComponent extends Component {
@service kredits;
get ipfsGatewayUrl () {
return config.ipfs.gatewayUrl;
}
get isConfirmed () {
return (this.args.reimbursement.confirmedAt - this.kredits.currentBlock) <= 0;
}
get isUnconfirmed () {
return !this.isConfirmed;
}
get showVetoButton () {
return this.isUnconfirmed && this.kredits.currentUserIsCore;
}
@action
veto (id) {
this.kredits.vetoReimbursement(id).then(transaction => {
console.debug('[controllers:budget] Veto submitted to chain: '+transaction.hash);
});
}
}
@@ -0,0 +1,34 @@
<li data-reimbursement-id={{@reimbursement.id}}
class="{{item-status @reimbursement}}">
<p class="meta">
<span class="recipient">
<UserAvatar @contributor={{@reimbursement.contributor}} />
</span>
<span class="title">
Expenses covered by {{@reimbursement.contributor.name}}
</span>
</p>
<p class="token-amount">
<span class="amount">
{{sats-to-btc @reimbursement.amount}}</span>&#8239;<span class="symbol">BTC</span>
</p>
<ExpenseList @expenses={{@reimbursement.expenses}} />
<div class="meta">
<p class="confirmation-eta">
<ConfirmedIn @confirmedAtBlock={{@reimbursement.confirmedAt}} />
</p>
<p class="actions">
<a href="{{this.ipfsGatewayUrl}}/{{@reimbursement.ipfsHash}}"
class="button small" target="_blank" rel="noopener noreferrer">
Inspect IPFS data
</a>
{{#if this.showVetoButton}}
<button {{on "click" (fn this.veto @reimbursement.id)}}
disabled={{@reimbursement.vetoed}}
class="button small danger" type="button">veto</button>
{{/if}}
</p>
</div>
</li>
@@ -1,23 +1,10 @@
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 { 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; @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);
});
}
} }
+2 -35
View File
@@ -1,38 +1,5 @@
<ul class="item-list spaced reimbursement-list {{if @loading 'loading'}}"> <ul class="item-list spaced reimbursement-list {{if @loading 'loading'}}">
{{#each this.itemsSorted as |reimbursement|}} {{#each this.itemsSorted as |item|}}
<li data-reimbursement-id={{reimbursement.id}} <ReimbursementItem @reimbursement={{item}} />
class="{{item-status reimbursement}}">
<p class="meta">
<span class="recipient">
<UserAvatar @contributor={{reimbursement.contributor}} />
</span>
<span class="title">
Expenses covered by {{reimbursement.contributor.name}}
</span>
</p>
<p class="token-amount">
<span class="amount">
{{sats-to-btc reimbursement.amount}}</span>&#8239;<span class="symbol">BTC</span>
</p>
<ExpenseList @expenses={{reimbursement.expenses}} />
<div class="meta">
<p class="confirmation-eta">
<ConfirmedIn @confirmedAtBlock={{reimbursement.confirmedAt}} />
</p>
<p class="actions">
<a href="{{this.ipfsGatewayUrl}}/{{reimbursement.ipfsHash}}"
class="button small" target="_blank" rel="noopener noreferrer">
Inspect IPFS data
</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>
</li>
{{/each}} {{/each}}
</ul> </ul>
+3
View File
@@ -30,5 +30,8 @@ export default class BudgetRoute extends Route {
} }
schedule('afterRender', this.kredits.fetchMissingReimbursements, schedule('afterRender', this.kredits.fetchMissingReimbursements,
this.kredits.fetchMissingReimbursements.perform); this.kredits.fetchMissingReimbursements.perform);
schedule('afterRender', this.kredits.syncReimbursementEvents,
this.kredits.syncReimbursementEvents.perform);
} }
} }
+27
View File
@@ -780,5 +780,32 @@ export default Service.extend({
this.contributors this.contributors
.findBy('address', to) .findBy('address', to)
.incrementProperty('balance', value); .incrementProperty('balance', value);
},
syncReimbursementEvents: task(function * () {
yield this.fetchEvents(
'Reimbursement', // contract
'ReimbursementAdded', // event
0,
// this.kredits.currentBlock - (2*60*24*14), // from block
this.currentBlock // to block
);
}).group('syncTaskGroup'),
async fetchEvents(contractName, eventName, fromBlock, toBlock) {
const contract = this.kredits[contractName].contract;
const eventFilter = contract.filters[eventName]();
const filterOptions = { fromBlock, toBlock };
console.debug(contract, eventFilter, filterOptions);
contract.queryFilter(eventFilter)
.then(events => {
events.forEach(event => {
console.debug("Event:", event.args.creator, event.args.key, event.args.value);
});
}).catch(e => {
console.error(e);
});
} }
}); });
+3 -1
View File
@@ -62,7 +62,9 @@ module.exports = function(environment) {
} }
}, },
corsProxy: 'https://cors.5apps.com/?uri=' corsProxy: 'https://cors.5apps.com/?uri=',
hideVetoedEntriesAfterBlocks: 5760 // 48 hours
}; };
if (environment === 'development') { if (environment === 'development') {