Address page with QR code
This commit is contained in:
		
							parent
							
								
									4de8384708
								
							
						
					
					
						commit
						5d61e00ab1
					
				@ -13,4 +13,7 @@ export interface AbstractBitcoinApi {
 | 
			
		||||
  getBlockTransactionsFromIndex(hash: string, index: number): Promise<IBlock>;
 | 
			
		||||
  getBlocks(): Promise<string>;
 | 
			
		||||
  getBlocksFromHeight(height: number): Promise<string>;
 | 
			
		||||
  getAddress(address: string): Promise<IBlock>;
 | 
			
		||||
  getAddressTransactions(address: string): Promise<IBlock>;
 | 
			
		||||
  getAddressTransactionsFromLastSeenTxid(address: string, lastSeenTxid: string): Promise<IBlock>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -84,22 +84,27 @@ class BitcoindApi implements AbstractBitcoinApi {
 | 
			
		||||
  getBlock(hash: string): Promise<IBlock> {
 | 
			
		||||
    throw new Error('Method not implemented.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlocks(): Promise<string> {
 | 
			
		||||
    throw new Error('Method not implemented.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlocksFromHeight(height: number): Promise<string> {
 | 
			
		||||
    throw new Error('Method not implemented.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlockTransactions(hash: string): Promise<IBlock> {
 | 
			
		||||
    throw new Error('Method not implemented.');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlockTransactionsFromIndex(hash: string, index: number): Promise<IBlock> {
 | 
			
		||||
    throw new Error('Method not implemented.');
 | 
			
		||||
  }
 | 
			
		||||
  getAddress(address: string): Promise<IBlock> {
 | 
			
		||||
    throw new Error('Method not implemented.');
 | 
			
		||||
  }
 | 
			
		||||
  getAddressTransactions(address: string): Promise<IBlock> {
 | 
			
		||||
    throw new Error('Method not implemented.');
 | 
			
		||||
  }
 | 
			
		||||
  getAddressTransactionsFromLastSeenTxid(address: string, lastSeenTxid: string): Promise<IBlock> {
 | 
			
		||||
    throw new Error('Method not implemented.');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default BitcoindApi;
 | 
			
		||||
 | 
			
		||||
@ -149,6 +149,39 @@ class EsploraApi implements AbstractBitcoinApi {
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAddress(address: string): Promise<IBlock> {
 | 
			
		||||
    return new Promise(async (resolve, reject) => {
 | 
			
		||||
      try {
 | 
			
		||||
        const blockInfo: AxiosResponse = await this.client.get('/address/' + address);
 | 
			
		||||
        resolve(blockInfo.data);
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        reject(error);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAddressTransactions(address: string): Promise<IBlock> {
 | 
			
		||||
    return new Promise(async (resolve, reject) => {
 | 
			
		||||
      try {
 | 
			
		||||
        const blockInfo: AxiosResponse = await this.client.get('/address/' + address + '/txs');
 | 
			
		||||
        resolve(blockInfo.data);
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        reject(error);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAddressTransactionsFromLastSeenTxid(address: string, lastSeenTxid: string): Promise<IBlock> {
 | 
			
		||||
    return new Promise(async (resolve, reject) => {
 | 
			
		||||
      try {
 | 
			
		||||
        const blockInfo: AxiosResponse = await this.client.get('/address/' + address + '/txs/chain/' + lastSeenTxid);
 | 
			
		||||
        resolve(blockInfo.data);
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        reject(error);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default EsploraApi;
 | 
			
		||||
 | 
			
		||||
@ -272,6 +272,9 @@ class MempoolSpace {
 | 
			
		||||
        .get(config.API_ENDPOINT + 'explorer/block/:hash', routes.getBlock)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'explorer/block/:hash/tx', routes.getBlockTransactions)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'explorer/block/:hash/tx/:index', routes.getBlockTransactionsFromIndex)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'explorer/address/:address', routes.getAddress)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'explorer/address/:address/tx', routes.getAddressTransactions)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'explorer/address/:address/tx/chain/:txid', routes.getAddressTransactionsFromTxid)
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -126,6 +126,33 @@ class Routes {
 | 
			
		||||
      res.status(500).send(e.message);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async getAddress(req, res) {
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await bitcoinApi.getAddress(req.params.address);
 | 
			
		||||
      res.send(result);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      res.status(500).send(e.message);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async getAddressTransactions(req, res) {
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await bitcoinApi.getAddressTransactions(req.params.address);
 | 
			
		||||
      res.send(result);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      res.status(500).send(e.message);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async getAddressTransactionsFromTxid(req, res) {
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await bitcoinApi.getAddressTransactionsFromLastSeenTxid(req.params.address, req.params.txid);
 | 
			
		||||
      res.send(result);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      res.status(500).send(e.message);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default new Routes();
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@
 | 
			
		||||
    "@angular/platform-browser-dynamic": "^8.2.11",
 | 
			
		||||
    "@angular/router": "^8.2.11",
 | 
			
		||||
    "@ng-bootstrap/ng-bootstrap": "^5.1.1",
 | 
			
		||||
    "angularx-qrcode": "^1.7.0-beta.5",
 | 
			
		||||
    "bootstrap": "^4.3.1",
 | 
			
		||||
    "chartist": "^0.11.2",
 | 
			
		||||
    "core-js": "^3.3.3",
 | 
			
		||||
 | 
			
		||||
@ -1 +1,81 @@
 | 
			
		||||
<p>address works!</p>
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <h1>Address</h1>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
  
 | 
			
		||||
    <ng-template [ngIf]="!isLoadingAddress && !error">
 | 
			
		||||
 | 
			
		||||
      <table class="table table-borderless">
 | 
			
		||||
        <thead>
 | 
			
		||||
          <tr class="header-bg">
 | 
			
		||||
            <th>
 | 
			
		||||
              <a [routerLink]="['/explorer/address/', address.address]">{{ address.address }}</a>
 | 
			
		||||
            </th>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
      </table>
 | 
			
		||||
 | 
			
		||||
      <br>
 | 
			
		||||
  
 | 
			
		||||
      <div class="row">
 | 
			
		||||
        <div class="col">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Number of transactions</td>
 | 
			
		||||
                <td>{{ address.chain_stats.tx_count + address.mempool_stats.tx_count }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Total received</td>
 | 
			
		||||
                <td>{{ (address.chain_stats.funded_txo_sum + address.mempool_stats.funded_txo_sum) / 100000000 | number: '1.2-2' }} BTC</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Total sent</td>
 | 
			
		||||
                <td>{{ (address.chain_stats.spent_txo_sum + address.mempool_stats.spent_txo_sum) / 100000000 | number: '1.2-2' }} BTC</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col text-center">
 | 
			
		||||
          <div class="qr-wrapper">
 | 
			
		||||
            <qrcode id="qrCode" [qrdata]="address.address" [size]="128" [level]="'M'"></qrcode>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <br>
 | 
			
		||||
 | 
			
		||||
      <h2>{{ transactions?.length || '?' }} of {{ address.chain_stats.tx_count + address.mempool_stats.tx_count }} transactions</h2>
 | 
			
		||||
 | 
			
		||||
      <br>
 | 
			
		||||
 | 
			
		||||
      <app-transactions-list [transactions]="transactions" [showConfirmations]="true"></app-transactions-list>
 | 
			
		||||
 | 
			
		||||
      <div class="text-center">
 | 
			
		||||
        <ng-template [ngIf]="isLoadingTransactions">
 | 
			
		||||
          <div class="spinner-border text-light"></div>
 | 
			
		||||
          <br><br>
 | 
			
		||||
        </ng-template>
 | 
			
		||||
        <button *ngIf="transactions?.length && transactions?.length !== (address.chain_stats.tx_count + address.mempool_stats.tx_count)" type="button" class="btn btn-primary" (click)="loadMore()">Load more</button>
 | 
			
		||||
      </div>
 | 
			
		||||
  
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 | 
			
		||||
    <ng-template [ngIf]="isLoadingAddress && !error">
 | 
			
		||||
      <div class="text-center">
 | 
			
		||||
        <div class="spinner-border text-light"></div>
 | 
			
		||||
        <br><br>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 | 
			
		||||
    <ng-template [ngIf]="error">
 | 
			
		||||
      <div class="text-center">
 | 
			
		||||
        Error loading address data.
 | 
			
		||||
        <br>
 | 
			
		||||
        <i>{{ error.message }}</i>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
  
 | 
			
		||||
  <br>
 | 
			
		||||
@ -0,0 +1,14 @@
 | 
			
		||||
.header-bg {
 | 
			
		||||
  background-color:#653b9c;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
.header-bg a {
 | 
			
		||||
  color: #FFF;
 | 
			
		||||
  text-decoration: underline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.qr-wrapper {
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,7 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
 | 
			
		||||
import { ActivatedRoute, ParamMap } from '@angular/router';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { switchMap } from 'rxjs/operators';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-address',
 | 
			
		||||
@ -6,10 +9,54 @@ import { Component, OnInit } from '@angular/core';
 | 
			
		||||
  styleUrls: ['./address.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class AddressComponent implements OnInit {
 | 
			
		||||
  address: any;
 | 
			
		||||
  isLoadingAddress = true;
 | 
			
		||||
  latestBlockHeight: number;
 | 
			
		||||
  transactions: any[];
 | 
			
		||||
  isLoadingTransactions = true;
 | 
			
		||||
  error: any;
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
  constructor(
 | 
			
		||||
    private route: ActivatedRoute,
 | 
			
		||||
    private apiService: ApiService,
 | 
			
		||||
    private ref: ChangeDetectorRef,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.route.paramMap.pipe(
 | 
			
		||||
      switchMap((params: ParamMap) => {
 | 
			
		||||
        this.error = undefined;
 | 
			
		||||
        this.isLoadingAddress = true;
 | 
			
		||||
        const address: string = params.get('id') || '';
 | 
			
		||||
        return this.apiService.getAddress$(address);
 | 
			
		||||
      })
 | 
			
		||||
    )
 | 
			
		||||
    .subscribe((address) => {
 | 
			
		||||
      this.address = address;
 | 
			
		||||
      this.isLoadingAddress = false;
 | 
			
		||||
      this.getAddressTransactions(address.address);
 | 
			
		||||
      this.ref.markForCheck();
 | 
			
		||||
    },
 | 
			
		||||
    (error) => {
 | 
			
		||||
      this.error = error;
 | 
			
		||||
      this.isLoadingAddress = false;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAddressTransactions(address: string) {
 | 
			
		||||
    this.apiService.getAddressTransactions$(address)
 | 
			
		||||
      .subscribe((transactions: any) => {
 | 
			
		||||
        this.transactions = transactions;
 | 
			
		||||
        this.isLoadingTransactions = false;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  loadMore() {
 | 
			
		||||
    this.isLoadingTransactions = true;
 | 
			
		||||
    this.apiService.getAddressTransactionsFromHash$(this.address.id, this.transactions[this.transactions.length - 1].txid)
 | 
			
		||||
      .subscribe((transactions) => {
 | 
			
		||||
        this.transactions = this.transactions.concat(transactions);
 | 
			
		||||
        this.isLoadingTransactions = false;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <h1>Block <ng-template [ngIf]="!isLoadingBlock"><a [routerLink]="['/explorer/block/', block.id]">#{{ block.height }}</a></ng-template></h1>
 | 
			
		||||
  
 | 
			
		||||
    <ng-template [ngIf]="!isLoadingBlock" [ngIfElse]="loadingBlock">
 | 
			
		||||
    <ng-template [ngIf]="!isLoadingBlock && !error">
 | 
			
		||||
 | 
			
		||||
      <br>
 | 
			
		||||
  
 | 
			
		||||
@ -27,7 +27,7 @@
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Status</td>
 | 
			
		||||
                <td>{{ latestBlockHeight - block.height + 1 }} confirmations</td>
 | 
			
		||||
                <td>{{ (latestBlockHeight - block.height + 1) }} confirmation{{ (latestBlockHeight - block.height + 1) === 1 ? '' : 's' }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
@ -61,17 +61,26 @@
 | 
			
		||||
          <div class="spinner-border text-light"></div>
 | 
			
		||||
          <br><br>
 | 
			
		||||
        </ng-template>
 | 
			
		||||
        <button  *ngIf="transactions?.length" type="button" class="btn btn-primary" (click)="loadMore()">Load more</button>
 | 
			
		||||
        <button *ngIf="transactions?.length && transactions?.length !== block.tx_count" type="button" class="btn btn-primary" (click)="loadMore()">Load more</button>
 | 
			
		||||
      </div>
 | 
			
		||||
  
 | 
			
		||||
    </ng-template>
 | 
			
		||||
    <ng-template #loadingBlock>
 | 
			
		||||
 | 
			
		||||
    <ng-template [ngIf]="isLoadingBlock && !error">
 | 
			
		||||
      <div class="text-center">
 | 
			
		||||
        <div class="spinner-border text-light"></div>
 | 
			
		||||
        <br><br>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 | 
			
		||||
    <ng-template [ngIf]="error">
 | 
			
		||||
      <div class="text-center">
 | 
			
		||||
        Error loading block data.
 | 
			
		||||
        <br>
 | 
			
		||||
        <i>{{ error.message }}</i>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
  
 | 
			
		||||
  <br>
 | 
			
		||||
@ -16,6 +16,7 @@ export class BlockComponent implements OnInit {
 | 
			
		||||
  latestBlockHeight: number;
 | 
			
		||||
  transactions: any[];
 | 
			
		||||
  isLoadingTransactions = true;
 | 
			
		||||
  error: any;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private route: ActivatedRoute,
 | 
			
		||||
@ -27,16 +28,21 @@ export class BlockComponent implements OnInit {
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.route.paramMap.pipe(
 | 
			
		||||
      switchMap((params: ParamMap) => {
 | 
			
		||||
        this.error = undefined;
 | 
			
		||||
        this.isLoadingBlock = true;
 | 
			
		||||
        const blockHash: string = params.get('id') || '';
 | 
			
		||||
        this.getBlockTransactions(blockHash);
 | 
			
		||||
        return this.apiService.getBlock$(blockHash);
 | 
			
		||||
      })
 | 
			
		||||
    )
 | 
			
		||||
    .subscribe((block) => {
 | 
			
		||||
      this.block = block;
 | 
			
		||||
      this.isLoadingBlock = false;
 | 
			
		||||
      this.getBlockTransactions(block.id);
 | 
			
		||||
      this.ref.markForCheck();
 | 
			
		||||
    },
 | 
			
		||||
    (error) => {
 | 
			
		||||
      this.error = error;
 | 
			
		||||
      this.isLoadingBlock = false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.memPoolService.blocks$
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { QRCodeModule } from 'angularx-qrcode';
 | 
			
		||||
import { ExplorerComponent } from './explorer/explorer.component';
 | 
			
		||||
import { TransactionComponent } from './transaction/transaction.component';
 | 
			
		||||
import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
@ -33,6 +34,7 @@ const routes: Routes = [
 | 
			
		||||
    SharedModule,
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    RouterModule.forChild(routes),
 | 
			
		||||
    QRCodeModule,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class ExplorerModule { }
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf]="!isLoadingTx" [ngIfElse]="loadingTx">
 | 
			
		||||
  <ng-template [ngIf]="!isLoadingTx && !error">
 | 
			
		||||
 | 
			
		||||
    <app-transactions-list [transactions]="[tx]" [showConfirmations]="true"></app-transactions-list>
 | 
			
		||||
 | 
			
		||||
@ -49,11 +49,21 @@
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
  </ng-template>
 | 
			
		||||
  <ng-template #loadingTx>
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf="isLoadingTx && !error">
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      <div class="spinner-border text-light"></div>
 | 
			
		||||
      <br><br>
 | 
			
		||||
    </div>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf]="error">
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      Error loading transaction data.
 | 
			
		||||
      <br>
 | 
			
		||||
      <i>{{ error.message }}</i>
 | 
			
		||||
    </div>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
</div>
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@ export class TransactionComponent implements OnInit {
 | 
			
		||||
  tx: any;
 | 
			
		||||
  isLoadingTx = true;
 | 
			
		||||
  conversions: any;
 | 
			
		||||
  error: any;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private route: ActivatedRoute,
 | 
			
		||||
@ -23,6 +24,7 @@ export class TransactionComponent implements OnInit {
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.route.paramMap.pipe(
 | 
			
		||||
      switchMap((params: ParamMap) => {
 | 
			
		||||
        this.error = undefined;
 | 
			
		||||
        const txId: string = params.get('id') || '';
 | 
			
		||||
        return this.apiService.getTransaction$(txId);
 | 
			
		||||
      })
 | 
			
		||||
@ -30,6 +32,10 @@ export class TransactionComponent implements OnInit {
 | 
			
		||||
    .subscribe((tx) => {
 | 
			
		||||
      this.tx = tx;
 | 
			
		||||
      this.isLoadingTx = false;
 | 
			
		||||
    },
 | 
			
		||||
    (error) => {
 | 
			
		||||
      this.error = error;
 | 
			
		||||
      this.isLoadingTx = false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.memPoolService.conversions$
 | 
			
		||||
 | 
			
		||||
@ -1,93 +1,93 @@
 | 
			
		||||
<ng-template ngFor let-tx [ngForOf]="transactions">
 | 
			
		||||
    
 | 
			
		||||
  <table class="table table-borderless">
 | 
			
		||||
      <thead>
 | 
			
		||||
        <tr class="header-bg">
 | 
			
		||||
          <th>
 | 
			
		||||
            <a [routerLink]="['/explorer/tx/', tx.txid]">{{ tx.txid }}</a>
 | 
			
		||||
          </th>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </thead>
 | 
			
		||||
    </table>
 | 
			
		||||
    <thead>
 | 
			
		||||
      <tr class="header-bg">
 | 
			
		||||
        <th>
 | 
			
		||||
          <a [routerLink]="['/explorer/tx/', tx.txid]">{{ tx.txid }}</a>
 | 
			
		||||
        </th>
 | 
			
		||||
      </tr>
 | 
			
		||||
    </thead>
 | 
			
		||||
  </table>
 | 
			
		||||
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col">
 | 
			
		||||
          <table class="table table-borderless smaller-text">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>
 | 
			
		||||
                  <div *ngFor="let vin of tx.vin">
 | 
			
		||||
                    <ng-template [ngIf]="vin.is_coinbase" [ngIfElse]="regularVin">
 | 
			
		||||
                      Coinbase
 | 
			
		||||
                    </ng-template>
 | 
			
		||||
                    <ng-template #regularVin>
 | 
			
		||||
                      <a [routerLink]="['/explorer/address/', vin.prevout.scriptpubkey_address]">{{ vin.prevout.scriptpubkey_address }}</a>
 | 
			
		||||
                      (<a [routerLink]="['/explorer/tx/', vin.txid]">tx</a>)
 | 
			
		||||
                    </ng-template>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </td>
 | 
			
		||||
                <td class="text-right">
 | 
			
		||||
                  <div *ngFor="let vin of tx.vin">
 | 
			
		||||
                    <ng-template [ngIf]="vin.prevout">
 | 
			
		||||
                      <ng-template [ngIf]="viewFiat" [ngIfElse]="viewFiatVin">
 | 
			
		||||
                        <span class="green-color">{{ conversions.USD * (vin.prevout.value / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
 | 
			
		||||
                      </ng-template>
 | 
			
		||||
                      <ng-template #viewFiatVin>
 | 
			
		||||
                        {{ vin.prevout.value / 100000000 }} BTC
 | 
			
		||||
                      </ng-template>
 | 
			
		||||
                    </ng-template>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col">
 | 
			
		||||
          <table class="table table-borderless smaller-text">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
  <div class="row">
 | 
			
		||||
      <div class="col">
 | 
			
		||||
        <table class="table table-borderless smaller-text">
 | 
			
		||||
          <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td>
 | 
			
		||||
                <div *ngFor="let vout of tx.vout">
 | 
			
		||||
                  <a *ngIf="vout.scriptpubkey_address; else scriptpubkey_type" [routerLink]="['/explorer/address/', vout.scriptpubkey_address]">{{ vout.scriptpubkey_address }}</a>
 | 
			
		||||
                  <ng-template #scriptpubkey_type>
 | 
			
		||||
                    {{ vout.scriptpubkey_type | uppercase }}
 | 
			
		||||
                <div *ngFor="let vin of tx.vin">
 | 
			
		||||
                  <ng-template [ngIf]="vin.is_coinbase" [ngIfElse]="regularVin">
 | 
			
		||||
                    Coinbase
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                  <ng-template #regularVin>
 | 
			
		||||
                    <a [routerLink]="['/explorer/address/', vin.prevout.scriptpubkey_address]">{{ vin.prevout.scriptpubkey_address }}</a>
 | 
			
		||||
                    (<a [routerLink]="['/explorer/tx/', vin.txid]">tx</a>)
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                </div>
 | 
			
		||||
              </td>
 | 
			
		||||
              <td class="text-right">
 | 
			
		||||
                <div *ngFor="let vout of tx.vout">
 | 
			
		||||
                  <ng-template [ngIf]="viewFiat" [ngIfElse]="viewFiatVout">
 | 
			
		||||
                    <span class="green-color">{{ conversions.USD * (vout.value / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                  <ng-template #viewFiatVout>
 | 
			
		||||
                    {{ vout.value / 100000000 }} BTC
 | 
			
		||||
                <div *ngFor="let vin of tx.vin">
 | 
			
		||||
                  <ng-template [ngIf]="vin.prevout">
 | 
			
		||||
                    <ng-template [ngIf]="viewFiat" [ngIfElse]="viewFiatVin">
 | 
			
		||||
                      <span class="green-color">{{ conversions.USD * (vin.prevout.value / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
 | 
			
		||||
                    </ng-template>
 | 
			
		||||
                    <ng-template #viewFiatVin>
 | 
			
		||||
                      {{ vin.prevout.value / 100000000 }} BTC
 | 
			
		||||
                    </ng-template>
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                </div>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col">
 | 
			
		||||
        <table class="table table-borderless smaller-text">
 | 
			
		||||
          <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td class="text-right" colspan="4">
 | 
			
		||||
                <ng-template [ngIf]="showConfirmations">
 | 
			
		||||
                  <button *ngIf="tx.status.confirmed; else unconfirmedButton" type="button" class="btn btn-success">{{ latestBlockHeight - tx.status.block_height + 1 }} confirmations</button>
 | 
			
		||||
                  <ng-template #unconfirmedButton>
 | 
			
		||||
                    <button type="button" class="btn btn-danger">Unconfirmed</button>
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                   
 | 
			
		||||
            <td>
 | 
			
		||||
              <div *ngFor="let vout of tx.vout">
 | 
			
		||||
                <a *ngIf="vout.scriptpubkey_address; else scriptpubkey_type" [routerLink]="['/explorer/address/', vout.scriptpubkey_address]">{{ vout.scriptpubkey_address }}</a>
 | 
			
		||||
                <ng-template #scriptpubkey_type>
 | 
			
		||||
                  {{ vout.scriptpubkey_type | uppercase }}
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <button type="button" class="btn btn-primary" (click)="viewFiat = !viewFiat">
 | 
			
		||||
                  <ng-template [ngIf]="viewFiat" [ngIfElse]="viewFiatButton">
 | 
			
		||||
                    <span *ngIf="conversions">{{ conversions.USD * (getTotalTxOutput(tx) / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                  <ng-template #viewFiatButton>
 | 
			
		||||
                    {{ getTotalTxOutput(tx) / 100000000 }} BTC
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                </button>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td class="text-right">
 | 
			
		||||
              <div *ngFor="let vout of tx.vout">
 | 
			
		||||
                <ng-template [ngIf]="viewFiat" [ngIfElse]="viewFiatVout">
 | 
			
		||||
                  <span class="green-color">{{ conversions.USD * (vout.value / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <ng-template #viewFiatVout>
 | 
			
		||||
                  {{ vout.value / 100000000 }} BTC
 | 
			
		||||
                </ng-template>
 | 
			
		||||
              </div>
 | 
			
		||||
            </td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="text-right" colspan="4">
 | 
			
		||||
              <ng-template [ngIf]="showConfirmations">
 | 
			
		||||
                <button *ngIf="tx.status.confirmed; else unconfirmedButton" type="button" class="btn btn-success">{{ latestBlockHeight - tx.status.block_height + 1 }} confirmations</button>
 | 
			
		||||
                <ng-template #unconfirmedButton>
 | 
			
		||||
                  <button type="button" class="btn btn-danger">Unconfirmed</button>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                 
 | 
			
		||||
              </ng-template>
 | 
			
		||||
              <button type="button" class="btn btn-primary" (click)="viewFiat = !viewFiat">
 | 
			
		||||
                <ng-template [ngIf]="viewFiat" [ngIfElse]="viewFiatButton">
 | 
			
		||||
                  <span *ngIf="conversions">{{ conversions.USD * (getTotalTxOutput(tx) / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <ng-template #viewFiatButton>
 | 
			
		||||
                  {{ getTotalTxOutput(tx) / 100000000 }} BTC
 | 
			
		||||
                </ng-template>
 | 
			
		||||
              </button>
 | 
			
		||||
            </td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
  </ng-template>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,9 @@
 | 
			
		||||
.header-bg {
 | 
			
		||||
  background-color: #181b2d !important;
 | 
			
		||||
  background-color:#653b9c;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.header-bg a {
 | 
			
		||||
  color: #FFF;
 | 
			
		||||
  text-decoration: underline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -170,11 +170,23 @@ export class ApiService {
 | 
			
		||||
    return this.httpClient.get<any[]>(API_BASE_URL + '/explorer/tx/' + txId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlock$(hash: string): Observable<any[]> {
 | 
			
		||||
    return this.httpClient.get<any[]>(API_BASE_URL + '/explorer/block/' + hash);
 | 
			
		||||
  getBlock$(hash: string): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<any>(API_BASE_URL + '/explorer/block/' + hash);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlockTransactions$(hash: string, index?: number): Observable<any[]> {
 | 
			
		||||
    return this.httpClient.get<any[]>(API_BASE_URL + '/explorer/block/' + hash + '/tx/' + (index || ''));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAddress$(address: string): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<any>(API_BASE_URL + '/explorer/address/' + address);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAddressTransactions$(address: string): Observable<any[]> {
 | 
			
		||||
    return this.httpClient.get<any[]>(API_BASE_URL + '/explorer/address/' + address+ '/tx/');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAddressTransactionsFromHash$(address: string, txid: string): Observable<any[]> {
 | 
			
		||||
    return this.httpClient.get<any[]>(API_BASE_URL + '/explorer/address/' + address + '/tx/chain/' + txid);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7884
									
								
								frontend/yarn.lock
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7884
									
								
								frontend/yarn.lock
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user