Refactored frontend data handling.

This commit is contained in:
Simon Lindh
2019-07-24 23:08:28 +03:00
parent 139b321c71
commit 04d970786c
14 changed files with 320 additions and 195 deletions

View File

@@ -1,4 +1,4 @@
<div class="txBubble" *ngIf="tx">
<div class="txBubble" [ngStyle]="txBubbleStyle" *ngIf="txTrackingEnabled && tx">
<span class="txBubbleText" ngClass="arrow-{{ arrowPosition }}">
<table style="width: 100%;">
<tr>
@@ -6,8 +6,8 @@
<td class="text-right"><a href="https://www.blockstream.info/tx/{{ tx?.txid }}" target="_blank">{{ txIdShort }}</a></td>
</tr>
<tr>
<td class="text-left"><b>Fees:</b></td>
<td class="text-right">{{ tx?.fee }} BTC</td>
<td class="text-left"><b>Fee:</b></td>
<td class="text-right">{{ tx?.fee * 100000000 | number }} sats <span *ngIf="conversions">(<span class="green-color">{{ conversions.USD * tx?.fee | currency:'USD':'symbol':'1.2-2' }}</span>)</span></td>
</tr>
<tr>
<td class="text-left"><b>Fee per vByte:</b></td>

View File

@@ -63,3 +63,7 @@
.txBubble .arrow-top-left.txBubbleText::after {
left: 20%;
}
.green-color {
color: #3bcc49;
}

View File

@@ -1,26 +1,144 @@
import { Component, OnInit, Input, OnChanges } from '@angular/core';
import { ITransaction } from '../blockchain/interfaces';
import { Component, OnInit, OnDestroy, HostListener } from '@angular/core';
import { ITransaction, IProjectedBlock } from '../blockchain/interfaces';
import { Subscription } from 'rxjs';
import { ITxTracking, MemPoolService } from '../services/mem-pool.service';
@Component({
selector: 'app-tx-bubble',
templateUrl: './tx-bubble.component.html',
styleUrls: ['./tx-bubble.component.scss']
})
export class TxBubbleComponent implements OnChanges {
@Input() tx: ITransaction | null = null;
@Input() txTrackingBlockHeight = 0;
@Input() latestBlockHeight = 0;
@Input() arrowPosition: 'top' | 'right' | 'bottom' | 'top-right' | 'top-left' = 'top';
export class TxBubbleComponent implements OnInit, OnDestroy {
tx: ITransaction | null = null;
txTrackingBlockHeight = 0;
latestBlockHeight = 0;
arrowPosition: 'top' | 'right' | 'bottom' | 'top-right' | 'top-left' = 'top';
txTrackingSubscription: Subscription;
projectedBlocksSubscription: Subscription;
blocksSubscription: Subscription;
projectedBlocks: IProjectedBlock[] = [];
txIdShort = '';
confirmations = 0;
conversions: any;
constructor() { }
txBubbleStyle: any = {
'position': 'absolute',
'top': '425px',
'visibility': 'hidden',
};
ngOnChanges() {
if (this.tx) {
this.txIdShort = this.tx.txid.substring(0, 6) + '...' + this.tx.txid.substring(this.tx.txid.length - 6);
txTrackingLoading = false;
txTrackingEnabled = false;
txTrackingTx: ITransaction | null = null;
txShowTxNotFound = false;
txBubbleArrowPosition = 'top';
@HostListener('window:resize', ['$event'])
onResize(event: Event) {
this.moveTxBubbleToPosition();
}
constructor(
private memPoolService: MemPoolService,
) { }
ngOnInit() {
this.txTrackingSubscription = this.memPoolService.txTracking$
.subscribe((response: ITxTracking) => {
this.txTrackingBlockHeight = response.blockHeight;
this.txTrackingEnabled = response.enabled;
if (response.tx) {
this.tx = response.tx;
}
if (this.txTrackingEnabled) {
setTimeout(() => this.moveTxBubbleToPosition());
}
if (this.txShowTxNotFound) {
setTimeout(() => { this.txShowTxNotFound = false; }, 2000);
}
if (this.tx) {
this.txIdShort = this.tx.txid.substring(0, 6) + '...' + this.tx.txid.substring(this.tx.txid.length - 6);
}
if (this.latestBlockHeight) {
this.confirmations = (this.latestBlockHeight - this.txTrackingBlockHeight) + 1;
}
});
this.projectedBlocksSubscription = this.memPoolService.projectedBlocks$
.subscribe((projectedblocks) => this.projectedBlocks = projectedblocks);
this.blocksSubscription = this.memPoolService.blocks$
.subscribe((block) => {
this.latestBlockHeight = block.height;
if (this.txTrackingBlockHeight) {
this.confirmations = (this.latestBlockHeight - this.txTrackingBlockHeight) + 1;
}
});
this.memPoolService.conversions$
.subscribe((conversions) => {
this.conversions = conversions;
});
}
ngOnDestroy() {
this.projectedBlocksSubscription.unsubscribe();
this.txTrackingSubscription.unsubscribe();
this.blocksSubscription.unsubscribe();
}
moveTxBubbleToPosition() {
let element: HTMLElement | null = null;
if (this.txTrackingBlockHeight === 0) {
const index = this.projectedBlocks.findIndex((pB) => pB.hasMytx);
if (index > -1) {
element = document.getElementById('projected-block-' + index);
} else {
return;
}
} else {
element = document.getElementById('bitcoin-block-' + this.txTrackingBlockHeight);
}
this.txBubbleStyle['visibility'] = 'visible';
this.txBubbleStyle['position'] = 'absolute';
if (!element) {
if (window.innerWidth <= 768) {
this.txBubbleArrowPosition = 'bottom';
this.txBubbleStyle['left'] = window.innerWidth / 2 - 50 + 'px';
this.txBubbleStyle['bottom'] = '270px';
this.txBubbleStyle['top'] = 'inherit';
this.txBubbleStyle['position'] = 'fixed';
} else {
this.txBubbleStyle['left'] = window.innerWidth - 220 + 'px';
this.txBubbleArrowPosition = 'right';
this.txBubbleStyle['top'] = '425px';
}
} else {
this.txBubbleArrowPosition = 'top';
const domRect: DOMRect | ClientRect = element.getBoundingClientRect();
this.txBubbleStyle['left'] = domRect.left - 50 + 'px';
this.txBubbleStyle['top'] = domRect.top + 140 + window.scrollY + 'px';
if (domRect.left + 100 > window.innerWidth) {
this.txBubbleStyle['left'] = window.innerWidth - 220 + 'px';
this.txBubbleArrowPosition = 'right';
} else if (domRect.left + 220 > window.innerWidth) {
this.txBubbleStyle['left'] = window.innerWidth - 240 + 'px';
this.txBubbleArrowPosition = 'top-right';
} else {
this.txBubbleStyle['left'] = domRect.left + 15 + 'px';
}
if (domRect.left < 86) {
this.txBubbleArrowPosition = 'top-left';
this.txBubbleStyle['left'] = 125 + 'px';
}
}
this.confirmations = (this.latestBlockHeight - this.txTrackingBlockHeight) + 1;
}
}