From bd2bd478ef0341716523b4f26eb9cffe897651d5 Mon Sep 17 00:00:00 2001 From: Simon Lindh Date: Sun, 10 Nov 2019 16:44:00 +0800 Subject: [PATCH] Transaction view. --- backend/src/index.ts | 1 + backend/src/routes.ts | 9 ++ frontend/angular.json | 17 +++ frontend/package.json | 3 +- .../block-modal/block-modal.component.scss | 6 - .../blockchain-blocks.component.html | 5 +- .../blockchain-blocks.component.scss | 4 - .../blockchain-blocks.component.ts | 7 + ...blockchain-projected-blocks.component.scss | 4 - .../projected-block-modal.component.scss | 7 - .../explorer/address/address.component.html | 1 + .../explorer/address/address.component.scss | 0 .../app/explorer/address/address.component.ts | 15 ++ frontend/src/app/explorer/explorer.module.ts | 7 +- .../transaction/transaction.component.html | 144 +++++++++++++++++- .../transaction/transaction.component.ts | 39 ++++- .../master-page/master-page.component.html | 2 +- .../app/master-page/master-page.component.ts | 2 + frontend/src/app/services/api.service.ts | 3 + .../app/tx-bubble/tx-bubble.component.html | 5 +- .../app/tx-bubble/tx-bubble.component.scss | 4 - .../src/app/tx-bubble/tx-bubble.component.ts | 3 + .../environments/environment-esplora.prod.ts | 4 + frontend/src/environments/environment.prod.ts | 3 +- frontend/src/environments/environment.ts | 3 +- frontend/src/styles.scss | 26 +++- 26 files changed, 287 insertions(+), 37 deletions(-) create mode 100644 frontend/src/app/explorer/address/address.component.html create mode 100644 frontend/src/app/explorer/address/address.component.scss create mode 100644 frontend/src/app/explorer/address/address.component.ts create mode 100644 frontend/src/environments/environment-esplora.prod.ts diff --git a/backend/src/index.ts b/backend/src/index.ts index 85ddbb19e..97c1bf92b 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -268,6 +268,7 @@ class MempoolSpace { this.app .get(config.API_ENDPOINT + 'explorer/blocks', routes.getBlocks) .get(config.API_ENDPOINT + 'explorer/blocks/:height', routes.getBlocks) + .get(config.API_ENDPOINT + 'explorer/tx/:id', routes.getRawTransaction) ; } diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 7229b659b..adf3e0daf 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -90,6 +90,15 @@ class Routes { res.status(500).send(e.message); } } + + public async getRawTransaction(req, res) { + try { + const result = await bitcoinApi.getRawTransaction(req.params.id); + res.send(result); + } catch (e) { + res.status(500).send(e.message); + } + } } export default new Routes(); diff --git a/frontend/angular.json b/frontend/angular.json index 8742ea254..378711229 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -48,6 +48,23 @@ "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true + }, + "esplora": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment-esplora.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true } } }, diff --git a/frontend/package.json b/frontend/package.json index 1dd256eb6..59b35dc0a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,7 +5,8 @@ "scripts": { "ng": "ng", "start": "ng serve --aot --proxy-config proxy.conf.json", - "build": "ng build --prod --vendorChunk=false --build-optimizer=true", + "build": "ng build --prod", + "build-esplora": "ng build --prod --configuration=esplora", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" diff --git a/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.scss b/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.scss index 75d226682..8b1378917 100644 --- a/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.scss +++ b/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.scss @@ -1,7 +1 @@ -.yellow-color { - color: #ffd800; -} -.green-color { - color: #3bcc49; -} diff --git a/frontend/src/app/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/blockchain-blocks/blockchain-blocks.component.html index d62f8c838..7a7aedd65 100644 --- a/frontend/src/app/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/blockchain-blocks/blockchain-blocks.component.html @@ -2,7 +2,8 @@
@@ -13,7 +14,7 @@
{{ block.size | bytes: 2 }}
{{ block.nTx }} transactions


-
{{ block.time | timeSince }} ago
+
{{ block.time | timeSince : trigger }} ago
diff --git a/frontend/src/app/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/blockchain-blocks/blockchain-blocks.component.scss index 25b787ba4..a7ef50cd3 100644 --- a/frontend/src/app/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/blockchain-blocks/blockchain-blocks.component.scss @@ -39,10 +39,6 @@ margin-bottom: 2px; } -.yellow-color { - color: #ffd800; -} - .transaction-count { font-size: 12px; } diff --git a/frontend/src/app/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/blockchain-blocks/blockchain-blocks.component.ts index e788e9237..ba1cc0b12 100644 --- a/frontend/src/app/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/blockchain-blocks/blockchain-blocks.component.ts @@ -4,6 +4,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { BlockModalComponent } from './block-modal/block-modal.component'; import { MemPoolService } from '../services/mem-pool.service'; import { Subscription } from 'rxjs'; +import { environment } from '../../environments/environment'; @Component({ selector: 'app-blockchain-blocks', @@ -13,6 +14,9 @@ import { Subscription } from 'rxjs'; export class BlockchainBlocksComponent implements OnInit, OnDestroy { blocks: IBlock[] = []; blocksSubscription: Subscription; + interval: any; + trigger = 0; + isEsploraEnabled = !!environment.esplora; constructor( private modalService: NgbModal, @@ -28,10 +32,13 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { this.blocks.unshift(block); this.blocks = this.blocks.slice(0, 8); }); + + this.interval = setInterval(() => this.trigger++, 10 * 1000); } ngOnDestroy() { this.blocksSubscription.unsubscribe(); + clearInterval(this.interval); } trackByBlocksFn(index: number, item: IBlock) { diff --git a/frontend/src/app/blockchain-projected-blocks/blockchain-projected-blocks.component.scss b/frontend/src/app/blockchain-projected-blocks/blockchain-projected-blocks.component.scss index dc5ce18c4..9400031d4 100644 --- a/frontend/src/app/blockchain-projected-blocks/blockchain-projected-blocks.component.scss +++ b/frontend/src/app/blockchain-projected-blocks/blockchain-projected-blocks.component.scss @@ -49,10 +49,6 @@ margin-bottom: 2px; } -.yellow-color { - color: #ffd800; -} - .transaction-count { font-size: 12px; } diff --git a/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.scss b/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.scss index 75d226682..e69de29bb 100644 --- a/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.scss +++ b/frontend/src/app/blockchain-projected-blocks/projected-block-modal/projected-block-modal.component.scss @@ -1,7 +0,0 @@ -.yellow-color { - color: #ffd800; -} - -.green-color { - color: #3bcc49; -} diff --git a/frontend/src/app/explorer/address/address.component.html b/frontend/src/app/explorer/address/address.component.html new file mode 100644 index 000000000..72b22c183 --- /dev/null +++ b/frontend/src/app/explorer/address/address.component.html @@ -0,0 +1 @@ +

address works!

diff --git a/frontend/src/app/explorer/address/address.component.scss b/frontend/src/app/explorer/address/address.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/explorer/address/address.component.ts b/frontend/src/app/explorer/address/address.component.ts new file mode 100644 index 000000000..563eb98e3 --- /dev/null +++ b/frontend/src/app/explorer/address/address.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-address', + templateUrl: './address.component.html', + styleUrls: ['./address.component.scss'] +}) +export class AddressComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/frontend/src/app/explorer/explorer.module.ts b/frontend/src/app/explorer/explorer.module.ts index b3952d03b..9e020d437 100644 --- a/frontend/src/app/explorer/explorer.module.ts +++ b/frontend/src/app/explorer/explorer.module.ts @@ -5,6 +5,7 @@ import { TransactionComponent } from './transaction/transaction.component'; import { RouterModule, Routes } from '@angular/router'; import { SharedModule } from '../shared/shared.module'; import { BlockComponent } from './block/block.component'; +import { AddressComponent } from './address/address.component'; const routes: Routes = [ { @@ -19,10 +20,14 @@ const routes: Routes = [ path: 'tx/:id', component: TransactionComponent, }, + { + path: 'address/:id', + component: AddressComponent, + }, ]; @NgModule({ - declarations: [ExplorerComponent, TransactionComponent, BlockComponent], + declarations: [ExplorerComponent, TransactionComponent, BlockComponent, AddressComponent], imports: [ SharedModule, CommonModule, diff --git a/frontend/src/app/explorer/transaction/transaction.component.html b/frontend/src/app/explorer/transaction/transaction.component.html index 4873937bc..dbc258801 100644 --- a/frontend/src/app/explorer/transaction/transaction.component.html +++ b/frontend/src/app/explorer/transaction/transaction.component.html @@ -1 +1,143 @@ -

transaction works!

+
+

Transaction

+ + + + + + + + + +
+ {{ tx.txid }} +
+ +
+
+ + + + + + + + +
+
+ + Coinbase + + + {{ vin.prevout.scriptpubkey_address }} + (tx) + +
+
+
+ + + {{ conversions.USD * (vin.prevout.value / 100000000) | currency:'USD':'symbol':'1.2-2' }} + + + {{ vin.prevout.value / 100000000 }} BTC + + +
+
+ +
+
+ + + + + + + + + + +
+
+ {{ vout.scriptpubkey_address }} + + {{ vout.scriptpubkey_type | uppercase }} + +
+
+
+ + {{ conversions.USD * (vout.value / 100000000) | currency:'USD':'symbol':'1.2-2' }} + + + {{ vout.value / 100000000 }} BTC + +
+
+ + + + +   + +
+
+
+
+ +

Details

+ +
+ +
+
+ + + + + + + + + + + + + + + +
Size{{ tx.size | bytes }}
Weight{{ tx.weight }} WU
Included in block#{{ tx.status.block_height }}
+
+
+ + + + + + + + + + + +
Fees{{ tx.fee }} ({{ conversions.USD * tx.fee | currency:'USD':'symbol':'1.2-2' }})
Fees per vByte{{ (tx.fee * 100000000) / tx.vsize | number : '1.2-2' }} sat/vB
+
+
+ +
+ +
+
+

+
+
+
+ \ No newline at end of file diff --git a/frontend/src/app/explorer/transaction/transaction.component.ts b/frontend/src/app/explorer/transaction/transaction.component.ts index 7d3999445..14cb23fb2 100644 --- a/frontend/src/app/explorer/transaction/transaction.component.ts +++ b/frontend/src/app/explorer/transaction/transaction.component.ts @@ -1,4 +1,8 @@ import { Component, OnInit } from '@angular/core'; +import { ApiService } from 'src/app/services/api.service'; +import { ActivatedRoute, ParamMap } from '@angular/router'; +import { switchMap } from 'rxjs/operators'; +import { MemPoolService } from 'src/app/services/mem-pool.service'; @Component({ selector: 'app-transaction', @@ -6,10 +10,41 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./transaction.component.scss'] }) export class TransactionComponent implements OnInit { + tx: any; + isLoadingTx = true; + conversions: any; + totalOutput: number; - constructor() { } + viewFiat = false; + latestBlockHeight: number; + + constructor( + private route: ActivatedRoute, + private apiService: ApiService, + private memPoolService: MemPoolService, + ) { } ngOnInit() { - } + this.route.paramMap.pipe( + switchMap((params: ParamMap) => { + const txId: string = params.get('id') || ''; + return this.apiService.getTransaction$(txId); + }) + ) + .subscribe((tx) => { + this.tx = tx; + this.totalOutput = this.tx.vout.map((v: any) => v.value || 0).reduce((a: number, b: number) => a + b); + this.isLoadingTx = false; + }); + this.memPoolService.conversions$ + .subscribe((conversions) => { + this.conversions = conversions; + }); + + this.memPoolService.blocks$ + .subscribe((block) => { + this.latestBlockHeight = block.height; + }); + } } diff --git a/frontend/src/app/master-page/master-page.component.html b/frontend/src/app/master-page/master-page.component.html index f5c773a67..acaf151e2 100644 --- a/frontend/src/app/master-page/master-page.component.html +++ b/frontend/src/app/master-page/master-page.component.html @@ -18,7 +18,7 @@ -