Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
251e61891f
|
|||
| 66e1adc719 | |||
|
62388a0488
|
|||
| d7fe860353 | |||
|
14da36b806
|
|||
|
636c79ecc7
|
|||
|
d67bfd59da
|
|||
|
67538a9437
|
|||
|
473522986d
|
|||
|
0dd5f6c5ad
|
|||
|
731e01f2c5
|
|||
|
f02e5572ba
|
|||
|
aad2aaecd1
|
|||
|
7a61d1c569
|
|||
|
697ace35b5
|
|||
|
89ddde28b8
|
|||
|
50b0f2cd7a
|
|||
|
1b78cb4cb4
|
|||
| b32f805cbd | |||
|
3110fd347e
|
|||
|
5612ac4e95
|
|||
|
69ab4913aa
|
|||
|
39e01e4558
|
|||
|
7afc75dbff
|
|||
|
f5f74ae27f
|
|||
|
55f7baecf6
|
@@ -18,7 +18,8 @@ export default class AddExpenseItemComponent extends Component {
|
||||
|
||||
currencies = [
|
||||
{ code: 'EUR' },
|
||||
{ code: 'USD' }
|
||||
{ code: 'USD' },
|
||||
{ code: 'BTC' }
|
||||
];
|
||||
|
||||
get isValidAmount () {
|
||||
|
||||
@@ -5,7 +5,9 @@ import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { A } from '@ember/array';
|
||||
import { scheduleOnce } from '@ember/runloop';
|
||||
import { btcToSats, satsToBtc } from 'kredits-web/utils/btc-conversions';
|
||||
import isValidAmount from 'kredits-web/utils/is-valid-amount';
|
||||
import isoDateIsToday from 'kredits-web/utils/iso-date-is-today';
|
||||
import readFileContent from 'kredits-web/utils/read-file-content';
|
||||
import config from 'kredits-web/config/environment';
|
||||
|
||||
@@ -27,6 +29,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);
|
||||
}
|
||||
@@ -69,22 +75,6 @@ export default class AddReimbursementComponent extends Component {
|
||||
anchor.scrollIntoView();
|
||||
}
|
||||
|
||||
updateTotalAmountFromFiat() {
|
||||
let btcAmount = parseFloat(this.total);
|
||||
|
||||
if (this.exchangeRates.btceur > 0 && this.totalEUR > 0) {
|
||||
btcAmount += (this.totalEUR / this.exchangeRates.btceur);
|
||||
}
|
||||
if (this.exchangeRates.btcusd > 0 && this.totalUSD > 0) {
|
||||
btcAmount += (this.totalUSD / this.exchangeRates.btcusd);
|
||||
}
|
||||
if (this.totalUSD === 0 && this.totalEUR === 0) {
|
||||
btcAmount = 0;
|
||||
}
|
||||
|
||||
this.total = btcAmount.toFixed(8);
|
||||
}
|
||||
|
||||
// TODO use ember-concurrency here
|
||||
// https://github.com/67P/kredits-web/pull/209#discussion_r1064234421
|
||||
@action
|
||||
@@ -104,7 +94,7 @@ export default class AddReimbursementComponent extends Component {
|
||||
|
||||
@action
|
||||
updateContributor (event) {
|
||||
this.recipientId = event.target.value;
|
||||
this.recipientId = parseInt(event.target.value);
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -114,16 +104,38 @@ export default class AddReimbursementComponent extends Component {
|
||||
}
|
||||
|
||||
@action
|
||||
addExpenseItem (expenseItem) {
|
||||
this.expenses.pushObject(expenseItem);
|
||||
this.updateTotalAmountFromFiat();
|
||||
async addExpenseItem (expense) {
|
||||
let totalBTC = parseFloat(this.total);
|
||||
|
||||
if (expense.currency === "BTC") {
|
||||
expense.amountSats = btcToSats(expense.amount);
|
||||
totalBTC += expense.amount;
|
||||
} else {
|
||||
let amountSats;
|
||||
if (isoDateIsToday(expense.date)) {
|
||||
amountSats = btcToSats(expense.amount / this.exchangeRates[expense.currency]);
|
||||
} else {
|
||||
const rates = await this.exchangeRates.fetchHistoricRates(expense.date);
|
||||
amountSats = btcToSats(expense.amount / rates[expense.currency]);
|
||||
}
|
||||
expense.amountSats = amountSats;
|
||||
totalBTC += satsToBtc(amountSats);
|
||||
}
|
||||
console.debug("Adding expense:", expense);
|
||||
|
||||
this.total = totalBTC.toFixed(8);
|
||||
this.expenses.pushObject(expense);
|
||||
this.expenseFormVisible = false;
|
||||
}
|
||||
|
||||
@action
|
||||
removeExpenseItem (expenseItem) {
|
||||
this.expenses.removeObject(expenseItem);
|
||||
this.updateTotalAmountFromFiat();
|
||||
async removeExpenseItem (expense) {
|
||||
let totalBTC = parseFloat(this.total);
|
||||
let amountBTC = satsToBtc(expense.amountSats);
|
||||
totalBTC = totalBTC - amountBTC;
|
||||
this.total = totalBTC.toFixed(8);
|
||||
|
||||
this.expenses.removeObject(expense);
|
||||
|
||||
if (this.expenses.length === 0) {
|
||||
this.expenseFormVisible = true;
|
||||
@@ -136,12 +148,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
|
||||
amount: btcToSats(this.total),
|
||||
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,18 +1,43 @@
|
||||
import Component from '@ember/component';
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
export default class ContributorComponent extends Component {
|
||||
@service router;
|
||||
|
||||
router: service(),
|
||||
@tracked selectedContributorId = null;
|
||||
@tracked showToplistOnly = true;
|
||||
|
||||
selectedContributorId: null,
|
||||
get contributorList () {
|
||||
return this.args.contributorList;
|
||||
}
|
||||
|
||||
actions: {
|
||||
get contributorTop10 () {
|
||||
return this.contributorList ?
|
||||
this.contributorList.slice(0, 10) : [];
|
||||
}
|
||||
|
||||
get contributors () {
|
||||
return this.showToplistOnly ?
|
||||
this.contributorTop10 : this.contributorList;
|
||||
}
|
||||
|
||||
get hiddenContributorsAmount () {
|
||||
return this.contributorList.length - 10;
|
||||
}
|
||||
|
||||
get showAllButtonText () {
|
||||
return `Show ${this.hiddenContributorsAmount} more contributors`;
|
||||
}
|
||||
|
||||
@action
|
||||
openContributorDetails (contributor) {
|
||||
this.router.transitionTo('dashboard.contributors.show', contributor);
|
||||
}
|
||||
|
||||
@action
|
||||
showAllContributors () {
|
||||
this.showToplistOnly = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each @contributorList as |c|}}
|
||||
{{#each this.contributors as |c|}}
|
||||
<tr role="button"
|
||||
onclick={{action "openContributorDetails" c.contributor}}
|
||||
class="{{if (is-current-user c.contributor) "current-user"}} {{if (eq c.contributor.id @selectedContributorId) "selected"}}">
|
||||
@@ -21,5 +21,12 @@
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{#if this.showToplistOnly}}
|
||||
<tr role="button" onclick={{action "showAllContributors"}}>
|
||||
<td colspan="2">
|
||||
{{this.showAllButtonText}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<span class="date">{{fmt-date-localized expense.date}}:</span>
|
||||
<span class="title">{{expense.title}}</span>
|
||||
</h4>
|
||||
<div class="amount">
|
||||
<div class="amount" title="{{fmt-amount-sats-title expense.amountSats}}">
|
||||
{{fmt-fiat-currency expense.amount expense.currency}}
|
||||
</div>
|
||||
<p class="description">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<li data-reimbursement-id={{@reimbursement.id}}
|
||||
class="{{item-status @reimbursement}}"
|
||||
role="button" {{on "click" this.toggleExpenseDetails}}>
|
||||
<p class="meta">
|
||||
class="{{item-status @reimbursement}}">
|
||||
<p class="meta cursor-pointer" role="button"
|
||||
{{on "click" this.toggleExpenseDetails}}>
|
||||
<span class="recipient">
|
||||
<UserAvatar @contributor={{@reimbursement.contributor}} />
|
||||
</span>
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ export default Controller.extend({
|
||||
kreditsToplistSorting: computed('showUnconfirmedKredits', function(){
|
||||
return this.showUnconfirmedKredits ? ['amountTotal:desc'] : ['amountConfirmed:desc'];
|
||||
}),
|
||||
kreditsToplist: sort('kreditsByContributor', 'kreditsToplistSorting'),
|
||||
kreditsToplist: computed('kreditsByContributor', function(){
|
||||
return this.kreditsByContributor.filter(c => c.amountTotal > 0);
|
||||
}),
|
||||
kreditsToplistSorted: sort('kreditsToplist', 'kreditsToplistSorting'),
|
||||
|
||||
showUnconfirmedKredits: true,
|
||||
hideUnconfirmedKredits: not('showUnconfirmedKredits'),
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { helper } from '@ember/component/helper';
|
||||
|
||||
export default helper(function fmtAmountSatsTitle(params) {
|
||||
const amountSats = params[0];
|
||||
|
||||
if (typeof amountSats === 'number' && amountSats > 0) {
|
||||
return `${amountSats} sats`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
@@ -2,10 +2,14 @@ import { helper } from '@ember/component/helper';
|
||||
|
||||
export default helper(function fmtFiatCurrency(params) {
|
||||
const lang = navigator.language || navigator.userLanguage;
|
||||
const value = params[0];
|
||||
const currency = params[1] || 'EUR';
|
||||
|
||||
if (currency === 'BTC') return `BTC ${value}`;
|
||||
|
||||
const formatter = new Intl.NumberFormat(lang, {
|
||||
style: 'currency',
|
||||
currency: params[1] || 'EUR',
|
||||
currencyDisplay: 'code'
|
||||
style: 'currency', currency, currencyDisplay: 'code'
|
||||
})
|
||||
|
||||
return formatter.format(params[0]);
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ export default class CommunityFundsService extends Service {
|
||||
|
||||
// Format and round the approximate USD value
|
||||
const lang = navigator.language || navigator.userLanguage;
|
||||
const balanceUSD = (res.confirmed_balance / 100000000) * this.exchangeRates.btcusd;
|
||||
const balanceUSD = (res.confirmed_balance / 100000000) * this.exchangeRates.USD;
|
||||
res.balanceUSD = Math.round(balanceUSD).toLocaleString(lang);
|
||||
|
||||
this.balances.pushObject({
|
||||
|
||||
@@ -4,6 +4,7 @@ import config from 'kredits-web/config/environment';
|
||||
|
||||
// Need to go through proxy for CORS headers
|
||||
const bitstampBaseUrl = `${config.corsProxy}https://www.bitstamp.net/api/v2`;
|
||||
const kosmosBtcPriceBaseUrl = "https://storage.kosmos.org/kosmos/public/btc-price";
|
||||
|
||||
async function fetchFromBitstamp(currencyPair) {
|
||||
try {
|
||||
@@ -16,11 +17,12 @@ async function fetchFromBitstamp(currencyPair) {
|
||||
}
|
||||
|
||||
export default class ExchangeRatesService extends Service {
|
||||
@tracked btceur = 0;
|
||||
@tracked btcusd = 0;
|
||||
@tracked EUR = 0;
|
||||
@tracked USD = 0;
|
||||
@tracked historic = {};
|
||||
|
||||
get exchangeRatesLoaded () {
|
||||
return (this.btceur !== 0) && (this.btcusd !== 0);
|
||||
return (this.EUR !== 0) && (this.USD !== 0);
|
||||
}
|
||||
|
||||
async fetchRates (source='bitstamp') {
|
||||
@@ -28,8 +30,24 @@ export default class ExchangeRatesService extends Service {
|
||||
|
||||
switch(source) {
|
||||
case 'bitstamp':
|
||||
this.btceur = await fetchFromBitstamp('btceur');
|
||||
this.btcusd = await fetchFromBitstamp('btcusd');
|
||||
this.EUR = await fetchFromBitstamp('btceur');
|
||||
this.USD = await fetchFromBitstamp('btcusd');
|
||||
}
|
||||
}
|
||||
|
||||
async fetchHistoricRates (isoDate) {
|
||||
if (typeof this.historic[isoDate] === "object") {
|
||||
return this.historic[isoDate];
|
||||
} else {
|
||||
const url = `${kosmosBtcPriceBaseUrl}/${isoDate}`;
|
||||
try {
|
||||
const rates = await fetch(url).then(res => res.json());
|
||||
this.historic[isoDate] = rates;
|
||||
return rates;
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
Promise.reject(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,10 @@ a {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
section {
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
|
||||
+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">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{{/if}}
|
||||
</header>
|
||||
<div class="content">
|
||||
<ContributorList @contributorList={{this.kreditsToplist}}
|
||||
<ContributorList @contributorList={{this.kreditsToplistSorted}}
|
||||
@showUnconfirmedKredits={{this.showUnconfirmedKredits}}
|
||||
@selectedContributorId={{this.selectedContributorId}}
|
||||
@loading={{this.kredits.syncContributors.isRunning}} />
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export function floatToBtc(number) {
|
||||
return Number(number.toFixed(8))
|
||||
}
|
||||
|
||||
export function btcToSats(btc) {
|
||||
return Math.round(btc * 100_000_000);
|
||||
}
|
||||
|
||||
export function satsToBtc(sats) {
|
||||
return Math.round((sats / 100_000_000) * 100_000_000) / 100_000_000;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export default function(value) {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
return value === today;
|
||||
}
|
||||
@@ -76,10 +76,10 @@ module.exports = function(environment) {
|
||||
ENV.githubSignupUrl = 'http://localhost:8888/kredits/signup/github';
|
||||
|
||||
ENV.ipfs = {
|
||||
host: 'localhost',
|
||||
host: '10.1.1.198',
|
||||
port: '5001',
|
||||
protocol: 'http',
|
||||
gatewayUrl: 'http://localhost:8080/ipfs'
|
||||
gatewayUrl: 'http://10.1.1.198:9090/ipfs'
|
||||
};
|
||||
|
||||
// Uncomment if you want to use local akkounts
|
||||
|
||||
Generated
+29
-19
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "kredits-web",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "kredits-web",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
@@ -14,7 +14,7 @@
|
||||
"@ember/optional-features": "^1.3.0",
|
||||
"@glimmer/component": "^1.0.0",
|
||||
"@glimmer/tracking": "^1.0.0",
|
||||
"@kredits/contracts": "^7.3.0",
|
||||
"@kredits/contracts": "^7.5.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"ember-auto-import": "^1.12.1",
|
||||
@@ -3062,17 +3062,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@kosmos/schemas": {
|
||||
"version": "3.1.0",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@kosmos/schemas/-/schemas-3.2.0.tgz",
|
||||
"integrity": "sha512-GyWXmWcATcakmEdPOpafdckBgWFqcpSh+tB8nm11VGgtgA94pfoFhKZ3t88WELItKfuP/GFHgMiZmdMB3bSkdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@kredits/contracts": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.3.0.tgz",
|
||||
"integrity": "sha512-7Bo2LFEqGIK39G54AStas1RWouBOp+r7Vcv2vP1uLbY01Usea8SHvd2OjLP6nFgsQa0n/rto9oremHv5IAylrQ==",
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.5.0.tgz",
|
||||
"integrity": "sha512-4Jw6lXn9DfZiTnMtWHwGLS5zhxEJZ2ANfAgcr7tZxqRl7Y0ijpoWvPCA+LkSGqRgKspyiw9+7vSVTtyvAyQbPQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@kosmos/schemas": "^3.1.0",
|
||||
"@kosmos/schemas": "^3.2.0",
|
||||
"ethers": "^5.4.7",
|
||||
"ipfs-http-client": "^56.0.3",
|
||||
"multihashes": "^4.0.3",
|
||||
@@ -6816,7 +6817,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 +6829,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",
|
||||
@@ -26062,16 +26068,18 @@
|
||||
}
|
||||
},
|
||||
"@kosmos/schemas": {
|
||||
"version": "3.1.0",
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@kosmos/schemas/-/schemas-3.2.0.tgz",
|
||||
"integrity": "sha512-GyWXmWcATcakmEdPOpafdckBgWFqcpSh+tB8nm11VGgtgA94pfoFhKZ3t88WELItKfuP/GFHgMiZmdMB3bSkdQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@kredits/contracts": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.3.0.tgz",
|
||||
"integrity": "sha512-7Bo2LFEqGIK39G54AStas1RWouBOp+r7Vcv2vP1uLbY01Usea8SHvd2OjLP6nFgsQa0n/rto9oremHv5IAylrQ==",
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.5.0.tgz",
|
||||
"integrity": "sha512-4Jw6lXn9DfZiTnMtWHwGLS5zhxEJZ2ANfAgcr7tZxqRl7Y0ijpoWvPCA+LkSGqRgKspyiw9+7vSVTtyvAyQbPQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@kosmos/schemas": "^3.1.0",
|
||||
"@kosmos/schemas": "^3.2.0",
|
||||
"ethers": "^5.4.7",
|
||||
"ipfs-http-client": "^56.0.3",
|
||||
"multihashes": "^4.0.3",
|
||||
@@ -29050,7 +29058,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": {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "kredits-web",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"private": true,
|
||||
"description": "Contribution dashboard of the Kosmos project",
|
||||
"repository": "https://github.com/67P/kredits-web",
|
||||
@@ -30,7 +30,7 @@
|
||||
"@ember/optional-features": "^1.3.0",
|
||||
"@glimmer/component": "^1.0.0",
|
||||
"@glimmer/tracking": "^1.0.0",
|
||||
"@kredits/contracts": "^7.3.0",
|
||||
"@kredits/contracts": "^7.5.0",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"ember-auto-import": "^1.12.1",
|
||||
|
||||
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
File diff suppressed because one or more lines are too long
+145
-103
File diff suppressed because one or more lines are too long
+9767
-5870
File diff suppressed because one or more lines are too long
+4
-4
@@ -8,10 +8,10 @@
|
||||
<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.2.0%2B0777c213%22%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frsk-testnet.kosmos.org%22%2C%22web3ChainId%22%3A31%2C%22web3NetworkName%22%3A%22RSK%20Testnet%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%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%22communityFundsAPI%22%3A%7B%22balances%22%3A%7B%22onchain%22%3A%7B%22icon%22%3A%22icon-btc.png%22%2C%22symbol%22%3A%22BTC%22%2C%22description%22%3A%22BTC%20on%20chain%22%2C%22url%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fbtcpay%2Fonchain_btc_balance%22%7D%2C%22lightning%22%3A%7B%22icon%22%3A%22icon-btc-lightning.png%22%2C%22symbol%22%3A%22BTC%22%2C%22description%22%3A%22BTC%20on%20Lightning%20Network%22%2C%22url%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fbtcpay%2Flightning_btc_balance%22%7D%7D%7D%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.3.0%2B66e1adc7%22%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frsk-testnet.kosmos.org%22%2C%22web3ChainId%22%3A31%2C%22web3NetworkName%22%3A%22RSK%20Testnet%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%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%22communityFundsAPI%22%3A%7B%22balances%22%3A%7B%22onchain%22%3A%7B%22icon%22%3A%22icon-btc.png%22%2C%22symbol%22%3A%22BTC%22%2C%22description%22%3A%22BTC%20on%20chain%22%2C%22url%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fbtcpay%2Fonchain_btc_balance%22%7D%2C%22lightning%22%3A%7B%22icon%22%3A%22icon-btc-lightning.png%22%2C%22symbol%22%3A%22BTC%22%2C%22description%22%3A%22BTC%20on%20Lightning%20Network%22%2C%22url%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fbtcpay%2Flightning_btc_balance%22%7D%7D%7D%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/kredits-web-1ce689f6aada92a7d79a1947300931cf.css">
|
||||
<link integrity="" rel="stylesheet" href="/assets/kredits-web-273a3e2096140c611fc6c314653c5122.css">
|
||||
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
<body>
|
||||
|
||||
|
||||
<script src="/assets/vendor-4d87b3e0995c5bb18e46836a089900a4.js" integrity="sha256-5WmWY05Kd+n98Sw0GwuaWodmDVBZ2yVGGtC/2owVfQE= sha512-tiGPA5zvfhnSC9LPTmpvXJmOu30yhsdPqSiZJMPGmE/ez/xJLMaM29vjs4Cs74cDf6fX4uYSGRIu1KfOyGpJYA==" ></script>
|
||||
<script src="/assets/kredits-web-dab5f8c2df81891a0eb6d4d2bbf24a27.js" integrity="sha256-5XKNFa8JPKQWJztf69+Qhuszl/RV5uIYlg8/aPYp0ZY= sha512-0NYDa2a5cJBY6LxPDrEtaqD9YpuDEH7oR17jLvoMzWHBx4WIwerNRc9uadXwg+7UMnua3ysxt8M6i9uaJKRhTA==" ></script>
|
||||
<script src="/assets/vendor-fe68375ecc84328a68fb6e2dc6c2ffd0.js" integrity="sha256-R9zoGCHpj2nktDrCaA5bsKl5UIzBz3pi8OxcjZUcUXg= sha512-KgK1Q5VBzvVFUa5DEMaexc2VLg337DOyWnvp/3HvNzcjSFwCRG/dCn3x6EMuxULl1lY/rCVJ2ZgZN0K5NwZDkA==" ></script>
|
||||
<script src="/assets/kredits-web-ff25bacd2246c053f7629aa0ac30852d.js" integrity="sha256-ZMtyPPTI2FdCZOW2AhZKoSc3V1F8p7eb5paSnXfUUVE= sha512-lbKnfjHisBjgh4AVaSvDb+7zrtfrMd9PhVj3kUW+UREmA9kl3qLaWECHtIfWz4VNPfzQV9xg5P9hQFmcrPe+ig==" ></script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,5 +18,12 @@ module('Integration | Helper | fmt-fiat-currency', function(hooks) {
|
||||
await render(hbs`{{fmt-fiat-currency this.amount 'USD'}}`);
|
||||
assert.ok(this.element.textContent.trim().match(/USD/),
|
||||
'using defined currency when given');
|
||||
|
||||
await render(hbs`{{fmt-fiat-currency 0.00123 'BTC'}}`);
|
||||
assert.ok(this.element.textContent.trim().match(/0.00123/),
|
||||
'allows more decimals');
|
||||
assert.ok(this.element.textContent.trim().match(/BTC/),
|
||||
'using defined currency when given');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -39,12 +39,4 @@ module('Unit | Component | add-reimbursement', function(hooks) {
|
||||
assert.equal(component.totalEUR, '71');
|
||||
assert.equal(component.totalUSD, '59');
|
||||
});
|
||||
|
||||
test('#updateTotalAmountFromFiat', async function(assert) {
|
||||
let component = createComponent('component:add-reimbursement');
|
||||
component.expenses = expenses;
|
||||
await component.exchangeRates.fetchRates();
|
||||
component.updateTotalAmountFromFiat();
|
||||
assert.equal(component.total, '0.01323322', 'converts EUR and USD totals to BTC and rounds to 8 decimals');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
// import { isEmpty, isPresent } from '@ember/utils';
|
||||
// import { module, test } from 'qunit';
|
||||
// import { setupTest } from 'ember-qunit';
|
||||
// import Contributor from 'kredits-web/models/contributor';
|
||||
//
|
||||
// module('Unit | Controller | index', function(hooks) {
|
||||
// setupTest(hooks);
|
||||
//
|
||||
// let addFixtures = function(controller) {
|
||||
// [
|
||||
// { github_username: "neo", github_uid: "318", totalKreditsEarned: 10000 },
|
||||
// { github_username: "morpheus", github_uid: "843", totalKreditsEarned: 15000 },
|
||||
// { github_username: "trinity", github_uid: "123", totalKreditsEarned: 5000 },
|
||||
// { github_username: "mouse", github_uid: "696", totalKreditsEarned: 0 }
|
||||
// ].forEach(fixture => {
|
||||
// controller.get('kredits.contributors').push(Contributor.create(fixture));
|
||||
// });
|
||||
// };
|
||||
//
|
||||
// test('doesn\'t contain people with 0 balance', function(assert) {
|
||||
// let controller = this.owner.lookup('controller:index');
|
||||
// addFixtures(controller);
|
||||
//
|
||||
// let contributorsSorted = controller.get('contributorsSorted');
|
||||
//
|
||||
// assert.ok(isPresent(contributorsSorted.findBy('github_username', 'neo')));
|
||||
// assert.ok(isEmpty(contributorsSorted.findBy('github_username', 'mouse')));
|
||||
// });
|
||||
// });
|
||||
import { isEmpty } from '@ember/utils';
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import Contributor from 'kredits-web/models/contributor';
|
||||
|
||||
module('Unit | Controller | Dashboard', function(hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
let addFixtures = function(controller) {
|
||||
[
|
||||
{ github_username: "neo", github_uid: "318", totalKreditsEarned: 10000 },
|
||||
{ github_username: "morpheus", github_uid: "843", totalKreditsEarned: 15000 },
|
||||
{ github_username: "trinity", github_uid: "123", totalKreditsEarned: 5000 },
|
||||
{ github_username: "mouse", github_uid: "696", totalKreditsEarned: 0 }
|
||||
].forEach(fixture => {
|
||||
controller.get('kredits.contributors').push(Contributor.create(fixture));
|
||||
});
|
||||
};
|
||||
|
||||
test('kreditsToplistSorted()', function(assert) {
|
||||
const controller = this.owner.lookup('controller:dashboard');
|
||||
addFixtures(controller);
|
||||
|
||||
const kreditsToplistSorted = controller.get('kreditsToplistSorted');
|
||||
|
||||
assert.equal(kreditsToplistSorted.length, 3,
|
||||
'contains all contributors with kredits');
|
||||
assert.ok(isEmpty(kreditsToplistSorted.findBy('github_username', 'mouse')),
|
||||
'does not contain contributors with 0 kredits');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ module('Unit | Service | exchange-rates', function(hooks) {
|
||||
test('#fetchRates', async function(assert) {
|
||||
let service = this.owner.lookup('service:exchange-rates');
|
||||
await service.fetchRates();
|
||||
assert.equal(service.btceur, 9167.57, 'fetches BTCEUR from Bitstamp');
|
||||
assert.equal(service.btcusd, 10749.70, 'fetches BTCUSD from Bitstamp');
|
||||
assert.equal(service.EUR, 9167.57, 'fetches BTCEUR from Bitstamp');
|
||||
assert.equal(service.USD, 10749.70, 'fetches BTCUSD from Bitstamp');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { floatToBtc, btcToSats, satsToBtc } from 'kredits-web/utils/btc-conversions';
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
module('Unit | Utility | btc-conversions', function() {
|
||||
test('floatToBtc', function(assert) {
|
||||
assert.equal(floatToBtc(0.001429007), 0.00142901);
|
||||
});
|
||||
|
||||
test('btcToSats', function(assert) {
|
||||
assert.equal(btcToSats(0.001429007), 142901);
|
||||
});
|
||||
|
||||
test('satsToBtc', function(assert) {
|
||||
assert.equal(satsToBtc(142901), 0.00142901);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user