Refactor: tx-details

This commit is contained in:
Gabriel Masclef 2018-01-05 16:30:55 -03:00
parent f09be76687
commit cc47c1fe8a
No known key found for this signature in database
GPG Key ID: DD6D7EAADE12280D
9 changed files with 540 additions and 113 deletions

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="25px" height="25px" viewBox="0 0 25 25" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 40.1 (33804) - http://www.bohemiancoding.com/sketch -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Wallet" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.4---Transaction-(Detail)" transform="translate(-39.000000, -914.000000)">
<g id="Group-2-Copy-6" transform="translate(41.000000, 909.000000)">
<g id="Group" transform="translate(0.000000, 7.000000)">
<path d="M10.5,21 C16.2989899,21 21,16.2989899 21,10.5 C21,4.70101013 16.2989899,0 10.5,0 C4.70101013,0 0,4.70101013 0,10.5 C0,16.2989899 4.70101013,21 10.5,21 Z" id="Oval-2-Copy-3" stroke="#13E5B6" stroke-width="3" fill="#13E5B6"></path>
<path d="M4.8565172,10.7739543 L17.6308211,10.7739543 M9.55650668,16.6261508 L3.82082067,10.8572239 L9.35708555,5.17917933" id="Line" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" transform="translate(10.725821, 10.902665) scale(1, -1) rotate(-135.000000) translate(-10.725821, -10.902665) "></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Card" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 40 40" style="enable-background:new 0 0 40 40;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#647CE8;}
.st1{fill:none;stroke:#B2C1F7;}
</style>
<path id="card" class="st0" d="M11.6,28C10.2,28,9,26.8,9,25.5V14.5c0-1.4,1.2-2.5,2.6-2.5h16.5c1.5,0,2.6,1.1,2.6,2.5v10.9
C30.6,26.8,29.5,28,28,28H11.6z"/>
<path id="stripe-bottom" class="st0" d="M9,18.1h22"/>
<path id="stripe-top" class="st0" d="M9,15.6h22"/>
<path id="bottom-line" class="st1" d="M11.3,23.8h4.3"/>
<path id="top-line" class="st1" d="M11.3,21.3h8.4"/>
</svg>

After

Width:  |  Height:  |  Size: 818 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,6 +1,7 @@
import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
import * as _ from "lodash";
//providers
import { ConfigProvider } from '../../../providers/config/config';
@ -13,7 +14,6 @@ import { PopupProvider } from '../../../providers/popup/popup';
import { FeedbackCompletePage } from '../feedback-complete/feedback-complete';
import { HomePage } from '../../home/home';
import * as _ from "lodash";
@Component({
selector: 'page-send-feedback',

View File

@ -5,68 +5,151 @@
</ion-header>
<ion-content>
<ion-list>
<ion-list *ngIf="btx">
<ion-item>
<div *ngIf="tx.action == 'received'" class="action">
<img src="assets/img/tx-action/icon-received.svg" width="40">
<span translate>Received</span>
<div class="sending-label" *ngIf="btx.confirmations > 0">
<img class="sending-img" src="assets/img/tx-action/icon-sent.svg" width="40" *ngIf="btx.action === 'sent'">
<img class="sending-img" src="assets/img/tx-action/icon-received.svg" width="40" *ngIf="btx.action === 'received'">
<img class="sending-img" src="assets/img/tx-action/icon-moved.svg" width="40" *ngIf="btx.action === 'moved'">
<span *ngIf="btx.action === 'sent'">{{'Sent' | translate}}</span>
<span *ngIf="btx.action === 'received'">{{'Received' | translate}}</span>
<span *ngIf="btx.action === 'moved'">{{'Moved' | translate}}</span>
</div>
<div *ngIf="tx.action == 'sent'" class="action">
<img src="assets/img/tx-action/icon-sent.svg" width="40">
<span translate>Sent</span>
<div class="sending-label" *ngIf="btx.confirmations === 0">
<img class="sending-img" src="assets/img/tx-action/icon-confirming.svg">
<span *ngIf="btx.action == 'sent' || btx.action == 'moved'" translate>Sending</span>
<span *ngIf="btx.action == 'received'" translate>Receiving</span>
</div>
<div *ngIf="tx.action == 'moved'" class="action">
<img src="assets/img/tx-action/icon-moved.svg" width="40">
<span translate>Moved</span>
<div class="amount-label">
<div class="amount">{{btx.amountValueStr}}
<span class="unit">{{btx.amountUnitStr}}</span>
</div>
<div class="alternative" (click)="showRate = !showRate">
<span *ngIf="!showRate">{{btx.alternativeAmountStr}}</span>
<span *ngIf="showRate">
<span *ngIf="!rate">...</span>
<span *ngIf="rate">
{{rate| currency:'':2}} {{alternativeIsoCode}} ({{rateDate | amDateFormat:'MM/DD/YYYY HH:mm a'}})
</span>
</span>
</div>
</div>
</ion-item>
<div class="amount-str">{{tx.amount | satToUnit: wallet.coin}}</div>
<div class="amount-alt-str">{{tx.amount | satToFiat: wallet.coin}}</div>
<ion-item *ngIf="btx.action === 'sent'">
<span class="label" translate>To</span>
<span class="payment-proposal-to">
<img class="icon-bitcoin" *ngIf="!cardId" src="assets/img/icon-bitcoin-small.svg">
<img class="icon-bitcoin" *ngIf="cardId" src="assets/img/icon-card.svg" width="34">
<div copy-to-clipboard="{{ btx.addressTo }}" class="ellipsis pointer">
<span class="contact" *ngIf="!toName">{{ btx.addressTo }}"</span>
<span *ngIf="toName">{{ toName }}</span>
</div>
</span>
</ion-item>
<ion-item>
<ion-avatar item-start>
<img src="assets/img/icon-wallet.svg" class="icon-wallet">
</ion-avatar>
<h2 translate>To</h2>
<p *ngIf="tx.action != 'sent'">{{wallet.name || '...'}}</p>
<p *ngIf="tx.action == 'sent'">{{tx.addressTo || '...'}}</p>
<span class="label" *ngIf="btx.action === 'sent'" translate>From</span>
<span class="label" *ngIf="btx.action !== 'sent'" translate>To</span>
<div class="wallet">
<ion-icon item-start>
<img *ngIf="wallet.network == 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet-testnet.svg"
class="icon-wallet" />
<img *ngIf="wallet.network != 'testnet'" [ngStyle]="{'background-color': wallet.color}" src="assets/img/icon-wallet.svg"
class="icon-wallet" />
</ion-icon>
<div>{{wallet.name}}</div>
</div>
</ion-item>
<ion-item *ngIf="tx.action == 'sent'">
<ion-avatar item-start>
<img src="assets/img/icon-wallet.svg" class="icon-wallet">
</ion-avatar>
<h2 translate>From</h2>
<p>{{wallet.name || '...'}}</p>
</ion-item>
<ion-item>
<ion-label>{{'Date' | translate}}</ion-label>
<ion-item *ngIf="btx.action != 'received' && isShared">
<ion-label translate>Created by</ion-label>
<ion-note item-end>
{{tx.time * 1000 | amDateFormat:'MM/DD/YYYY HH:mm a'}}
{{btx.creatorName}}
</ion-note>
</ion-item>
<button ion-item (click)="addMemo()">
<ion-item *ngIf="btx.ts || btx.createdOn || btx.time">
<ion-label translate>Date</ion-label>
<ion-note item-end>
<time>{{ (btx.ts || btx.createdOn || btx.time) * 1000 | amDateFormat:'MM/DD/YYYY hh:mm a'}}</time>
</ion-note>
</ion-item>
<button ion-item (click)="showCommentPopup()">
<ion-label>{{'Memo' | translate}}</ion-label>
<span>{{tx.message}}</span>
</button>
<button ion-item (click)="addMemo()" *ngIf="tx.action != 'received'">
<ion-label>{{'Fee' | translate}}</ion-label>
<ion-note item-end>
{{tx.fees || '...' | satToUnit: wallet.coin}} - {{tx.fees || '...' | satToFiat: wallet.coin}}
<ion-note item-end *ngIf="btx.note">
{{btx.note.body || btx.message}}
</ion-note>
</button>
<ion-item *ngIf="btx.action != 'received'">
<ion-label>{{'Fee' | translate}}</ion-label>
<span>{{btx.feeStr || '...'}}</span>
<ion-note item-end>
<span>
{{btx.feeFiatStr || '...'}}&nbsp;
<span class="fee-rate" *ngIf="btx.feeRateStr" translate>- {{btx.feeRateStr}} of the transaction</span>
</span>
</ion-note>
</ion-item>
<ion-item class="low-fees" *ngIf="btx.action == 'received' && btx.lowFees">
<img src="assets/img/icon-warning.png" width="20">
<span translate>This transaction could take a long time to confirm or could be dropped due to the low fees set by the sender</span>
</ion-item>
<ion-item class="low-fees" *ngIf="btx.lowAmount">
<img src="assets/img/icon-warning.png" width="20">
<span translate>
This transaction amount is too small compared to current Bitcoin network fees. Spending these funds will need a Bitcoin network
fee cost comparable to the funds itself.
</span>
<a (click)="readMore()" translate>Learn more</a>
</ion-item>
<ion-item>
<ion-label>{{'Confirmations' | translate}}</ion-label>
<ion-note item-end>
{{confirmations || 'Unconfirmed' | translate}}
<span *ngIf="!btx.confirmations || btx.confirmations == 0" translate>
Unconfirmed
</span>
<span *ngIf="btx.confirmations>0 && !btx.safeConfirmed">
{{btx.confirmations}}
</span>
<span *ngIf="btx.safeConfirmed">
{{btx.safeConfirmed}}
</span>
</ion-note>
</ion-item>
<ion-item *ngIf="txsUnsubscribedForNotifications">
<ion-label>{{'Notify me if confirmed' | translate}}</ion-label>
<ion-toggle checked="false" *ngIf="!btx.confirmations || btx.confirmations == 0" [(ngModel)]="txNotification.value" (ionChange)="txConfirmNotificationChange()"></ion-toggle>
</ion-item>
<div *ngIf="actionList && actionList[0]">
<ion-item-divider color="light">{{'Timeline' | translate}}</ion-item-divider>
<div class="timeline-item" [ngClass]="{'action-created' : a.type == 'created' || a.type == 'accept', 'action-rejected' : a.type == 'reject'}"
*ngFor="let a of actionList; let i = index">
<div class="timeline-content">
<div class="timeline-content-icon">
<div class="rejected" *ngIf="a.type === 'reject'">!</div>
<img src="assets/img/icon-broadcasted.svg" *ngIf="a.type === 'broadcasted'">
<div *ngIf="a.type !== 'reject' && a.type !== 'broadcasted'">{{actionList.length - i}}</div>
</div>
<div class="timeline-content-label">
<div class="action">{{a.description}}</div>
<div class="name">{{a.by}}</div>
</div>
<ion-note>
<time>{{ a.time * 1000 | amTimeAgo}}</time>
</ion-note>
</div>
</div>
</div>
</ion-list>
<button ion-button block clear (click)="viewOnBlockchain()" translate>View on blockchain</button>
<button ion-button block clear *ngIf="btx" (click)="viewOnBlockchain()" translate>View on blockchain</button>
</ion-content>

View File

@ -1,21 +1,132 @@
page-tx-details {
.action {
$item-border-color: #EFEFEF;
$item-lateral-padding: 20px;
$v-success-color: #1abb9b;
$v-icon-border-radius: 3px;
$item-label-color: #6C6C6E;
.sending-label {
display: flex;
height: 4rem;
align-items: center;
margin-top: 1.5rem;
margin-bottom: 1.5rem;
.sending-img {
margin-right: 2rem;
}
span {
font-size: 1.8rem;
}
}
img {
margin-right: 15px;
.amount-label {
padding-top: 2rem;
.amount {
font-size: 3.5rem;
.unit {
font-weight: 100;
}
}
.alternative {
margin-top: 1rem;
color: color($global-colors, light-grey);
}
}
.amount-str {
font-size: 30px;
margin-bottom: .5rem;
.payment-proposal-to, .wallet {
display: flex;
align-items: center;
margin-top: 1rem;
.icon-bitcoin {
margin-right: 1rem;
width: 37px;
height: 37px;
}
}
.amount-alt-str {
font-size: 16px;
margin-left: 2px;
margin-bottom: 1.5rem;
.timeline-item {
border: 0;
&:nth-child(2) {
border-top: 1px solid $item-border-color;
}
&:last-child {
border-bottom: 1px solid $item-border-color;
}
padding: 17px $item-lateral-padding;
> * {
padding-right: 0;
}
}
.timeline-content {
display: flex;
align-items: center;
&-icon {
display: flex;
align-items: center;
min-width: 40px;
padding-right: 1rem;
padding-left: 1rem;
margin-right: .5rem;
position: relative;
&::before {
content: '';
background: #e8e8e8;
height: 100px;
width: 1px;
position: absolute;
left: 50%;
-webkit-transform: translateX(-50%) translateY(-100%);
transform: translateX(-50%) translateY(-100%);
top: 0;
}
&::after {
content: '';
background: #e8e8e8;
height: 100px;
width: 1px;
position: absolute;
left: 50%;
-webkit-transform: translateX(-50%) translateY(100%);
transform: translateX(-50%) translateY(100%);
bottom: 0;
}
> div {
border: 3px solid $v-success-color;
border-radius: $v-icon-border-radius;
display: flex;
height: 26px;
width: 26px;
font-size: 13px;
align-items: center;
justify-content: center;
font-weight: 600;
vertical-align: middle;
color: $v-success-color;
z-index: 10;
&.rejected {
background: #E15061;
border-color: #E15061;
color: #FFFFFF;
font-family: "Roboto-Bold";
font-size: 19px;
}
}
}
&-label {
flex-grow: 1;
> .action {
font-size: 16px;
}
> .name {
color: #aaa;
font-size: 14px;
}
}
}
}

View File

@ -1,11 +1,17 @@
import { Component } from "@angular/core";
import { NavParams } from 'ionic-angular';
import { NavController, NavParams, Events } from 'ionic-angular';
import { Logger } from '@nsalaun/ng-logger';
import * as _ from "lodash";
// Providers
import { AddressBookProvider } from '../../providers/address-book/address-book';
import { ConfigProvider } from '../../providers/config/config';
import { ExternalLinkProvider } from '../../providers/external-link/external-link';
import { OnGoingProcessProvider } from "../../providers/on-going-process/on-going-process";
import { PopupProvider } from '../../providers/popup/popup';
import { ProfileProvider } from '../../providers/profile/profile';
import { TxConfirmNotificationProvider } from '../../providers/tx-confirm-notification/tx-confirm-notification';
import { TxFormatProvider } from '../../providers/tx-format/tx-format';
import { WalletProvider } from '../../providers/wallet/wallet';
@Component({
@ -13,49 +19,253 @@ import { WalletProvider } from '../../providers/wallet/wallet';
templateUrl: 'tx-details.html'
})
export class TxDetailsPage {
public title: string;
private txId: string;
private config: any;
private blockexplorerUrl: string;
public wallet: any;
public tx: any;
public confirmations: string;
public btx: any;
public actionList: Array<any>;
public isShared: boolean;
public title: string;
public alternativeIsoCode: string;
public rateDate: any;
public rate: any;
public txNotification: any;
public color: string;
public copayerId: string;
public txsUnsubscribedForNotifications: boolean;
public toName: string;
constructor(
private navParams: NavParams,
private walletProvider: WalletProvider,
private profileProvider: ProfileProvider,
private addressBookProvider: AddressBookProvider,
private configProvider: ConfigProvider,
private events: Events,
private externalLinkProvider: ExternalLinkProvider,
private logger: Logger,
private navCtrl: NavController,
private navParams: NavParams,
private onGoingProcess: OnGoingProcessProvider,
private logger: Logger
private popupProvider: PopupProvider,
private profileProvider: ProfileProvider,
private txConfirmNotificationProvider: TxConfirmNotificationProvider,
private txFormatProvider: TxFormatProvider,
private walletProvider: WalletProvider
) {
this.config = this.configProvider.get();
this.txId = this.navParams.data.txid;
this.title = 'Transaction'; // Todo: gettextCatalog
this.wallet = this.profileProvider.getWallet(this.navParams.data.walletId);
this.tx = {};
this.confirmations = null;
this.color = this.wallet.color;
this.copayerId = this.wallet.credentials.copayerId;
this.isShared = this.wallet.credentials.n > 1;
this.txsUnsubscribedForNotifications = this.config.confirmedTxsNotifications ? !this.config.confirmedTxsNotifications.enabled : true;
if (this.wallet.coin == 'bch') {
this.blockexplorerUrl = 'bch-insight.bitpay.com';
} else {
this.blockexplorerUrl = 'insight.bitpay.com';
}
this.txConfirmNotificationProvider.checkIfEnabled(this.txId).then((res: any) => {
this.txNotification = {
value: res
};
});
this.updateTx();
}
ionViewDidLoad() {
const txid = this.navParams.data.txid;
ionViewWillEnter() {
this.events.subscribe('bwsEvent', (walletId: string, type: string, n: any) => {
if (type == 'NewBlock' && n && n.data && n.data.network == 'livenet') this.updateTxDebounced({ hideLoading: true });
});
}
this.onGoingProcess.set('loadingTxInfo', true);
this.walletProvider.getTx(this.wallet, txid).then((tx) => {
this.onGoingProcess.set('loadingTxInfo', false);
this.tx = tx;
if (this.tx.action == 'sent') this.title = 'Sent Funds';
if (this.tx.action == 'received') this.title = 'Received Funds';
if (this.tx.action == 'moved') this.title = 'Moved Funds';
ionViewWillLeave() {
this.events.unsubscribe('bwsEvent');
}
if (this.tx.safeConfirmed) this.confirmations = this.tx.safeConfirmed;
else if (this.tx.confirmations > 6) this.confirmations = '6+';
}).catch((err) => {
public readMore(): void {
let url = 'https://github.com/bitpay/copay/wiki/COPAY---FAQ#amount-too-low-to-spend';
let optIn = true;
let title = null;
let message = 'Read more in our Wiki'; // Todo: gettextCatalog
let okText = 'Open'; // Todo: gettextCatalog
let cancelText = 'Go Back'; // Todo: gettextCatalog
this.externalLinkProvider.open(url, optIn, title, message, okText, cancelText);
}
private updateMemo(): void {
this.walletProvider.getTxNote(this.wallet, this.btx.txid).then((note: string) => {
if (!note) return;
this.btx.note = note;
}).catch((err: any) => {
this.logger.warn('Could not fetch transaction note: ' + err);
return;
});
}
private initActionList(): void {
this.actionList = [];
if (this.btx.action != 'sent' || !this.isShared) return;
var actionDescriptions = {
created: 'Proposal Created', // Todo: gettextCatalog
accept: 'Accepted', // Todo: gettextCatalog
reject: 'Rejected', // Todo: gettextCatalog
broadcasted: 'Broadcasted' // Todo: gettextCatalog
};
this.actionList.push({
type: 'created',
time: this.btx.createdOn,
description: actionDescriptions.created,
by: this.btx.creatorName
});
_.each(this.btx.actions, (action: any) => {
this.actionList.push({
type: action.type,
time: action.createdOn,
description: actionDescriptions[action.type],
by: action.copayerName
});
});
this.actionList.push({
type: 'broadcasted',
time: this.btx.time,
description: actionDescriptions.broadcasted,
});
setTimeout(() => {
this.actionList.reverse();
}, 10);
}
private updateTxDebounced = _.debounce(this.updateTx, 1000);
private updateTx(opts?: any): void {
opts = opts ? opts : {};
if (!opts.hideLoading) this.onGoingProcess.set('loadingTxInfo', true);
this.walletProvider.getTx(this.wallet, this.txId).then((tx: any) => {
if (!opts.hideLoading) this.onGoingProcess.set('loadingTxInfo', false);
this.btx = this.txFormatProvider.processTx(this.wallet.coin, tx);
let v: string = this.txFormatProvider.formatAlternativeStr(this.wallet.coin, tx.fees);
this.btx.feeFiatStr = v;
this.btx.feeRateStr = (this.btx.fees / (this.btx.amount + this.btx.fees) * 100).toFixed(2) + '%';
if (this.btx.action != 'invalid') {
if (this.btx.action == 'sent') this.title = 'Sent Funds'; // Todo: gettextCatalog
if (this.btx.action == 'received') this.title = 'Received Funds'; // Todo: gettextCatalog
if (this.btx.action == 'moved') this.title = 'Moved Funds'; // Todo: gettextCatalog
}
this.updateMemo();
this.initActionList();
this.getFiatRate();
this.contact();
this.walletProvider.getLowAmount(this.wallet).then((amount: number) => {
this.btx.lowAmount = tx.amount < amount;
}).catch((err: any) => {
this.logger.warn('Error getting low amounts: ' + err);
return;
});
}).catch((err: any) => {
if (!opts.hideLoading) this.onGoingProcess.set('loadingTxInfo', false);
this.logger.warn('Error getting transaction: ' + err);
this.navCtrl.pop();
return this.popupProvider.ionicAlert('Error', 'Transaction not available at this time'); // Todo: gettextCatalog
});
}
public showCommentPopup(): void {
let opts: any = {};
if (this.btx.message) {
opts.defaultText = this.btx.message;
}
if (this.btx.note && this.btx.note.body) opts.defaultText = this.btx.note.body;
this.popupProvider.ionicPrompt(this.wallet.name, 'Memo', opts).then((text: string) => { // Todo: gettextCatalog
if (typeof text == "undefined") return;
this.btx.note = {
body: text
};
this.logger.debug('Saving memo');
let args = {
txid: this.btx.txid,
body: text
};
this.walletProvider.editTxNote(this.wallet, args).then((res: any) => {
this.logger.info('Tx Note edited: ', res);
}).catch((err: any) => {
this.logger.debug('Could not save tx comment ' + err);
});
});
}
public viewOnBlockchain(): void {
let btx = this.btx;
let url = 'https://' + (this.getShortNetworkName() == 'test' ? 'test-' : '') + this.blockexplorerUrl + '/tx/' + btx.txid;
let optIn = true;
let title = null;
let message = 'View Transaction on Insight'; // Todo: gettextCatalog
let okText = 'Open Insight'; // Todo: gettextCatalog
let cancelText = 'Go Back'; // Todo: gettextCatalog
this.externalLinkProvider.open(url, optIn, title, message, okText, cancelText);
}
public getShortNetworkName(): string {
let n: string = this.wallet.credentials.network;
return n.substring(0, 4);
}
private getFiatRate(): void {
this.alternativeIsoCode = this.wallet.status.alternativeIsoCode;
this.wallet.getFiatRate({
code: this.alternativeIsoCode,
ts: this.btx.time * 1000
}, (err, res) => {
if (err) {
this.logger.debug('Could not get historic rate');
return;
}
if (res && res.rate) {
this.rateDate = res.fetchedOn;
this.rate = res.rate;
}
});
}
public txConfirmNotificationChange(): void {
if (this.txNotification.value) {
this.txConfirmNotificationProvider.subscribe(this.wallet, {
txid: this.txId
});
} else {
this.txConfirmNotificationProvider.unsubscribe(this.wallet, this.txId);
}
}
private contact(): void {
let addr = this.btx.addressTo;
this.addressBookProvider.get(addr).then((ab: any) => {
if (ab) {
let name = _.isObject(ab) ? ab.name : ab;
this.toName = name;
} else {
this.toName = addr;
}
}).catch((err: any) => {
this.logger.warn(err);
});
}
addMemo() {
return;
}
viewOnBlockchain() {
const prefix = this.wallet.coin === 'bch' ? 'bch-' : this.wallet.network === 'testnet' ? 'test-' : '';
const url = 'https://' + prefix + 'insight.bitpay.com/tx/' + this.tx.txid;
this.externalLinkProvider.open(url);
}
}

View File

@ -677,10 +677,11 @@ export class WalletProvider {
// Approx utxo amount, from which the uxto is economically redeemable
public getMinFee(wallet: any, nbOutputs?: number): Promise<any> {
return new Promise((resolve, reject) => {
this.feeProvider.getFeeLevels(wallet.coin).then((data) => {
let lowLevelRate = (lodash.find(data.levels[wallet.network], {
level: 'normal',
}).feePerKb / 1000).toFixed(0);
this.feeProvider.getFeeLevels(wallet.coin).then((data: any) => {
let normalLevelRate: any = lodash.find(data.levels[wallet.network], (level: any) => {
return level.level === 'normal';
});
let lowLevelRate: string = (normalLevelRate.feePerKb / 1000).toFixed(0);
let size = this.getEstimatedTxSize(wallet, nbOutputs);
return resolve(size * parseInt(lowLevelRate));
}).catch((err) => {

View File

@ -120,6 +120,14 @@ $global-colors: (
}
}
.gravatar {
min-width: 3rem;
min-height: 3rem;
}
// Utilities
.assertive, a.assertive {
color: color($global-colors, assertive);
}
@ -132,31 +140,13 @@ $global-colors: (
font-weight: 700;
}
.gravatar {
min-width: 3rem;
min-height: 3rem;
.ellipsis {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/*
* Wallet selector
*/
@mixin wallets-list {
height: 3.5rem;
width: 3.5rem;
content: " ";
position: absolute;
top: 6px;
border-radius: $icon-border-radius;
.pointer {
cursor: pointer;
}
.wallet-livenet::before {
@include wallets-list;
background: color($colors, primary) url('../assets/img/icon-wallet.svg') no-repeat 0px 0px;
}
.wallet-testnet::before {
@include wallets-list;
background: color($colors, primary) url('../assets/img/icon-wallet-testnet.svg') no-repeat 0px 0px;
}