Compare commits

...

17 Commits

Author SHA1 Message Date
raucao 251e61891f 2.3.0 2025-02-17 10:35:44 +04:00
Râu Cao 66e1adc719 Merge pull request #227 from 67P/feature/contributor-list_improvements
Contributor list improvements
2025-02-17 06:26:35 +01:00
raucao 62388a0488 Improve test descriptions 2025-02-17 09:10:04 +04:00
Râu Cao d7fe860353 Merge pull request #226 from 67P/feature/currencies
Use historic BTC rate for expense items; allow BTC as currency
2025-02-16 15:50:25 +01:00
raucao 14da36b806 Only show top 10 contributors by default
Don't waste so much screen real estate. Add button to show all to the
end of the toplist.
2025-02-16 14:21:51 +04:00
raucao 636c79ecc7 Port component to native class 2025-02-16 13:53:11 +04:00
raucao d67bfd59da Hide contributors with 0 kredits in toplist 2025-02-16 13:45:48 +04:00
raucao 67538a9437 Use stable/legacy IPFS node in dev
Newer kubo/ipfs daemons don't work well with the old HTTP client.
2025-02-16 12:56:55 +04:00
raucao 473522986d Fix linter error 2025-01-20 16:19:41 -05:00
raucao 0dd5f6c5ad Change cursor to indicate possible click 2025-01-20 16:07:24 -05:00
raucao 731e01f2c5 Only expand item details on header click
It's annoying not being able to copy details otherwise
2025-01-20 16:05:04 -05:00
raucao f02e5572ba Show amountSats as title of expense item amounts 2025-01-20 15:45:36 -05:00
raucao aad2aaecd1 Update contracts, schemas 2025-01-20 15:45:16 -05:00
raucao 7a61d1c569 Add nvmrc config 2025-01-20 12:36:26 -05:00
raucao 697ace35b5 Use historic BTC rate for expense items; allow BTC as currency 2024-12-18 12:34:31 +04:00
raucao 89ddde28b8 Add util for checking if ISO date string is today 2024-12-18 12:32:52 +04:00
raucao 50b0f2cd7a Add BTC conversion utils 2024-12-18 12:30:12 +04:00
31 changed files with 10125 additions and 6070 deletions
+1
View File
@@ -0,0 +1 @@
16
+2 -1
View File
@@ -18,7 +18,8 @@ export default class AddExpenseItemComponent extends Component {
currencies = [ currencies = [
{ code: 'EUR' }, { code: 'EUR' },
{ code: 'USD' } { code: 'USD' },
{ code: 'BTC' }
]; ];
get isValidAmount () { get isValidAmount () {
+31 -23
View File
@@ -5,7 +5,9 @@ import { inject as service } from '@ember/service';
import { action } from '@ember/object'; 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 { btcToSats, satsToBtc } from 'kredits-web/utils/btc-conversions';
import isValidAmount from 'kredits-web/utils/is-valid-amount'; 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 readFileContent from 'kredits-web/utils/read-file-content';
import config from 'kredits-web/config/environment'; import config from 'kredits-web/config/environment';
@@ -73,22 +75,6 @@ export default class AddReimbursementComponent extends Component {
anchor.scrollIntoView(); anchor.scrollIntoView();
} }
updateTotalAmountFromFiat() {
let btcAmount = 0;
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 // TODO use ember-concurrency here
// https://github.com/67P/kredits-web/pull/209#discussion_r1064234421 // https://github.com/67P/kredits-web/pull/209#discussion_r1064234421
@action @action
@@ -118,16 +104,38 @@ export default class AddReimbursementComponent extends Component {
} }
@action @action
addExpenseItem (expenseItem) { async addExpenseItem (expense) {
this.expenses.pushObject(expenseItem); let totalBTC = parseFloat(this.total);
this.updateTotalAmountFromFiat();
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; this.expenseFormVisible = false;
} }
@action @action
removeExpenseItem (expenseItem) { async removeExpenseItem (expense) {
this.expenses.removeObject(expenseItem); let totalBTC = parseFloat(this.total);
this.updateTotalAmountFromFiat(); let amountBTC = satsToBtc(expense.amountSats);
totalBTC = totalBTC - amountBTC;
this.total = totalBTC.toFixed(8);
this.expenses.removeObject(expense);
if (this.expenses.length === 0) { if (this.expenses.length === 0) {
this.expenseFormVisible = true; this.expenseFormVisible = true;
@@ -143,7 +151,7 @@ export default class AddReimbursementComponent extends Component {
const contributor = this.contributors.findBy('id', this.contributorId); const contributor = this.contributors.findBy('id', this.contributorId);
const attributes = { const attributes = {
amount: parseInt(parseFloat(this.total) * 100000000), // convert to sats amount: btcToSats(this.total),
token: config.tokens['BTC'], token: config.tokens['BTC'],
recipientId: this.contributorId, recipientId: this.contributorId,
title: `Expenses covered by ${contributor.name}`, title: `Expenses covered by ${contributor.name}`,
+32 -7
View File
@@ -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 { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default Component.extend({ export default class ContributorComponent extends Component {
tagName: '', @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) { openContributorDetails (contributor) {
this.router.transitionTo('dashboard.contributors.show', contributor); this.router.transitionTo('dashboard.contributors.show', contributor);
} }
@action
showAllContributors () {
this.showToplistOnly = false;
}
} }
});
+8 -1
View File
@@ -2,7 +2,7 @@
<thead> <thead>
</thead> </thead>
<tbody> <tbody>
{{#each @contributorList as |c|}} {{#each this.contributors as |c|}}
<tr role="button" <tr role="button"
onclick={{action "openContributorDetails" c.contributor}} onclick={{action "openContributorDetails" c.contributor}}
class="{{if (is-current-user c.contributor) "current-user"}} {{if (eq c.contributor.id @selectedContributorId) "selected"}}"> class="{{if (is-current-user c.contributor) "current-user"}} {{if (eq c.contributor.id @selectedContributorId) "selected"}}">
@@ -21,5 +21,12 @@
</td> </td>
</tr> </tr>
{{/each}} {{/each}}
{{#if this.showToplistOnly}}
<tr role="button" onclick={{action "showAllContributors"}}>
<td colspan="2">
{{this.showAllButtonText}}
</td>
</tr>
{{/if}}
</tbody> </tbody>
</table> </table>
+1 -1
View File
@@ -5,7 +5,7 @@
<span class="date">{{fmt-date-localized expense.date}}:</span> <span class="date">{{fmt-date-localized expense.date}}:</span>
<span class="title">{{expense.title}}</span> <span class="title">{{expense.title}}</span>
</h4> </h4>
<div class="amount"> <div class="amount" title="{{fmt-amount-sats-title expense.amountSats}}">
{{fmt-fiat-currency expense.amount expense.currency}} {{fmt-fiat-currency expense.amount expense.currency}}
</div> </div>
<p class="description"> <p class="description">
@@ -1,7 +1,7 @@
<li data-reimbursement-id={{@reimbursement.id}} <li data-reimbursement-id={{@reimbursement.id}}
class="{{item-status @reimbursement}}" class="{{item-status @reimbursement}}">
role="button" {{on "click" this.toggleExpenseDetails}}> <p class="meta cursor-pointer" role="button"
<p class="meta"> {{on "click" this.toggleExpenseDetails}}>
<span class="recipient"> <span class="recipient">
<UserAvatar @contributor={{@reimbursement.contributor}} /> <UserAvatar @contributor={{@reimbursement.contributor}} />
</span> </span>
+4 -1
View File
@@ -25,7 +25,10 @@ export default Controller.extend({
kreditsToplistSorting: computed('showUnconfirmedKredits', function(){ kreditsToplistSorting: computed('showUnconfirmedKredits', function(){
return this.showUnconfirmedKredits ? ['amountTotal:desc'] : ['amountConfirmed:desc']; 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, showUnconfirmedKredits: true,
hideUnconfirmedKredits: not('showUnconfirmedKredits'), hideUnconfirmedKredits: not('showUnconfirmedKredits'),
+11
View File
@@ -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 '';
}
});
+7 -3
View File
@@ -2,10 +2,14 @@ import { helper } from '@ember/component/helper';
export default helper(function fmtFiatCurrency(params) { export default helper(function fmtFiatCurrency(params) {
const lang = navigator.language || navigator.userLanguage; 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, { const formatter = new Intl.NumberFormat(lang, {
style: 'currency', style: 'currency', currency, currencyDisplay: 'code'
currency: params[1] || 'EUR',
currencyDisplay: 'code'
}) })
return formatter.format(params[0]); return formatter.format(params[0]);
}); });
+1 -1
View File
@@ -42,7 +42,7 @@ export default class CommunityFundsService extends Service {
// Format and round the approximate USD value // Format and round the approximate USD value
const lang = navigator.language || navigator.userLanguage; 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); res.balanceUSD = Math.round(balanceUSD).toLocaleString(lang);
this.balances.pushObject({ this.balances.pushObject({
+23 -5
View File
@@ -4,6 +4,7 @@ import config from 'kredits-web/config/environment';
// Need to go through proxy for CORS headers // Need to go through proxy for CORS headers
const bitstampBaseUrl = `${config.corsProxy}https://www.bitstamp.net/api/v2`; const bitstampBaseUrl = `${config.corsProxy}https://www.bitstamp.net/api/v2`;
const kosmosBtcPriceBaseUrl = "https://storage.kosmos.org/kosmos/public/btc-price";
async function fetchFromBitstamp(currencyPair) { async function fetchFromBitstamp(currencyPair) {
try { try {
@@ -16,11 +17,12 @@ async function fetchFromBitstamp(currencyPair) {
} }
export default class ExchangeRatesService extends Service { export default class ExchangeRatesService extends Service {
@tracked btceur = 0; @tracked EUR = 0;
@tracked btcusd = 0; @tracked USD = 0;
@tracked historic = {};
get exchangeRatesLoaded () { get exchangeRatesLoaded () {
return (this.btceur !== 0) && (this.btcusd !== 0); return (this.EUR !== 0) && (this.USD !== 0);
} }
async fetchRates (source='bitstamp') { async fetchRates (source='bitstamp') {
@@ -28,8 +30,24 @@ export default class ExchangeRatesService extends Service {
switch(source) { switch(source) {
case 'bitstamp': case 'bitstamp':
this.btceur = await fetchFromBitstamp('btceur'); this.EUR = await fetchFromBitstamp('btceur');
this.btcusd = await fetchFromBitstamp('btcusd'); 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);
}
} }
} }
} }
+4
View File
@@ -45,6 +45,10 @@ a {
color: $primary-color; color: $primary-color;
} }
.cursor-pointer {
cursor: pointer;
}
section { section {
h2 { h2 {
font-size: 1.5rem; font-size: 1.5rem;
+1 -1
View File
@@ -11,7 +11,7 @@
{{/if}} {{/if}}
</header> </header>
<div class="content"> <div class="content">
<ContributorList @contributorList={{this.kreditsToplist}} <ContributorList @contributorList={{this.kreditsToplistSorted}}
@showUnconfirmedKredits={{this.showUnconfirmedKredits}} @showUnconfirmedKredits={{this.showUnconfirmedKredits}}
@selectedContributorId={{this.selectedContributorId}} @selectedContributorId={{this.selectedContributorId}}
@loading={{this.kredits.syncContributors.isRunning}} /> @loading={{this.kredits.syncContributors.isRunning}} />
+11
View File
@@ -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;
}
+4
View File
@@ -0,0 +1,4 @@
export default function(value) {
const today = new Date().toISOString().split('T')[0];
return value === today;
}
+2 -2
View File
@@ -76,10 +76,10 @@ module.exports = function(environment) {
ENV.githubSignupUrl = 'http://localhost:8888/kredits/signup/github'; ENV.githubSignupUrl = 'http://localhost:8888/kredits/signup/github';
ENV.ipfs = { ENV.ipfs = {
host: 'localhost', host: '10.1.1.198',
port: '5001', port: '5001',
protocol: 'http', protocol: 'http',
gatewayUrl: 'http://localhost:8080/ipfs' gatewayUrl: 'http://10.1.1.198:9090/ipfs'
}; };
// Uncomment if you want to use local akkounts // Uncomment if you want to use local akkounts
+18 -15
View File
@@ -1,12 +1,12 @@
{ {
"name": "kredits-web", "name": "kredits-web",
"version": "2.2.1", "version": "2.3.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "kredits-web", "name": "kredits-web",
"version": "2.2.1", "version": "2.3.0",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.19.1", "@babel/eslint-parser": "^7.19.1",
@@ -14,7 +14,7 @@
"@ember/optional-features": "^1.3.0", "@ember/optional-features": "^1.3.0",
"@glimmer/component": "^1.0.0", "@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0", "@glimmer/tracking": "^1.0.0",
"@kredits/contracts": "^7.3.0", "@kredits/contracts": "^7.5.0",
"babel-preset-es2015": "^6.22.0", "babel-preset-es2015": "^6.22.0",
"broccoli-asset-rev": "^3.0.0", "broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.12.1", "ember-auto-import": "^1.12.1",
@@ -3062,17 +3062,18 @@
} }
}, },
"node_modules/@kosmos/schemas": { "node_modules/@kosmos/schemas": {
"version": "3.1.0", "version": "3.2.0",
"dev": true, "resolved": "https://registry.npmjs.org/@kosmos/schemas/-/schemas-3.2.0.tgz",
"license": "MIT" "integrity": "sha512-GyWXmWcATcakmEdPOpafdckBgWFqcpSh+tB8nm11VGgtgA94pfoFhKZ3t88WELItKfuP/GFHgMiZmdMB3bSkdQ==",
"dev": true
}, },
"node_modules/@kredits/contracts": { "node_modules/@kredits/contracts": {
"version": "7.3.0", "version": "7.5.0",
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.3.0.tgz", "resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.5.0.tgz",
"integrity": "sha512-7Bo2LFEqGIK39G54AStas1RWouBOp+r7Vcv2vP1uLbY01Usea8SHvd2OjLP6nFgsQa0n/rto9oremHv5IAylrQ==", "integrity": "sha512-4Jw6lXn9DfZiTnMtWHwGLS5zhxEJZ2ANfAgcr7tZxqRl7Y0ijpoWvPCA+LkSGqRgKspyiw9+7vSVTtyvAyQbPQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@kosmos/schemas": "^3.1.0", "@kosmos/schemas": "^3.2.0",
"ethers": "^5.4.7", "ethers": "^5.4.7",
"ipfs-http-client": "^56.0.3", "ipfs-http-client": "^56.0.3",
"multihashes": "^4.0.3", "multihashes": "^4.0.3",
@@ -26067,16 +26068,18 @@
} }
}, },
"@kosmos/schemas": { "@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 "dev": true
}, },
"@kredits/contracts": { "@kredits/contracts": {
"version": "7.3.0", "version": "7.5.0",
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.3.0.tgz", "resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.5.0.tgz",
"integrity": "sha512-7Bo2LFEqGIK39G54AStas1RWouBOp+r7Vcv2vP1uLbY01Usea8SHvd2OjLP6nFgsQa0n/rto9oremHv5IAylrQ==", "integrity": "sha512-4Jw6lXn9DfZiTnMtWHwGLS5zhxEJZ2ANfAgcr7tZxqRl7Y0ijpoWvPCA+LkSGqRgKspyiw9+7vSVTtyvAyQbPQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@kosmos/schemas": "^3.1.0", "@kosmos/schemas": "^3.2.0",
"ethers": "^5.4.7", "ethers": "^5.4.7",
"ipfs-http-client": "^56.0.3", "ipfs-http-client": "^56.0.3",
"multihashes": "^4.0.3", "multihashes": "^4.0.3",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "kredits-web", "name": "kredits-web",
"version": "2.2.1", "version": "2.3.0",
"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",
@@ -30,7 +30,7 @@
"@ember/optional-features": "^1.3.0", "@ember/optional-features": "^1.3.0",
"@glimmer/component": "^1.0.0", "@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0", "@glimmer/tracking": "^1.0.0",
"@kredits/contracts": "^7.3.0", "@kredits/contracts": "^7.5.0",
"babel-preset-es2015": "^6.22.0", "babel-preset-es2015": "^6.22.0",
"broccoli-asset-rev": "^3.0.0", "broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.12.1", "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
File diff suppressed because one or more lines are too long
+4 -4
View File
@@ -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.2.1%2Bb32f805c%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/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> <body>
<script src="/assets/vendor-4d87b3e0995c5bb18e46836a089900a4.js" integrity="sha256-5WmWY05Kd+n98Sw0GwuaWodmDVBZ2yVGGtC/2owVfQE= sha512-tiGPA5zvfhnSC9LPTmpvXJmOu30yhsdPqSiZJMPGmE/ez/xJLMaM29vjs4Cs74cDf6fX4uYSGRIu1KfOyGpJYA==" ></script> <script src="/assets/vendor-fe68375ecc84328a68fb6e2dc6c2ffd0.js" integrity="sha256-R9zoGCHpj2nktDrCaA5bsKl5UIzBz3pi8OxcjZUcUXg= sha512-KgK1Q5VBzvVFUa5DEMaexc2VLg337DOyWnvp/3HvNzcjSFwCRG/dCn3x6EMuxULl1lY/rCVJ2ZgZN0K5NwZDkA==" ></script>
<script src="/assets/kredits-web-71e8e218f4178df50b78058520257c0d.js" integrity="sha256-pQsThEeIoXS7h22Jg3XPg+5l268k7S63rhGhhHC10o8= sha512-CV9qAyQL3jdXW4+DmTdaGFtGYZ9Lz+f4+8aUnQyK+wOeDkLpUultyhhF2P1+wHS6Hm2vj7n213Ef89YblxDgUA==" ></script> <script src="/assets/kredits-web-ff25bacd2246c053f7629aa0ac30852d.js" integrity="sha256-ZMtyPPTI2FdCZOW2AhZKoSc3V1F8p7eb5paSnXfUUVE= sha512-lbKnfjHisBjgh4AVaSvDb+7zrtfrMd9PhVj3kUW+UREmA9kl3qLaWECHtIfWz4VNPfzQV9xg5P9hQFmcrPe+ig==" ></script>
</body> </body>
@@ -18,5 +18,12 @@ module('Integration | Helper | fmt-fiat-currency', function(hooks) {
await render(hbs`{{fmt-fiat-currency this.amount 'USD'}}`); await render(hbs`{{fmt-fiat-currency this.amount 'USD'}}`);
assert.ok(this.element.textContent.trim().match(/USD/), assert.ok(this.element.textContent.trim().match(/USD/),
'using defined currency when given'); '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.totalEUR, '71');
assert.equal(component.totalUSD, '59'); 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');
});
}); });
+31 -29
View File
@@ -1,29 +1,31 @@
// import { isEmpty, isPresent } from '@ember/utils'; import { isEmpty } from '@ember/utils';
// import { module, test } from 'qunit'; import { module, test } from 'qunit';
// import { setupTest } from 'ember-qunit'; import { setupTest } from 'ember-qunit';
// import Contributor from 'kredits-web/models/contributor'; import Contributor from 'kredits-web/models/contributor';
//
// module('Unit | Controller | index', function(hooks) { module('Unit | Controller | Dashboard', function(hooks) {
// setupTest(hooks); setupTest(hooks);
//
// let addFixtures = function(controller) { let addFixtures = function(controller) {
// [ [
// { github_username: "neo", github_uid: "318", totalKreditsEarned: 10000 }, { github_username: "neo", github_uid: "318", totalKreditsEarned: 10000 },
// { github_username: "morpheus", github_uid: "843", totalKreditsEarned: 15000 }, { github_username: "morpheus", github_uid: "843", totalKreditsEarned: 15000 },
// { github_username: "trinity", github_uid: "123", totalKreditsEarned: 5000 }, { github_username: "trinity", github_uid: "123", totalKreditsEarned: 5000 },
// { github_username: "mouse", github_uid: "696", totalKreditsEarned: 0 } { github_username: "mouse", github_uid: "696", totalKreditsEarned: 0 }
// ].forEach(fixture => { ].forEach(fixture => {
// controller.get('kredits.contributors').push(Contributor.create(fixture)); controller.get('kredits.contributors').push(Contributor.create(fixture));
// }); });
// }; };
//
// test('doesn\'t contain people with 0 balance', function(assert) { test('kreditsToplistSorted()', function(assert) {
// let controller = this.owner.lookup('controller:index'); const controller = this.owner.lookup('controller:dashboard');
// addFixtures(controller); addFixtures(controller);
//
// let contributorsSorted = controller.get('contributorsSorted'); const kreditsToplistSorted = controller.get('kreditsToplistSorted');
//
// assert.ok(isPresent(contributorsSorted.findBy('github_username', 'neo'))); assert.equal(kreditsToplistSorted.length, 3,
// assert.ok(isEmpty(contributorsSorted.findBy('github_username', 'mouse'))); 'contains all contributors with kredits');
// }); assert.ok(isEmpty(kreditsToplistSorted.findBy('github_username', 'mouse')),
// }); 'does not contain contributors with 0 kredits');
});
});
+2 -2
View File
@@ -7,7 +7,7 @@ module('Unit | Service | exchange-rates', function(hooks) {
test('#fetchRates', async function(assert) { test('#fetchRates', async function(assert) {
let service = this.owner.lookup('service:exchange-rates'); let service = this.owner.lookup('service:exchange-rates');
await service.fetchRates(); await service.fetchRates();
assert.equal(service.btceur, 9167.57, 'fetches BTCEUR from Bitstamp'); assert.equal(service.EUR, 9167.57, 'fetches BTCEUR from Bitstamp');
assert.equal(service.btcusd, 10749.70, 'fetches BTCUSD from Bitstamp'); assert.equal(service.USD, 10749.70, 'fetches BTCUSD from Bitstamp');
}); });
}); });
+16
View File
@@ -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);
});
});