copay/src/pages/tx-details/tx-details.ts

269 lines
9.0 KiB
TypeScript

import { Component } from "@angular/core";
import { TranslateService } from '@ngx-translate/core';
import { Events, NavController, NavParams } from 'ionic-angular';
import * as _ from "lodash";
import { Logger } from '../../providers/logger/logger';
// 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({
selector: 'page-tx-details',
templateUrl: 'tx-details.html'
})
export class TxDetailsPage {
private txId: string;
private config: any;
private blockexplorerUrl: string;
public wallet: any;
public btx: any;
public actionList: 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 addressBookProvider: AddressBookProvider,
private configProvider: ConfigProvider,
private events: Events,
private externalLinkProvider: ExternalLinkProvider,
private logger: Logger,
private navCtrl: NavController,
private navParams: NavParams,
private onGoingProcess: OnGoingProcessProvider,
private popupProvider: PopupProvider,
private profileProvider: ProfileProvider,
private txConfirmNotificationProvider: TxConfirmNotificationProvider,
private txFormatProvider: TxFormatProvider,
private walletProvider: WalletProvider,
private translate: TranslateService
) {
this.config = this.configProvider.get();
this.txId = this.navParams.data.txid;
this.title = this.translate.instant('Transaction');
this.wallet = this.profileProvider.getWallet(this.navParams.data.walletId);
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;
let defaults = this.configProvider.getDefaults();
this.blockexplorerUrl = this.wallet.coin === 'bch'
? defaults.blockExplorerUrl.bch
: defaults.blockExplorerUrl.btc;
this.txConfirmNotificationProvider.checkIfEnabled(this.txId).then((res: any) => {
this.txNotification = {
value: res
};
});
this.updateTx();
}
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 });
});
}
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 = this.translate.instant('Read more in our Wiki');
let okText = this.translate.instant('Open');
let cancelText = this.translate.instant('Go Back');
this.externalLinkProvider.open(url, optIn, title, message, okText, cancelText);
}
private updateMemo(): void {
this.walletProvider.getTxNote(this.wallet, this.btx.txid).then((note: any) => {
if (!note || note.body == "") 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.btx.action != 'moved' || !this.isShared) return;
let actionDescriptions = {
created: this.translate.instant('Proposal Created'),
accept: this.translate.instant('Accepted'),
reject: this.translate.instant('Rejected'),
broadcasted: this.translate.instant('Broadcasted')
};
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, this.walletProvider.useLegacyAddress());
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 = this.translate.instant('Sent Funds');
if (this.btx.action == 'received') this.title = this.translate.instant('Received Funds');
if (this.btx.action == 'moved') this.title = this.translate.instant('Moved Funds');
}
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', this.translate.instant('Transaction not available at this time'));
});
}
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, this.translate.instant('Memo'), opts).then((text: string) => {
if (text == null) 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');
}).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 = this.translate.instant('View Transaction on Insight');
let okText = this.translate.instant('Open Insight');
let cancelText = this.translate.instant('Go Back');
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);
});
}
}