Bisq module separation.
Transaction view. Block view. Blocks list.
This commit is contained in:
		
							parent
							
								
									60e1b9a41e
								
							
						
					
					
						commit
						db2e293ce5
					
				@ -21,23 +21,13 @@ class Bisq {
 | 
			
		||||
          clearTimeout(fsWait);
 | 
			
		||||
        }
 | 
			
		||||
        fsWait = setTimeout(() => {
 | 
			
		||||
          console.log(`${filename} file changed. Reloading dump file.`);
 | 
			
		||||
          console.log(`${filename} file change detected.`);
 | 
			
		||||
          this.loadBisqDumpFile();
 | 
			
		||||
        }, 1000);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async loadBisqDumpFile(): Promise<void> {
 | 
			
		||||
    try {
 | 
			
		||||
      const data = await this.loadData();
 | 
			
		||||
      await this.loadBisqBlocksDump(data);
 | 
			
		||||
      this.buildIndex();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.log('loadBisqDumpFile() error.', e.message);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTransaction(txId: string): BisqTransaction | undefined {
 | 
			
		||||
    return this.transactionsIndex[txId];
 | 
			
		||||
  }
 | 
			
		||||
@ -46,43 +36,54 @@ class Bisq {
 | 
			
		||||
    return [this.transactions.slice(start, length + start), this.transactions.length];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlockTransactions(blockHash: string, start: number, length: number): [BisqTransaction[], number] {
 | 
			
		||||
    const block = this.blocksIndex[blockHash];
 | 
			
		||||
    if (!block) {
 | 
			
		||||
      return [[], -1];
 | 
			
		||||
    }
 | 
			
		||||
    return [block.txs.slice(start, length + start), block.txs.length];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlock(hash: string): BisqBlock | undefined {
 | 
			
		||||
    console.log(hash);
 | 
			
		||||
    console.log(this.blocksIndex[hash]);
 | 
			
		||||
    return this.blocksIndex[hash];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlocks(start: number, length: number): [BisqBlock[], number] {
 | 
			
		||||
    return [this.blocks.slice(start, length + start), this.blocks.length];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async loadBisqDumpFile(): Promise<void> {
 | 
			
		||||
    try {
 | 
			
		||||
      const data = await this.loadData();
 | 
			
		||||
      await this.loadBisqBlocksDump(data);
 | 
			
		||||
      this.buildIndex();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.log('loadBisqDumpFile() error.', e.message);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private buildIndex() {
 | 
			
		||||
    const start = new Date().getTime();
 | 
			
		||||
    this.transactions = [];
 | 
			
		||||
    this.transactionsIndex = {};
 | 
			
		||||
    this.blocks.forEach((block) => {
 | 
			
		||||
      if (this.blocksIndex[block.hash]) {
 | 
			
		||||
        return;
 | 
			
		||||
      if (!this.blocksIndex[block.hash]) {
 | 
			
		||||
        this.blocksIndex[block.hash] = block;
 | 
			
		||||
      }
 | 
			
		||||
      this.blocksIndex[block.hash] = block;
 | 
			
		||||
      block.txs.forEach((tx) => {
 | 
			
		||||
        this.transactions.unshift(tx);
 | 
			
		||||
        this.transactions.push(tx);
 | 
			
		||||
        this.transactionsIndex[tx.id] = tx;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    console.log('Bisq data index rebuilt');
 | 
			
		||||
    const time = new Date().getTime() - start;
 | 
			
		||||
    console.log('Bisq data index rebuilt in ' + time + ' ms');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async loadBisqBlocksDump(cacheData: string): Promise<void> {
 | 
			
		||||
    const start = new Date().getTime();
 | 
			
		||||
    if (cacheData && cacheData.length !== 0) {
 | 
			
		||||
      console.log('Parsing Bisq data from dump file');
 | 
			
		||||
      console.log('Loading Bisq data from dump...');
 | 
			
		||||
      const data: BisqBlocks = JSON.parse(cacheData);
 | 
			
		||||
      if (data.blocks && data.blocks.length !== this.blocks.length) {
 | 
			
		||||
        this.blocks = data.blocks;
 | 
			
		||||
        this.blocks.reverse();
 | 
			
		||||
        this.latestBlockHeight = data.chainHeight;
 | 
			
		||||
        const end = new Date().getTime();
 | 
			
		||||
        const time = end - start;
 | 
			
		||||
        console.log('Loaded bisq dump in ' + time + ' ms');
 | 
			
		||||
        const time = new Date().getTime() - start;
 | 
			
		||||
        console.log('Bisq dump loaded in ' + time + ' ms');
 | 
			
		||||
      } else {
 | 
			
		||||
        throw new Error(`Bisq dump didn't contain any blocks`);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -94,7 +94,7 @@ class Server {
 | 
			
		||||
      this.app
 | 
			
		||||
        .get(config.API_ENDPOINT + 'bisq/tx/:txId', routes.getBisqTransaction)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'bisq/block/:hash', routes.getBisqBlock)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'bisq/block/:hash/txs/:index/:length', routes.getBisqBlockTransactions)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'bisq/blocks/:index/:length', routes.getBisqBlocks)
 | 
			
		||||
        .get(config.API_ENDPOINT + 'bisq/txs/:index/:length', routes.getBisqTransactions)
 | 
			
		||||
      ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -105,7 +105,7 @@ class Routes {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getBisqBlock(req: Request, res: Response) {
 | 
			
		||||
    const result = bisq.getBlock(req['hash']);
 | 
			
		||||
    const result = bisq.getBlock(req.params.hash);
 | 
			
		||||
    if (result) {
 | 
			
		||||
      res.send(result);
 | 
			
		||||
    } else {
 | 
			
		||||
@ -113,16 +113,10 @@ class Routes {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getBisqBlockTransactions(req: Request, res: Response) {
 | 
			
		||||
    const blockHash = req.params.hash || '';
 | 
			
		||||
  public getBisqBlocks(req: Request, res: Response) {
 | 
			
		||||
    const index = parseInt(req.params.index, 10) || 0;
 | 
			
		||||
    const length = parseInt(req.params.length, 10) > 100 ? 100 : parseInt(req.params.length, 10) || 25;
 | 
			
		||||
    const [transactions, count] = bisq.getBlockTransactions(blockHash, index, length);
 | 
			
		||||
    if (count === -1) {
 | 
			
		||||
      res.header('X-Total-Count', '0');
 | 
			
		||||
      res.send([]);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const [transactions, count] = bisq.getBlocks(index, length);
 | 
			
		||||
    res.header('X-Total-Count', count.toString());
 | 
			
		||||
    res.send(transactions);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,6 @@ import { WebsocketService } from './services/websocket.service';
 | 
			
		||||
import { AddressLabelsComponent } from './components/address-labels/address-labels.component';
 | 
			
		||||
import { MempoolBlocksComponent } from './components/mempool-blocks/mempool-blocks.component';
 | 
			
		||||
import { QrcodeComponent } from './components/qrcode/qrcode.component';
 | 
			
		||||
import { ClipboardComponent } from './components/clipboard/clipboard.component';
 | 
			
		||||
import { MasterPageComponent } from './components/master-page/master-page.component';
 | 
			
		||||
import { AboutComponent } from './components/about/about.component';
 | 
			
		||||
import { TelevisionComponent } from './components/television/television.component';
 | 
			
		||||
@ -66,7 +65,6 @@ import { SharedModule } from './shared/shared.module';
 | 
			
		||||
    AddressLabelsComponent,
 | 
			
		||||
    MempoolBlocksComponent,
 | 
			
		||||
    QrcodeComponent,
 | 
			
		||||
    ClipboardComponent,
 | 
			
		||||
    ChartistComponent,
 | 
			
		||||
    FooterComponent,
 | 
			
		||||
    FiatComponent,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								frontend/src/app/bisq/bisq-api.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								frontend/src/app/bisq/bisq-api.service.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { HttpClient, HttpResponse } from '@angular/common/http';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { BisqTransaction, BisqBlock } from './bisq.interfaces';
 | 
			
		||||
 | 
			
		||||
const API_BASE_URL = '/api/v1';
 | 
			
		||||
 | 
			
		||||
@Injectable({
 | 
			
		||||
  providedIn: 'root'
 | 
			
		||||
})
 | 
			
		||||
export class BisqApiService {
 | 
			
		||||
  apiBaseUrl: string;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private httpClient: HttpClient,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  getTransaction$(txId: string): Observable<BisqTransaction> {
 | 
			
		||||
    return this.httpClient.get<BisqTransaction>(API_BASE_URL + '/bisq/tx/' + txId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listTransactions$(start: number, length: number): Observable<HttpResponse<BisqTransaction[]>> {
 | 
			
		||||
    return this.httpClient.get<BisqTransaction[]>(API_BASE_URL + `/bisq/txs/${start}/${length}`, { observe: 'response' });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlock$(hash: string): Observable<BisqBlock> {
 | 
			
		||||
    return this.httpClient.get<BisqBlock>(API_BASE_URL + '/bisq/block/' + hash);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listBlocks$(start: number, length: number): Observable<HttpResponse<BisqBlock[]>> {
 | 
			
		||||
    return this.httpClient.get<BisqBlock[]>(API_BASE_URL + `/bisq/blocks/${start}/${length}`, { observe: 'response' });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -6,23 +6,95 @@
 | 
			
		||||
 | 
			
		||||
  <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
  <ng-template ngFor let-tx [ngForOf]="bisqTransactions">
 | 
			
		||||
  <ng-template [ngIf]="!isLoading && !error">
 | 
			
		||||
 | 
			
		||||
    <div class="header-bg box" style="padding: 10px; margin-bottom: 10px;">
 | 
			
		||||
      <a [routerLink]="['/tx/' | relativeUrl, tx.id]" [state]="{ data: tx }">
 | 
			
		||||
        <span style="float: left;" class="d-block d-md-none">{{ tx.id | shortenString : 16 }}</span>
 | 
			
		||||
        <span style="float: left;" class="d-none d-md-block">{{ tx.id }}</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <div class="float-right">
 | 
			
		||||
        {{ tx.time | date:'yyyy-MM-dd HH:mm' }}
 | 
			
		||||
    <div class="box">
 | 
			
		||||
      <div class="row">
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width">Hash</td>
 | 
			
		||||
                <td><a [routerLink]="['/block/' | relativeUrl, block.hash]" title="{{ block.hash }}">{{ block.hash | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="block.hash"></app-clipboard></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Timestamp</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                  {{ block.time | date:'yyyy-MM-dd HH:mm' }}
 | 
			
		||||
                  <div class="lg-inline">
 | 
			
		||||
                    <i>(<app-time-since [time]="block.time / 1000" [fastRender]="true"></app-time-since> ago)</i>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </td>
 | 
			
		||||
              </tr>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width">Previous hash</td>
 | 
			
		||||
                <td><a [routerLink]="['/block/' | relativeUrl, block.previousBlockHash]" title="{{ block.hash }}">{{ block.previousBlockHash | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="block.previousBlockHash"></app-clipboard></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="clearfix"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <app-bisq-transfers [tx]="tx"></app-bisq-transfers>
 | 
			
		||||
    <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2>{{ block.txs.length | number }} transactions</h2>
 | 
			
		||||
 | 
			
		||||
    <ng-template ngFor let-tx [ngForOf]="block.txs">
 | 
			
		||||
 | 
			
		||||
      <div class="header-bg box" style="padding: 10px; margin-bottom: 10px;">
 | 
			
		||||
        <a [routerLink]="['/tx/' | relativeUrl, tx.id]" [state]="{ data: tx }">
 | 
			
		||||
          <span style="float: left;" class="d-block d-md-none">{{ tx.id | shortenString : 16 }}</span>
 | 
			
		||||
          <span style="float: left;" class="d-none d-md-block">{{ tx.id }}</span>
 | 
			
		||||
        </a>
 | 
			
		||||
        <div class="float-right">
 | 
			
		||||
          {{ tx.time | date:'yyyy-MM-dd HH:mm' }}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="clearfix"></div>
 | 
			
		||||
      </div>
 | 
			
		||||
  
 | 
			
		||||
      <app-bisq-transfers [tx]="tx"></app-bisq-transfers>
 | 
			
		||||
  
 | 
			
		||||
      <br>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 | 
			
		||||
  </ng-template>
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf]="isLoading">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <div class="box">
 | 
			
		||||
      <div class="row">
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width">Hash</td>
 | 
			
		||||
                <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Timestamp</td>
 | 
			
		||||
                <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width">Previous hash</td>
 | 
			
		||||
                <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,10 @@
 | 
			
		||||
 | 
			
		||||
.td-width {
 | 
			
		||||
  width: 175px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 767.98px) {
 | 
			
		||||
	.td-width {
 | 
			
		||||
		width: 140px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,32 +1,52 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { BisqTransaction } from 'src/app/interfaces/bisq.interfaces';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { Component, OnInit, OnDestroy } from '@angular/core';
 | 
			
		||||
import { BisqTransaction, BisqBlock } from 'src/app/bisq/bisq.interfaces';
 | 
			
		||||
import { BisqApiService } from '../bisq-api.service';
 | 
			
		||||
import { ActivatedRoute, ParamMap } from '@angular/router';
 | 
			
		||||
import { Subscribable, Subscription, of } from 'rxjs';
 | 
			
		||||
import { switchMap } from 'rxjs/operators';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-bisq-block',
 | 
			
		||||
  templateUrl: './bisq-block.component.html',
 | 
			
		||||
  styleUrls: ['./bisq-block.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class BisqBlockComponent implements OnInit {
 | 
			
		||||
  bisqTransactions: BisqTransaction[];
 | 
			
		||||
  bisqTransactionsCount: number;
 | 
			
		||||
 | 
			
		||||
export class BisqBlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
  block: BisqBlock;
 | 
			
		||||
  subscription: Subscription;
 | 
			
		||||
  blockHash = '';
 | 
			
		||||
  blockHeight = 0;
 | 
			
		||||
  isLoading = true;
 | 
			
		||||
  error: any;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private apiService: ApiService,
 | 
			
		||||
    private bisqApiService: BisqApiService,
 | 
			
		||||
    private route: ActivatedRoute,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.apiService.listBisqBlockTransactions$(this.blockHash, 0, 10)
 | 
			
		||||
    .subscribe((response) => {
 | 
			
		||||
      this.bisqTransactionsCount = parseInt(response.headers.get('x-total-count'), 10);
 | 
			
		||||
      this.bisqTransactions = response.body;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.subscription = this.route.paramMap
 | 
			
		||||
      .pipe(
 | 
			
		||||
        switchMap((params: ParamMap) => {
 | 
			
		||||
          this.blockHash = params.get('id') || '';
 | 
			
		||||
          this.isLoading = true;
 | 
			
		||||
          if (history.state.data && history.state.data.blockHeight) {
 | 
			
		||||
            this.blockHeight = history.state.data.blockHeight;
 | 
			
		||||
          }
 | 
			
		||||
          if (history.state.data && history.state.data.block) {
 | 
			
		||||
            this.blockHeight = history.state.data.block.height;
 | 
			
		||||
            return of(history.state.data.block);
 | 
			
		||||
          }
 | 
			
		||||
          return this.bisqApiService.getBlock$(this.blockHash);
 | 
			
		||||
        })
 | 
			
		||||
      )
 | 
			
		||||
      .subscribe((block: BisqBlock) => {
 | 
			
		||||
        this.isLoading = false;
 | 
			
		||||
        this.blockHeight = block.height;
 | 
			
		||||
        this.block = block;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    this.subscription.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,30 @@
 | 
			
		||||
<div class="container-xl">
 | 
			
		||||
  <h2 style="float: left;">Blocks</h2>
 | 
			
		||||
  <h2 style="float: left;">BSQ Blocks</h2>
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
  <table class="table table-borderless table-striped">
 | 
			
		||||
    <thead>
 | 
			
		||||
      <th>Hash</th>
 | 
			
		||||
      <th>Total Sent (BSQ)</th>
 | 
			
		||||
      <th>Transactions</th>
 | 
			
		||||
      <th>Height</th>
 | 
			
		||||
      <th>Time</th>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody>
 | 
			
		||||
      <tr *ngFor="let block of blocks; trackBy: trackByFn">
 | 
			
		||||
        <td><a [routerLink]="['/block/' | relativeUrl, block.hash]" title="{{ block.hash }}" [state]="{ data: { block: block } }">{{ block.hash | shortenString : 13 }}</a></td>
 | 
			
		||||
        <td>{{ calculateTotalOutput(block) / 100 | number: '1.2-2' }}</td>
 | 
			
		||||
        <td>{{ block.txs.length }}</td>
 | 
			
		||||
        <td><a [routerLink]="['/block/' | relativeUrl, block.hash]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
 | 
			
		||||
        <td>{{ block.time | date:'yyyy-MM-dd HH:mm' }}</td>
 | 
			
		||||
      </tr> 
 | 
			
		||||
    </tbody>
 | 
			
		||||
  </table>
 | 
			
		||||
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <ngb-pagination [collectionSize]="totalCount" [rotate]="true" [pageSize]="itemsPerPage" [(page)]="page" (pageChange)="pageChange(page)" [maxSize]="5" [boundaryLinks]="true"></ngb-pagination>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
@ -1,4 +1,8 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { BisqApiService } from '../bisq-api.service';
 | 
			
		||||
import { switchMap } from 'rxjs/operators';
 | 
			
		||||
import { Subject } from 'rxjs';
 | 
			
		||||
import { BisqBlock, BisqOutput, BisqTransaction } from '../bisq.interfaces';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-bisq-blocks',
 | 
			
		||||
@ -6,10 +10,47 @@ import { Component, OnInit } from '@angular/core';
 | 
			
		||||
  styleUrls: ['./bisq-blocks.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class BisqBlocksComponent implements OnInit {
 | 
			
		||||
  blocks: BisqBlock[];
 | 
			
		||||
  totalCount: number;
 | 
			
		||||
  page = 1;
 | 
			
		||||
  itemsPerPage: number;
 | 
			
		||||
  contentSpace = window.innerHeight - (165 + 75);
 | 
			
		||||
  fiveItemsPxSize = 250;
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
  pageSubject$ = new Subject<number>();
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private bisqApiService: BisqApiService,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10);
 | 
			
		||||
 | 
			
		||||
    this.pageSubject$
 | 
			
		||||
      .pipe(
 | 
			
		||||
        switchMap((page) => this.bisqApiService.listBlocks$((page - 1) * 10, this.itemsPerPage))
 | 
			
		||||
      )
 | 
			
		||||
      .subscribe((response) => {
 | 
			
		||||
        this.blocks = response.body;
 | 
			
		||||
        this.totalCount = parseInt(response.headers.get('x-total-count'), 10);
 | 
			
		||||
      }, (error) => {
 | 
			
		||||
        console.log(error);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    this.pageSubject$.next(1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  calculateTotalOutput(block: BisqBlock): number {
 | 
			
		||||
    return block.txs.reduce((a: number, tx: BisqTransaction) =>
 | 
			
		||||
      a + tx.outputs.reduce((acc: number, output: BisqOutput) => acc + output.bsqAmount, 0), 0
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  trackByFn(index: number) {
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pageChange(page: number) {
 | 
			
		||||
    this.pageSubject$.next(page);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,10 +11,6 @@
 | 
			
		||||
            <td>Outputs</td>
 | 
			
		||||
            <td>{{ totalOutput / 100 | number: '1.2-2' }} BSQ</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td>Burnt</td>
 | 
			
		||||
            <td>{{ tx.burntFee / 100 | number: '1.2-2' }} BSQ</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td>Issuance</td>
 | 
			
		||||
            <td>{{ totalIssued / 100 | number: '1.2-2' }} BSQ</td>
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { Component, ChangeDetectionStrategy, Input, OnChanges } from '@angular/core';
 | 
			
		||||
import { BisqTransaction } from 'src/app/interfaces/bisq.interfaces';
 | 
			
		||||
import { BisqTransaction } from 'src/app/bisq/bisq.interfaces';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-bisq-transaction-details',
 | 
			
		||||
 | 
			
		||||
@ -2,64 +2,133 @@
 | 
			
		||||
 | 
			
		||||
  <h1 class="float-left mr-3 mb-md-3">Transaction</h1>
 | 
			
		||||
 | 
			
		||||
  <button type="button" class="btn btn-sm btn-success float-right mr-2 mt-1 mt-md-3">2 confirmations</button>
 | 
			
		||||
  <ng-template [ngIf]="!isLoading" [ngIfElse]="isLoadingTmpl">
 | 
			
		||||
 | 
			
		||||
  <div>
 | 
			
		||||
    <a [routerLink]="['/bisq-tx' | relativeUrl, bisqTx.blockHash]" style="line-height: 56px;">
 | 
			
		||||
      <span class="d-inline d-lg-none">{{ bisqTx.blockHash | shortenString : 24 }}</span>
 | 
			
		||||
      <span class="d-none d-lg-inline">{{ bisqTx.blockHash }}</span>
 | 
			
		||||
    </a>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="clearfix"></div>
 | 
			
		||||
    <button *ngIf="(latestBlock$ | async) as latestBlock" type="button" class="btn btn-sm btn-success float-right mr-2 mt-1 mt-md-3">{{ latestBlock.height - bisqTx.blockHeight + 1 }} confirmation<ng-container *ngIf="latestBlock.height - bisqTx.blockHeight + 1 > 1">s</ng-container></button>
 | 
			
		||||
 | 
			
		||||
  <div class="box">
 | 
			
		||||
    <div class="row">
 | 
			
		||||
      <div class="col-sm">
 | 
			
		||||
    <div>
 | 
			
		||||
      <a [routerLink]="['/bisq-tx' | relativeUrl, bisqTx.blockHash]" style="line-height: 56px;">
 | 
			
		||||
        <span class="d-inline d-lg-none">{{ bisqTx.blockHash | shortenString : 24 }}</span>
 | 
			
		||||
        <span class="d-none d-lg-inline">{{ bisqTx.blockHash }}</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <app-clipboard [text]="txId"></app-clipboard>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
    <div class="box">
 | 
			
		||||
      <div class="row">
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width">Included in block</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                  <a [routerLink]="['/block/' | relativeUrl, bisqTx.blockHash]" [state]="{ data: { blockHeight: bisqTx.blockHash } }">{{ bisqTx.blockHeight }}</a>
 | 
			
		||||
                  <i> (<app-time-since [time]="bisqTx.time / 1000" [fastRender]="true"></app-time-since> ago)</i>
 | 
			
		||||
                </td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td class="td-width">Fee burnt</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    {{ bisqTx.burntFee / 100 | number: '1.2-2' }} BSQ
 | 
			
		||||
                </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2>Details</h2>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <app-bisq-transaction-details [tx]="bisqTx"></app-bisq-transaction-details>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2>Inputs & Outputs</h2>
 | 
			
		||||
 | 
			
		||||
    <app-bisq-transfers [tx]="bisqTx"></app-bisq-transfers>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
  </ng-template>
 | 
			
		||||
 | 
			
		||||
  <ng-template #isLoadingTmpl>
 | 
			
		||||
 | 
			
		||||
    <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
    <div class="box">
 | 
			
		||||
      <div class="row">
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width"><span class="skeleton-loader"></span></td>
 | 
			
		||||
                <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width"><span class="skeleton-loader"></span></td>
 | 
			
		||||
                <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2>Details</h2>
 | 
			
		||||
    <div class="box">
 | 
			
		||||
      <table class="table table-borderless table-striped">
 | 
			
		||||
        <tbody>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
            <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
            <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
      </table>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2>Inputs & Outputs</h2>
 | 
			
		||||
 | 
			
		||||
    <div class="box">
 | 
			
		||||
      <div class="row">
 | 
			
		||||
        <table class="table table-borderless table-striped">
 | 
			
		||||
          <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td class="td-width">Included in block</td>
 | 
			
		||||
              <td>
 | 
			
		||||
                <a [routerLink]="['/block/' | relativeUrl, bisqTx.blockHash]" [state]="{ data: { blockHeight: bisqTx.blockHash } }">{{ bisqTx.blockHeight }}</a>
 | 
			
		||||
                <i> (<app-time-since [time]="bisqTx.time" [fastRender]="true"></app-time-since> ago)</i>
 | 
			
		||||
              </td>
 | 
			
		||||
              <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
              <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col-sm">
 | 
			
		||||
        <table class="table table-borderless table-striped">
 | 
			
		||||
          <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width">Fee</td>
 | 
			
		||||
                <td>15,436 sat ($1.40)</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Fee per vByte</td>
 | 
			
		||||
                <td>	68.2 sat/vB 
 | 
			
		||||
                </td>
 | 
			
		||||
              </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
 | 
			
		||||
<h2>Details</h2>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<app-bisq-transaction-details [tx]="bisqTx"></app-bisq-transaction-details>
 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
 | 
			
		||||
<h2>Inputs & Outputs</h2>
 | 
			
		||||
 | 
			
		||||
<app-bisq-transfers [tx]="bisqTx"></app-bisq-transfers>
 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,9 @@
 | 
			
		||||
.td-width {
 | 
			
		||||
  width: 175px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 767.98px) {
 | 
			
		||||
	.td-width {
 | 
			
		||||
		width: 150px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
			
		||||
 | 
			
		||||
import { BisqTransactionComponent } from './bisq-transaction.component';
 | 
			
		||||
 | 
			
		||||
describe('BisqTransactionComponent', () => {
 | 
			
		||||
  let component: BisqTransactionComponent;
 | 
			
		||||
  let fixture: ComponentFixture<BisqTransactionComponent>;
 | 
			
		||||
 | 
			
		||||
  beforeEach(async(() => {
 | 
			
		||||
    TestBed.configureTestingModule({
 | 
			
		||||
      declarations: [ BisqTransactionComponent ]
 | 
			
		||||
    })
 | 
			
		||||
    .compileComponents();
 | 
			
		||||
  }));
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    fixture = TestBed.createComponent(BisqTransactionComponent);
 | 
			
		||||
    component = fixture.componentInstance;
 | 
			
		||||
    fixture.detectChanges();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should create', () => {
 | 
			
		||||
    expect(component).toBeTruthy();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@ -1,36 +1,50 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { Component, OnInit, OnDestroy } from '@angular/core';
 | 
			
		||||
import { ActivatedRoute, ParamMap } from '@angular/router';
 | 
			
		||||
import { BisqTransaction } from 'src/app/interfaces/bisq.interfaces';
 | 
			
		||||
import { switchMap } from 'rxjs/operators';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { of } from 'rxjs';
 | 
			
		||||
import { BisqTransaction } from 'src/app/bisq/bisq.interfaces';
 | 
			
		||||
import { switchMap, map } from 'rxjs/operators';
 | 
			
		||||
import { of, Observable, Subscription } from 'rxjs';
 | 
			
		||||
import { StateService } from 'src/app/services/state.service';
 | 
			
		||||
import { Block } from 'src/app/interfaces/electrs.interface';
 | 
			
		||||
import { BisqApiService } from '../bisq-api.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-bisq-transaction',
 | 
			
		||||
  templateUrl: './bisq-transaction.component.html',
 | 
			
		||||
  styleUrls: ['./bisq-transaction.component.scss']
 | 
			
		||||
})
 | 
			
		||||
export class BisqTransactionComponent implements OnInit {
 | 
			
		||||
export class BisqTransactionComponent implements OnInit, OnDestroy {
 | 
			
		||||
  bisqTx: BisqTransaction;
 | 
			
		||||
  latestBlock$: Observable<Block>;
 | 
			
		||||
  txId: string;
 | 
			
		||||
  isLoading = true;
 | 
			
		||||
  subscription: Subscription;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private route: ActivatedRoute,
 | 
			
		||||
    private apiService: ApiService,
 | 
			
		||||
    private bisqApiService: BisqApiService,
 | 
			
		||||
    private stateService: StateService,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.route.paramMap.pipe(
 | 
			
		||||
    this.subscription = this.route.paramMap.pipe(
 | 
			
		||||
      switchMap((params: ParamMap) => {
 | 
			
		||||
        this.isLoading = true;
 | 
			
		||||
        this.txId = params.get('id') || '';
 | 
			
		||||
        if (history.state.bsqTx) {
 | 
			
		||||
          return of(history.state.bsqTx);
 | 
			
		||||
        if (history.state.data) {
 | 
			
		||||
          return of(history.state.data);
 | 
			
		||||
        }
 | 
			
		||||
        return this.apiService.getBisqTransaction$(this.txId);
 | 
			
		||||
        return this.bisqApiService.getTransaction$(this.txId);
 | 
			
		||||
      })
 | 
			
		||||
    )
 | 
			
		||||
    .subscribe((tx) => {
 | 
			
		||||
      this.isLoading = false;
 | 
			
		||||
      this.bisqTx = tx;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.latestBlock$ = this.stateService.blocks$.pipe(map((([block]) => block)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    this.subscription.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<div class="container-xl">
 | 
			
		||||
  <h2 style="float: left;">Latest BSQ Transactions</h2>
 | 
			
		||||
  <h2 style="float: left;">BSQ Transactions</h2>
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <div class="clearfix"></div>
 | 
			
		||||
@ -14,7 +14,7 @@
 | 
			
		||||
      <th>Block Time</th>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody>
 | 
			
		||||
      <tr *ngFor="let tx of transactions">
 | 
			
		||||
      <tr *ngFor="let tx of transactions; trackBy: trackByFn">
 | 
			
		||||
        <td><a [routerLink]="['/tx/' | relativeUrl, tx.id]" [state]="{ bsqTx: tx }">{{ tx.id | shortenString : 16 }}</a></td>
 | 
			
		||||
        <td><app-bisq-icon class="mr-1" [txType]="tx.txType"></app-bisq-icon> {{ tx.txTypeDisplayString }}</td>
 | 
			
		||||
        <td>{{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }}</td>
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { BisqTransaction, BisqOutput } from '../../interfaces/bisq.interfaces';
 | 
			
		||||
import { BisqTransaction, BisqOutput } from '../bisq.interfaces';
 | 
			
		||||
import { Subject } from 'rxjs';
 | 
			
		||||
import { switchMap } from 'rxjs/operators';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { BisqApiService } from '../bisq-api.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-bisq-transactions',
 | 
			
		||||
@ -14,13 +14,13 @@ export class BisqTransactionsComponent implements OnInit {
 | 
			
		||||
  totalCount: number;
 | 
			
		||||
  page = 1;
 | 
			
		||||
  itemsPerPage: number;
 | 
			
		||||
  contentSpace = window.innerHeight - (200 + 200);
 | 
			
		||||
  contentSpace = window.innerHeight - (165 + 75);
 | 
			
		||||
  fiveItemsPxSize = 250;
 | 
			
		||||
 | 
			
		||||
  pageSubject$ = new Subject<number>();
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private apiService: ApiService,
 | 
			
		||||
    private bisqApiService: BisqApiService,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
@ -28,7 +28,7 @@ export class BisqTransactionsComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
    this.pageSubject$
 | 
			
		||||
      .pipe(
 | 
			
		||||
        switchMap((page) => this.apiService.listBisqTransactions$((page - 1) * 10, this.itemsPerPage))
 | 
			
		||||
        switchMap((page) => this.bisqApiService.listTransactions$((page - 1) * 10, this.itemsPerPage))
 | 
			
		||||
      )
 | 
			
		||||
      .subscribe((response) => {
 | 
			
		||||
        this.transactions = response.body;
 | 
			
		||||
@ -47,4 +47,8 @@ export class BisqTransactionsComponent implements OnInit {
 | 
			
		||||
  calculateTotalOutput(outputs: BisqOutput[]): number {
 | 
			
		||||
    return outputs.reduce((acc: number, output: BisqOutput) => acc + output.bsqAmount, 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  trackByFn(index: number) {
 | 
			
		||||
    return index;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
 | 
			
		||||
import { BisqTransaction } from 'src/app/interfaces/bisq.interfaces';
 | 
			
		||||
import { BisqTransaction } from 'src/app/bisq/bisq.interfaces';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-bisq-transfers',
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import { faLeaf, faQuestion, faExclamationTriangle, faRocket, faRetweet, faFileA
 | 
			
		||||
  faEye, faEyeSlash, faLock, faLockOpen } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { BisqBlocksComponent } from './bisq-blocks/bisq-blocks.component';
 | 
			
		||||
import { BisqExplorerComponent } from './bisq-explorer/bisq-explorer.component';
 | 
			
		||||
import { BisqApiService } from './bisq-api.service';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@ -34,6 +35,9 @@ import { BisqExplorerComponent } from './bisq-explorer/bisq-explorer.component';
 | 
			
		||||
    NgbPaginationModule,
 | 
			
		||||
    FontAwesomeModule,
 | 
			
		||||
  ],
 | 
			
		||||
  providers: [
 | 
			
		||||
    BisqApiService,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class BisqModule {
 | 
			
		||||
  constructor(library: FaIconLibrary) {
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ import { ActivatedRoute, ParamMap, Router } from '@angular/router';
 | 
			
		||||
import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
			
		||||
import { switchMap, tap, debounceTime, catchError } from 'rxjs/operators';
 | 
			
		||||
import { Block, Transaction, Vout } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { of } from 'rxjs';
 | 
			
		||||
import { of, Subscription } from 'rxjs';
 | 
			
		||||
import { StateService } from '../../services/state.service';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { env } from 'src/app/app.constants';
 | 
			
		||||
@ -25,6 +25,7 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
  isLoadingTransactions = true;
 | 
			
		||||
  error: any;
 | 
			
		||||
  blockSubsidy: number;
 | 
			
		||||
  subscription: Subscription;
 | 
			
		||||
  fees: number;
 | 
			
		||||
  paginationMaxSize: number;
 | 
			
		||||
  page = 1;
 | 
			
		||||
@ -43,7 +44,7 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
    this.paginationMaxSize = window.matchMedia('(max-width: 700px)').matches ? 3 : 5;
 | 
			
		||||
    this.network = this.stateService.network;
 | 
			
		||||
 | 
			
		||||
    this.route.paramMap
 | 
			
		||||
    this.subscription = this.route.paramMap
 | 
			
		||||
    .pipe(
 | 
			
		||||
      switchMap((params: ParamMap) => {
 | 
			
		||||
        const blockHash: string = params.get('id') || '';
 | 
			
		||||
@ -129,6 +130,7 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    this.stateService.markBlock$.next({});
 | 
			
		||||
    this.subscription.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setBlockSubsidy() {
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ import { AudioService } from 'src/app/services/audio.service';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { calcSegwitFeeGains } from 'src/app/bitcoin.utils';
 | 
			
		||||
import { BisqTransaction } from 'src/app/interfaces/bisq.interfaces';
 | 
			
		||||
import { BisqTransaction } from 'src/app/bisq/bisq.interfaces';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-transaction',
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,6 @@ import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
 | 
			
		||||
import { OptimizedMempoolStats } from '../interfaces/node-api.interface';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { StateService } from './state.service';
 | 
			
		||||
import { BisqTransaction, BisqBlock } from '../interfaces/bisq.interfaces';
 | 
			
		||||
 | 
			
		||||
const API_BASE_URL = '{network}/api/v1';
 | 
			
		||||
 | 
			
		||||
@ -61,22 +60,4 @@ export class ApiService {
 | 
			
		||||
    });
 | 
			
		||||
    return this.httpClient.get<number[]>(this.apiBaseUrl + '/transaction-times', { params });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBisqTransaction$(txId: string): Observable<BisqTransaction> {
 | 
			
		||||
    return this.httpClient.get<BisqTransaction>(this.apiBaseUrl + '/bisq/tx/' + txId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listBisqTransactions$(start: number, length: number): Observable<HttpResponse<BisqTransaction[]>> {
 | 
			
		||||
    return this.httpClient.get<BisqTransaction[]>(this.apiBaseUrl + `/bisq/txs/${start}/${length}`, { observe: 'response' });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBisqBlock$(hash: string): Observable<BisqBlock> {
 | 
			
		||||
    return this.httpClient.get<BisqBlock>(this.apiBaseUrl + '/bisq/block/' + hash);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listBisqBlockTransactions$(blockHash: string, start: number, length: number): Observable<HttpResponse<BisqTransaction[]>> {
 | 
			
		||||
    return this.httpClient.get<BisqTransaction[]>(
 | 
			
		||||
      this.apiBaseUrl + `/bisq/block/${blockHash}/txs/${start}/${length}`, { observe: 'response' }
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import { ScriptpubkeyTypePipe } from './pipes/scriptpubkey-type-pipe/scriptpubke
 | 
			
		||||
import { BytesPipe } from './pipes/bytes-pipe/bytes.pipe';
 | 
			
		||||
import { WuBytesPipe } from './pipes/bytes-pipe/wubytes.pipe';
 | 
			
		||||
import { TimeSinceComponent } from '../components/time-since/time-since.component';
 | 
			
		||||
import { ClipboardComponent } from '../components/clipboard/clipboard.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@ -20,6 +21,7 @@ import { TimeSinceComponent } from '../components/time-since/time-since.componen
 | 
			
		||||
    WuBytesPipe,
 | 
			
		||||
    CeilPipe,
 | 
			
		||||
    ShortenStringPipe,
 | 
			
		||||
    ClipboardComponent,
 | 
			
		||||
    TimeSinceComponent,
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
@ -38,6 +40,7 @@ import { TimeSinceComponent } from '../components/time-since/time-since.componen
 | 
			
		||||
    CeilPipe,
 | 
			
		||||
    ShortenStringPipe,
 | 
			
		||||
    TimeSinceComponent,
 | 
			
		||||
    ClipboardComponent
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class SharedModule {}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user