Introduce budget, reimbursements for expenses #195

Merged
raucao merged 57 commits from feature/expenses into master 2021-06-03 14:23:45 +00:00
5 changed files with 71 additions and 29 deletions
Showing only changes of commit c7b6f9e3e7 - Show all commits
+15 -13
View File
2
@@ -3,6 +3,7 @@ import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import moment from 'moment';
import isValidAmount from 'kredits-web/utils/is-valid-amount';
import { isPresent } from '@ember/utils';
export default class AddExpenseItemComponent extends Component {
// @tracked newExpense = Expense.create();
@@ -69,20 +70,21 @@ export default class AddExpenseItemComponent extends Component {
const [ date ] = dateInput.toISOString().split('T');
const isValid = this.validateForm();
if (!isValid) return false;
if (isValid) {
const expense = {
amount: parseFloat(this.amount),
currency: this.currency,
date: date,
title: this.title,
description: this.description,
url: this.url,
tags: this.tags.split(',').map(t => t.trim())
}
this.args.addExpenseItem(expense);
} else {
return false;
const expense = {
amount: parseFloat(this.amount),
currency: this.currency,
date: date,
title: this.title,
description: isPresent(this.description) ? this.description : undefined,
url: isPresent(this.url) ? this.url : undefined,
}
if (isPresent(this.tags)) {
expense.tags = this.tags.split(',').map(t => t.trim());
}
this.args.addExpenseItem(expense);
}
}
+28 -6
View File
@@ -5,16 +5,17 @@ import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { A } from '@ember/array';
import { scheduleOnce } from '@ember/runloop';
import Reimbursement from 'kredits-web/models/reimbursement';
import isValidAmount from 'kredits-web/utils/is-valid-amount';
import config from 'kredits-web/config/environment';
export default class AddReimbursementComponent extends Component {
@service router;
@service kredits;
@service exchangeRates;
@alias('kredits.contributorsSorted') contributors;
@tracked recipientId = null;
@tracked contributorId = null;
@tracked title = '';
@tracked total = '0';
@tracked expenses = A([]);
@@ -106,9 +107,30 @@ export default class AddReimbursementComponent extends Component {
@action
submit (e) {
e.preventDefault();
// TODO
// amount = parseFloat(this.total)
// token = "WBTC" (or token address)
// title = "Expenses covered by contributor.name"
const contributor = this.contributors.findBy('id', this.contributorId);
const attributes = {
amount: parseInt(parseFloat(this.total) * 100000000), // convert to sats
token: config.tokens['WBTC'],
contributorId: parseInt(this.contributorId),
title: `Expenses covered by ${contributor.name}`,
description: this.description,
url: this.url,
expenses: JSON.parse(JSON.stringify((this.expenses)))
}
this.inProgress = true;
this.kredits.addReimbursement(attributes)
.then((/* reimbursement */) => {
this.router.transitionTo('budget');
})
.catch(e => {
console.error('Could not add reimbursement:', e);
window.alert('Something went wrong. Please check the browser console.')
galfert commented 2020-11-13 15:20:34 +00:00 (Migrated from github.com)
Review

What's the reason for this stringify/parse combo? Probably a good idea to add a code comment for this.

What's the reason for this `stringify`/`parse` combo? Probably a good idea to add a code comment for this.
raucao commented 2020-11-17 11:47:13 +00:00 (Migrated from github.com)
Review

It's to get rid of the EmberObject properties and only retain the pure expense data in the object handed to the wrapper.

It's to get rid of the EmberObject properties and only retain the pure expense data in the object handed to the wrapper.
})
.finally(() => {
this.inProgress = false;
});
}
}
@@ -2,7 +2,7 @@
<label>
<p class="label">Contributor:</p>
<p>
<select required onchange={{action (mut this.recipientId) value="target.value"}}>
<select required onchange={{action (mut this.contributorId) value="target.value"}}>
<option value="" selected disabled hidden></option>
{{#each this.contributors as |contributor|}}
<option value={{contributor.id}} selected={{eq this.contributorId contributor.id}}>{{contributor.name}}</option>
@@ -71,8 +71,13 @@
{{/if}}
<p class="actions">
{{input type="submit" value="Submit" disabled=this.submitButtonDisabled
title="Submit/propose this reimbursement"}}
{{#if this.inProgress}}
{{input type="submit" value="Submitting..." disabled=true
title="Submit/propose this reimbursement"}}
{{else}}
{{input type="submit" value="Submit" disabled=this.submitButtonDisabled
title="Submit/propose this reimbursement"}}
{{/if}}
</p>
{{#if this.expenseFormVisible}}
+3 -7
View File
@@ -1,12 +1,12 @@
import EmberObject, { computed } from '@ember/object';
import { isEmpty, isPresent } from '@ember/utils';
import { isPresent } from '@ember/utils';
import moment from 'moment';
export default EmberObject.extend({
// Contract
id: null,
contributorId: null,
recipientId: null,
token: null,
amount: null,
confirmedAt: null,
@@ -14,7 +14,7 @@ export default EmberObject.extend({
ipfsHash: null,
// contributor model instance
contributor: null,
recipient: null,
// TODO contributor who submitted the reimbursement
// recordedBy: null,
@@ -24,10 +24,6 @@ export default EmberObject.extend({
pendingTx: null,
init () {
this._super(...arguments);
},
iso8601Date: computed('date', 'time', function() {
return this.time ? `${this.date}T${this.time}` : this.date;
}),
+17
View File
2
@@ -577,6 +577,23 @@ export default Service.extend({
return obj;
},
addReimbursement (attributes) {
console.debug('[kredits] add reimbursement', attributes);
return this.kredits.Reimbursement.add(attributes, { gasLimit: 300000 })
.then(data => {
console.debug('[kredits] add reimbursement response', data);
const reimbursement = Reimbursement.create(processReimbursementData(data));
reimbursement.setProperties({
contributor: this.contributors.findBy('id', attributes.contributorId),
pendingTx: data,
confirmedAtBlock: this.currentBlock + 40320
});
this.reimbursements.pushObject(reimbursement);
return reimbursement;
});
},
//
// Contract events
//