Reimbursement form fixes and improvements #223
@@ -27,6 +27,10 @@ export default class AddReimbursementComponent extends Component {
|
||||
this.exchangeRates.fetchRates();
|
||||
}
|
||||
|
||||
get contributorId () {
|
||||
return this.recipientId || this.kredits.currentUser?.id;
|
||||
}
|
||||
|
||||
get isValidTotal () {
|
||||
return isValidAmount(this.total);
|
||||
}
|
||||
@@ -70,7 +74,7 @@ export default class AddReimbursementComponent extends Component {
|
||||
}
|
||||
|
||||
updateTotalAmountFromFiat() {
|
||||
let btcAmount = parseFloat(this.total);
|
||||
let btcAmount = 0;
|
||||
|
||||
if (this.exchangeRates.btceur > 0 && this.totalEUR > 0) {
|
||||
btcAmount += (this.totalEUR / this.exchangeRates.btceur);
|
||||
@@ -104,7 +108,7 @@ export default class AddReimbursementComponent extends Component {
|
||||
|
||||
@action
|
||||
updateContributor (event) {
|
||||
this.recipientId = event.target.value;
|
||||
this.recipientId = parseInt(event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -136,12 +140,12 @@ export default class AddReimbursementComponent extends Component {
|
||||
if (!this.kredits.currentUser) { window.alert('You need to connect your RSK account first.'); return false }
|
||||
if (!this.kredits.currentUserIsCore) { window.alert('Only core contributors can submit reimbursements.'); return false }
|
||||
|
||||
const contributor = this.contributors.findBy('id', parseInt(this.recipientId));
|
||||
const contributor = this.contributors.findBy('id', this.contributorId);
|
||||
|
||||
const attributes = {
|
||||
amount: parseInt(parseFloat(this.total) * 100000000), // convert to sats
|
||||
token: config.tokens['BTC'],
|
||||
recipientId: parseInt(this.recipientId),
|
||||
recipientId: this.contributorId,
|
||||
title: `Expenses covered by ${contributor.name}`,
|
||||
description: this.description,
|
||||
url: this.url,
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
<label>
|
||||
<p class="label">Contributor:</p>
|
||||
<p>
|
||||
<select required {{on "change" this.updateContributor}}>
|
||||
<option value="" selected disabled hidden></option>
|
||||
<select id="contributor" required {{on "change" this.updateContributor}}>
|
||||
{{#each this.contributors as |contributor|}}
|
||||
<option value={{contributor.id}} selected={{eq this.contributorId contributor.id}}>{{contributor.name}}</option>
|
||||
{{/each}}
|
||||
@@ -15,6 +14,7 @@
|
||||
<p class="label">Total amount (BTC):</p>
|
||||
<p>
|
||||
<Input @type="text"
|
||||
@name="total-btc"
|
||||
@placeholder="0.0015"
|
||||
@value={{this.total}}
|
||||
@required={{true}}
|
||||
@@ -50,7 +50,9 @@
|
||||
|
||||
<p class="actions">
|
||||
<button {{on "click" this.showExpenseForm}}
|
||||
class="green small" type="button">+ Add another item</button>
|
||||
id="add-another-item" class="green small" type="button">
|
||||
+ Add another item
|
||||
</button>
|
||||
</p>
|
||||
{{else}}
|
||||
<p>No line items yet.</p>
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { alias } from '@ember/object/computed';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class BudgetController extends Controller {
|
||||
@service kredits;
|
||||
@service router;
|
||||
|
||||
@alias('kredits.reimbursementsUnconfirmed') reimbursementsUnconfirmed;
|
||||
@alias('kredits.reimbursementsConfirmed') reimbursementsConfirmed;
|
||||
@alias('kredits.currentUserIsCore') currentUserIsCore;
|
||||
|
||||
@action
|
||||
addReimbursement () {
|
||||
if (!this.kredits.currentUser) {
|
||||
window.alert('You need to connect your RSK account first.');
|
||||
return false;
|
||||
}
|
||||
if (!this.kredits.currentUserIsCore) {
|
||||
window.alert('Only core contributors can submit reimbursements.');
|
||||
return false;
|
||||
}
|
||||
this.router.transitionTo('reimbursements.new');
|
||||
}
|
||||
}
|
||||
|
||||
+10
-18
@@ -1,22 +1,6 @@
|
||||
<main id="budget">
|
||||
|
||||
<div id="aside">
|
||||
<!-- <section id="main-nav"> -->
|
||||
<!-- <header> -->
|
||||
<!-- <h2>Budget</h2> -->
|
||||
<!-- </header> -->
|
||||
<!-- <div class="content"> -->
|
||||
<!-- <ul> -->
|
||||
<!-- <li> -->
|
||||
<!-- <LinkTo @route="budget.expenses">Expenses</LinkTo> -->
|
||||
<!-- </li> -->
|
||||
<!-- <li> -->
|
||||
<!-- <a href="#">Rewards</a> -->
|
||||
<!-- </li> -->
|
||||
<!-- </ul> -->
|
||||
<!-- </div> -->
|
||||
<!-- </section> -->
|
||||
|
||||
<section id="funds">
|
||||
<header>
|
||||
<h2>Community funds</h2>
|
||||
@@ -33,7 +17,11 @@
|
||||
<header class="with-nav">
|
||||
<h2>Proposed Reimbursements</h2>
|
||||
<nav>
|
||||
<LinkTo @route="reimbursements.new" @title="Submit a reimbursement" class="button small green">add</LinkTo>
|
||||
<button type="button" class="button small green"
|
||||
title="Submit a reimbursement"
|
||||
{{on "click" this.addReimbursement}}>
|
||||
add
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="content">
|
||||
@@ -47,7 +35,11 @@
|
||||
<header class="with-nav">
|
||||
<h2>Confirmed Reimbursements</h2>
|
||||
<nav>
|
||||
<LinkTo @route="reimbursements.new" @title="Submit a reimbursement" class="button small green">add</LinkTo>
|
||||
<button type="button" class="button small green"
|
||||
title="Submit a reimbursement"
|
||||
{{on "click" this.addReimbursement}}>
|
||||
add
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="content">
|
||||
|
||||
Generated
+11
-4
@@ -6816,7 +6816,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001332",
|
||||
"version": "1.0.30001599",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz",
|
||||
"integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -6826,9 +6828,12 @@
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
]
|
||||
},
|
||||
"node_modules/capture-exit": {
|
||||
"version": "2.0.0",
|
||||
@@ -29050,7 +29055,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001332",
|
||||
"version": "1.0.30001599",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz",
|
||||
"integrity": "sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==",
|
||||
"dev": true
|
||||
},
|
||||
"capture-exit": {
|
||||
|
||||
@@ -1,13 +1,58 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'ember-qunit';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { click, fillIn, render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
import contributors from '../../../fixtures/contributors';
|
||||
|
||||
module('Integration | Component | add-reimbursement', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it works', async function(assert) {
|
||||
hooks.beforeEach(function() {
|
||||
let kredits = this.owner.lookup('service:kredits');
|
||||
kredits.set('contributors', contributors);
|
||||
kredits.set('currentUser', contributors.findBy('id', 3));
|
||||
});
|
||||
|
||||
test('Contributor select menu', async function(assert) {
|
||||
await render(hbs`<AddReimbursement />`);
|
||||
assert.ok(true);
|
||||
|
||||
assert.equal(this.element.querySelectorAll('select#contributor option').length, contributors.length,
|
||||
'contains correct amount of items');
|
||||
|
||||
assert.equal(this.element.querySelector('select#contributor option:checked').value, "3",
|
||||
'preselects the connected contributor account');
|
||||
});
|
||||
|
||||
test('Adding expense items', async function(assert) {
|
||||
await render(hbs`<AddReimbursement />`);
|
||||
|
||||
assert.dom(this.element).includesText('New expense item');
|
||||
|
||||
await fillIn('form input[name="expense-amount"]', '49');
|
||||
await fillIn('form input[name="expense-title"]', 'Domain kosmos.org (yearly fee)');
|
||||
await click('form#add-expense-item input[type="submit"]');
|
||||
|
||||
assert.equal(this.element.querySelector('input[name="total-eur"]').value, '49',
|
||||
'updates the total EUR amount');
|
||||
assert.equal(this.element.querySelector('input[name="total-usd"]').value, '0',
|
||||
'does not update the total USD amount');
|
||||
assert.equal(this.element.querySelector('input[name="total-btc"]').value, '0.00534493',
|
||||
'updates the total BTC amount');
|
||||
|
||||
assert.dom(this.element).doesNotIncludeText('New expense item');
|
||||
|
||||
await click('button#add-another-item');
|
||||
|
||||
await fillIn('form input[name="expense-amount"]', '29');
|
||||
await fillIn('select[name="expense-currency"]', 'USD');
|
||||
await fillIn('form input[name="expense-title"]', 'Domain kosmos.social (yearly fee)');
|
||||
await click('form#add-expense-item input[type="submit"]');
|
||||
|
||||
assert.equal(this.element.querySelector('input[name="total-usd"]').value, '29',
|
||||
'updates the total USD amount');
|
||||
assert.equal(this.element.querySelector('input[name="total-eur"]').value, '49',
|
||||
'does not update the total EUR amount');
|
||||
assert.equal(this.element.querySelector('input[name="total-btc"]').value, '0.00804268',
|
||||
'updates the total BTC amount');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user