Commit c45fd44f authored by Olivia Madrid's avatar Olivia Madrid

(feat): wallet balance tokens and service updates

1 merge request!680WIP: token balance component
Pipeline #101091169 passed with stages
in 46 minutes and 22 seconds
......@@ -15,6 +15,15 @@
*ngIf="tab.value || tab.value === 0"
[ngSwitch]="tab?.unit"
>
<ng-template ngSwitchCase="tokens">
{{ tab.value | token: 18 | number: '1.0-3' }}
</ng-template>
<ng-template ngSwitchCase="eth">
{{ tab.value | token: 18 | number: '1.0-3' }}
</ng-template>
<ng-template ngSwitchCase="btc">
{{ tab.value | token: 18 | number: '1.0-3' }}
</ng-template>
<ng-template ngSwitchCase="number">
{{ tab.value | number }}
</ng-template>
......
......@@ -5,20 +5,16 @@
<div class="m-walletBalance--tokens__balanceTitle">Token Balance</div>
<div class="m-walletBalance--tokens__balanceValWrapper">
<span class="m-walletBalance--tokens__balanceVal--int">{{
totalBalance.int
tokenBalance.int | number
}}</span
>.<span class="m-walletBalance--tokens__balanceVal--frac">{{
totalBalance.frac
}}</span>
><span
class="m-walletBalance--tokens__balanceVal--frac"
*ngIf="tokenBalance.frac"
>.{{ tokenBalance.frac | token: 15 | number: '3.0-0' }}</span
>
</div>
</div>
<a class="m-walletBalance--tokens__buyButtonWrapper" routerLink="/tokens"
><m-shadowboxSubmitButton
[disabled]="!session.getLoggedInUser().rewards"
>Buy tokens</m-shadowboxSubmitButton
></a
>
<ng-container *ngTemplateOutlet="buyTokens"></ng-container>
</div>
<div class="m-walletBalance--tokens__equationSymbol">=</div>
<div class="m-walletBalance--tokens__balanceWrapper--subtotal">
......@@ -29,12 +25,12 @@
</div>
<div class="m-walletBalance--tokens__balanceValWrapper">
<span class="m-walletBalance--tokens__balanceVal--int">{{
offchainBalance.int | token: 18 | number: '1.0-0'
offchainBalance.int | number
}}</span
><span
class="m-walletBalance--tokens__balanceVal--frac"
*ngIf="offchainBalance.frac"
>.{{ offchainBalance.frac }}</span
>.{{ offchainBalance.frac | token: 15 | number: '3.0-0' }}</span
>
tokens
</div>
......@@ -43,20 +39,17 @@
<div class="m-walletBalance--tokens__balanceWrapper--subtotal">
<div class="m-walletBalance--tokens__balanceTitle">
On-Chain<m-tooltip icon="help"
>A short description of On-chain</m-tooltip
>A "short description of On-chain" lol</m-tooltip
>
</div>
<div class="m-walletBalance--tokens__balanceValWrapper">
<span class="m-walletBalance--tokens__balanceVal--int">{{
onchainBalance.int | token: 18 | number: '1.0-0'
onchainBalance.int | number
}}</span
><span
class="m-walletBalance--tokens__balanceVal--frac"
*ngIf="onchainBalance.frac"
>.{{
(onchainBalance.total - onchainBalance.total.toFixed(0)) * 1000
| number: '1.0-0'
}}</span
>.{{ onchainBalance.frac | token: 15 | number: '3.0-0' }}</span
>
tokens
</div>
......@@ -69,11 +62,19 @@
<div class="m-walletBalance--tokens__payout">
Daily estimated payout
<span>{{ estimatedTokenPayout | token: 18 | number: '1.0-3' }}</span>
tokens. Next payout in <span>{{ nextPayout | timediff: true }}</span> (Daily
at 2:00am UTC)
tokens. Next payout in
<span>{{ nextPayout | timediff }}</span> (Daily at 2:00am UTC)
</div>
</ng-container>
<ng-template #buyTokens>
<a class="m-walletBalance--tokens__buyButtonWrapper" routerLink="/tokens"
><m-shadowboxSubmitButton [disabled]="!session.getLoggedInUser().rewards"
>Buy tokens</m-shadowboxSubmitButton
></a
>
</ng-template>
<ng-template #loading>
<h2>...</h2>
</ng-template>
......@@ -49,6 +49,9 @@ m-walletBalance--tokens {
}
.m-walletBalance--tokens__balanceWrapper--subtotal {
.m-walletBalance--tokens__balanceTitle {
min-width: 78px;
}
.m-walletBalance--tokens__balanceValWrapper {
font-size: 13px;
line-height: 18px;
......@@ -102,7 +105,6 @@ m-walletBalance--tokens {
margin-top: 10px;
}
// TODO make equationLeft flex-direction:column at a certain width
@media screen and (max-width: 800px) {
.m-walletBalance--tokens__equationLeft {
flex-direction: column;
......
......@@ -4,9 +4,12 @@ import {
OnDestroy,
ChangeDetectionStrategy,
ChangeDetectorRef,
Input,
} from '@angular/core';
import { Client } from '../../../../services/api/client';
import { Session } from '../../../../services/session';
import { WalletDashboardService } from './../dashboard.service';
import * as BN from 'bn.js';
@Component({
selector: 'm-walletBalance--tokens',
......@@ -14,91 +17,71 @@ import { Session } from '../../../../services/session';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WalletBalanceTokensV2Component implements OnInit, OnDestroy {
@Input() wallet;
constructor(
protected client: Client,
protected cd: ChangeDetectorRef,
protected session: Session
protected session: Session,
protected walletService: WalletDashboardService
) {}
tokenBalance;
offchainBalance;
onchainBalance;
inProgress = true;
protected updateTimer$;
nextPayout;
estimatedTokenPayout;
totalBalance = {
total: 123.345777892347923487,
int: 123,
frac: 345,
};
offchainBalance = {
total: 1.34,
int: 1,
frac: 34,
};
onchainBalance = {
total: 122,
int: 122,
frac: 0,
};
ngOnInit() {
this.loadBalances();
this.loadPayout();
this.tokenBalance = this.formatBalance(this.wallet.tokens.balance);
this.offchainBalance = this.formatBalance(this.wallet.offchain.balance);
this.onchainBalance = this.formatBalance(this.wallet.onchain.balance);
const payouts: any = this.walletService.getTokenPayoutOverview();
console.log('888', payouts);
this.nextPayout = payouts.nextPayout;
this.estimatedTokenPayout = payouts.currentReward;
this.inProgress = false;
this.updateTimer$ = setInterval(this.updateNextPayout.bind(this), 1000);
this.detectChanges();
}
ngOnDestroy() {
clearInterval(this.updateTimer$);
}
async loadBalances() {
try {
const result: any = await this.client.get(
`api/v2/blockchain/contributions/overview`
);
// this.totalBalance = result. ;
updateNextPayout() {
if (this.nextPayout) {
this.nextPayout--;
this.detectChanges();
} catch (e) {
console.error(e);
}
}
async loadPayout() {
try {
const result: any = await this.client.get(
`api/v2/blockchain/contributions/overview`
);
this.nextPayout = result.nextPayout;
this.estimatedTokenPayout = result.currentReward;
formatBalance(balance) {
const formattedBalance = {
total: balance,
int: 0,
frac: null,
};
if (balance <= 0) {
return formattedBalance;
}
this.detectChanges();
} catch (e) {
console.error(e);
if (balance.length > 18) {
formattedBalance.int = balance.slice(0, -18);
}
}
const decimals = balance.slice(-18);
updateNextPayout() {
if (this.nextPayout) {
this.nextPayout--;
this.detectChanges();
console.log('888iszero?', !new BN(decimals).isZero());
if (!new BN(decimals).isZero() || decimals.slice(0, 3) !== '000') {
formattedBalance.frac = decimals;
}
console.log('888', formattedBalance);
return formattedBalance;
}
detectChanges() {
this.cd.markForCheck();
this.cd.detectChanges();
}
//get total balance () {
// return total: #, int: #, dec: #
// }
//get offchain balance
// get onchain balance
// process all 3 balances
// option a: ~~total will truncate??
// option b: var num = (15.46974).toFixed(2) // returns str
}
......@@ -42,7 +42,7 @@ export class WalletChartComponent implements OnInit {
ngOnInit() {
this.activeTimespan = this.timespans[0];
this.data['visualisation'] = this.walletService.getTokenChartData(
this.data['visualisation'] = this.walletService.getTokenChart(
this.activeTimespan
);
}
......@@ -51,6 +51,6 @@ export class WalletChartComponent implements OnInit {
this.activeTimespan = this.timespans.find(
ts => ts.id === $event.timespanId
);
this.data = this.walletService.getTokenChartData(this.activeTimespan);
this.data = this.walletService.getTokenChart(this.activeTimespan);
}
}
......@@ -20,6 +20,7 @@
<div class="m-shadowboxLayout__body">
<m-walletBalance--tokens
[wallet]="wallet"
class="m-shadowboxLayout__body"
*ngIf="activeCurrencyId === 'tokens'"
></m-walletBalance--tokens>
......
......@@ -22,8 +22,8 @@ import { ShadowboxHeaderTab } from '../../../interfaces/dashboard';
export class WalletDashboardComponent implements OnInit, OnDestroy {
menu: Menu = sidebarMenu;
paramsSubscription: Subscription;
wallet;
currencies: ShadowboxHeaderTab[];
activeCurrencyId: string;
activeViewId: string;
......@@ -41,6 +41,8 @@ export class WalletDashboardComponent implements OnInit, OnDestroy {
btc: [{ id: 'settings', label: 'Settings' }],
};
currencies: ShadowboxHeaderTab[] = [];
constructor(
protected walletService: WalletDashboardService,
protected session: Session,
......@@ -57,7 +59,8 @@ export class WalletDashboardComponent implements OnInit, OnDestroy {
}
this.title.setTitle('Wallet');
this.currencies = this.walletService.getCurrencySubtotals();
this.wallet = this.walletService.getWallet();
console.log('888wallet', this.wallet);
this.route.paramMap.subscribe((params: ParamMap) => {
this.activeCurrencyId = params.get('currency');
......@@ -74,6 +77,23 @@ export class WalletDashboardComponent implements OnInit, OnDestroy {
this.detectChanges();
});
this.setCurrencies();
this.detectChanges();
}
setCurrencies() {
const headerCurrencies = ['tokens', 'usd', 'eth', 'btc'];
headerCurrencies.forEach(currency => {
const headerTab: ShadowboxHeaderTab = {
id: currency,
label: this.wallet[currency].label,
unit: this.wallet[currency].unit,
};
if (currency !== 'btc') {
headerTab.value = this.wallet[currency].balance;
}
this.currencies.push(headerTab);
});
}
ngOnDestroy() {
......
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, combineLatest, of } from 'rxjs';
import {
map,
distinctUntilChanged,
switchMap,
tap,
catchError,
} from 'rxjs/operators';
// import { BehaviorSubject, Observable, combineLatest, of } from 'rxjs';
import { MindsHttpClient } from '../../../common/api/client.service';
// import { ShadowboxHeaderTab } from '../../../interfaces/dashboard';
import fakeData from './fake-data';
import {
Response,
UserState,
ShadowboxHeaderTab,
} from '../../../interfaces/dashboard';
import { Web3WalletService } from '../../blockchain/web3-wallet.service';
import { TokenContractService } from '../../blockchain/contracts/token-contract.service';
import * as BN from 'bn.js';
@Injectable()
export class WalletDashboardService {
constructor(private http: MindsHttpClient) {
// this.loadFromRemote();
walletLoaded: boolean = false;
totalTokens = 0;
wallet: any = {
tokens: {
label: 'Tokens',
unit: 'tokens',
balance: 0,
address: null,
},
offchain: {
label: 'Off-chain',
unit: 'tokens',
balance: 0,
address: 'offchain',
},
onchain: {
label: 'On-chain',
unit: 'tokens',
balance: 0,
address: null,
},
receiver: {
label: 'Receiver',
unit: 'tokens',
balance: 0,
address: null,
},
usd: {
label: 'USD',
unit: 'usd',
balance: 0,
address: null,
},
eth: {
label: 'Ether',
unit: 'eth',
balance: 0,
address: null,
},
btc: {
label: 'Bitcoin',
unit: 'btc',
balance: 0,
address: null,
},
};
constructor(
private client: MindsHttpClient,
protected web3Wallet: Web3WalletService,
protected tokenContract: TokenContractService
) {}
getWallet() {
this.getTokenAccounts();
this.getStripeAccount();
this.getEthAccount();
// this.wallet = fakeData.wallet;
this.walletLoaded = true;
return this.wallet;
}
getTokenChartData(activeTimespan) {
return fakeData.visualisation;
async getTokenAccounts() {
await this.loadOffchainAndReceiver();
await this.loadOnchain();
}
getCurrencySubtotals() {
const currencySubtotals: ShadowboxHeaderTab[] = [
{
id: 'tokens',
label: 'Tokens',
unit: 'tokens',
},
{
id: 'usd',
label: 'USD',
unit: 'usd',
},
{
id: 'eth',
label: 'Ether',
unit: 'eth',
},
{
id: 'btc',
label: 'Bitcoin',
},
];
currencySubtotals[0].value = this.getTokenSubtotal();
currencySubtotals[1].value = this.getUsdSubtotal();
currencySubtotals[2].value = this.getEthSubtotal();
return currencySubtotals;
async loadOffchainAndReceiver() {
try {
const response: any = await this.client.get(
`api/v2/blockchain/wallet/balance`
);
if (response && response.addresses) {
this.totalTokens = response.balance;
response.addresses.forEach(address => {
if (address.label === 'Offchain') {
this.wallet.offchain.balance = address.balance;
} else if (address.label === 'Receiver') {
this.wallet.onchain.balance = address.balance;
this.wallet.receiver.balance = address.balance;
this.wallet.receiver.address = address.address;
}
});
} else {
console.error('No data');
}
} catch (e) {
console.error(e);
}
}
private getTokenSubtotal() {
// see WalletBalanceTokensComponent loadLocal(), loadRemote()
return 2167.457;
async loadOnchain() {
try {
const address = await this.web3Wallet.getCurrentWallet();
if (!address) {
return;
}
this.wallet.onchain.address = address;
if (this.wallet.receiver.address === address) {
return; // don't re-add onchain to totalTokens
}
const onchainBalance = await this.tokenContract.balanceOf(address);
this.wallet.onchain.balance = onchainBalance[0].toString();
this.totalTokens = new BN(this.totalTokens).add(onchainBalance[0]);
} catch (e) {
console.log(e);
}
}
private getUsdSubtotal() {
// get from Mark after Stripe update
return 13577;
async getEthAccount() {
const address = await this.web3Wallet.getCurrentWallet();
if (!address) {
return;
}
this.wallet.eth.address = address;
const ethBalance = await this.web3Wallet.getBalance(address);
if (ethBalance) {
this.wallet.eth.balance = ethBalance;
}
}
async getStripeAccount() {
const stripeAccount = <any>(
await this.client.get('api/v2/payments/stripe/connect')
);
if (stripeAccount && stripeAccount.totalBalance) {
this.wallet.usd.value =
stripeAccount.totalBalance.amount + stripeAccount.pendingBalance.amount;
}
return stripeAccount;
}
async getStripeTransactions() {
const { transactions } = <any>(
await this.client.get('api/v2/payments/stripe/transactions')
);
return transactions;
}
async getTokenPayoutOverview(): Promise<any> {
try {
const result: any = await this.client.get(
`api/v2/blockchain/contributions/overview`
);
return result;
} catch (e) {
console.error(e);
}
}
async hasMetamask(): Promise<boolean> {
const isLocal: any = await this.web3Wallet.isLocal();
return Boolean(isLocal);
}
// TODOOJM bucket endpoint needed
getTokenChart(activeTimespan) {
return fakeData.visualisation;
}
private getEthSubtotal() {
// see WalletBalanceTokensComponent loadEth()
return 15.3570957;
// TODOOJM tx/contribution endpoint needed
getTokenTransactionTable() {
return fakeData.token_transactions;
}
}
const fakeData = {
wallet: {
tokens: {
label: 'Tokens',
unit: 'tokens',
balance: '777123456789987654321',
address: null,
},
offchain: {
label: 'Off-chain',
unit: 'tokens',
balance: '222000000000000000000',
address: 'offchain',
},
onchain: {
label: 'On-chain',
unit: 'tokens',
balance: '333123956789987654321',
address: '0x7aA1A2a94c799f0124B6Bf8481D529BDa844498D',
},
receiver: {
label: 'Receiver',
unit: 'tokens',
balance: '000123456789987654321',
address: '0x8aA1A2a94c799f0124B6Bf8481D529BDa844498D',
},
usd: {
label: 'USD',
unit: 'usd',
balance: 2550,
address: null,
},
eth: {
label: 'Ether',
unit: 'eth',
balance: '1111595995595595595595',
address: '0x7aA1A2a94c799f0124B6Bf8481D529BDa844498D',
},
btc: {
label: 'Bitcoin',
unit: 'btc',
balance: 0,
address: null,
},
},
// balances: {
// tokens: '777123456789987654321',
// offchain: '222123456789987654321',
// onchain: '333123456789987654321',
// receiver: '000123456789987654321',
// eth: '111123456789987654321',
// usd: 250,
// },
// addresses: {
// receiver: '0x8aA1A2a94c799f0124B6Bf8481D529BDa844498D',
// onchain: '0x7aA1A2a94c799f0124B6Bf8481D529BDa844498D',
// eth: '0x7aA1A2a94c799f0124B6Bf8481D529BDa844498D',
// },
visualisation: {
type: 'chart',
unit: 'tokens',
......@@ -70,7 +127,6 @@ const fakeData = {
],
},
token_transactions: {
current_total: 25.0,
filters: [
{
id: 'transaction_types',
......
Please register or to comment