2023-06-15 12:57:20 -04:00
import { Component , OnInit , ChangeDetectionStrategy , Input , ChangeDetectorRef } from '@angular/core' ;
import { BehaviorSubject , combineLatest , Observable , timer , of } from 'rxjs' ;
import { delayWhen , map , retryWhen , scan , switchMap , tap } from 'rxjs/operators' ;
2022-09-21 17:23:45 +02:00
import { BlockExtended } from '../../interfaces/node-api.interface' ;
import { ApiService } from '../../services/api.service' ;
import { StateService } from '../../services/state.service' ;
import { WebsocketService } from '../../services/websocket.service' ;
2023-08-30 23:59:51 +09:00
import { SeoService } from '../../services/seo.service' ;
import { seoDescriptionNetwork } from '../../shared/common.utils' ;
2022-03-10 18:35:37 +01:00
@Component ( {
selector : 'app-blocks-list' ,
templateUrl : './blocks-list.component.html' ,
styleUrls : [ './blocks-list.component.scss' ] ,
changeDetection : ChangeDetectionStrategy.OnPush ,
} )
2023-06-15 12:57:20 -04:00
export class BlocksList implements OnInit {
2022-03-11 17:09:13 +01:00
@Input ( ) widget : boolean = false ;
2022-06-02 21:55:33 +02:00
blocks$ : Observable < BlockExtended [ ] > = undefined ;
2022-03-11 14:54:34 +01:00
2022-05-20 18:11:02 +02:00
indexingAvailable = false ;
2023-02-12 21:43:12 -06:00
auditAvailable = false ;
2022-03-10 18:35:37 +01:00
isLoading = true ;
2022-03-11 14:54:34 +01:00
fromBlockHeight = undefined ;
paginationMaxSize : number ;
page = 1 ;
2022-03-12 15:55:19 +01:00
lastPage = 1 ;
2022-03-22 15:16:15 +09:00
maxSize = window . innerWidth <= 767.98 ? 3 : 5 ;
2022-03-11 14:54:34 +01:00
blocksCount : number ;
fromHeightSubject : BehaviorSubject < number > = new BehaviorSubject ( this . fromBlockHeight ) ;
2022-03-11 17:09:13 +01:00
skeletonLines : number [ ] = [ ] ;
2022-06-02 21:55:33 +02:00
lastBlockHeight = - 1 ;
2022-03-10 18:35:37 +01:00
constructor (
private apiService : ApiService ,
2022-03-12 15:55:19 +01:00
private websocketService : WebsocketService ,
2022-03-11 14:54:34 +01:00
public stateService : StateService ,
2023-06-14 16:15:58 -04:00
private cd : ChangeDetectorRef ,
2023-08-30 23:59:51 +09:00
private seoService : SeoService ,
2022-03-10 18:35:37 +01:00
) {
}
ngOnInit ( ) : void {
2022-05-20 18:11:02 +02:00
this . indexingAvailable = ( this . stateService . env . BASE_MODULE === 'mempool' &&
this . stateService . env . MINING_DASHBOARD === true ) ;
2023-02-14 12:23:26 -06:00
this . auditAvailable = this . indexingAvailable && this . stateService . env . AUDIT ;
2022-05-20 18:11:02 +02:00
2022-03-19 23:32:01 +04:00
if ( ! this . widget ) {
this . websocketService . want ( [ 'blocks' ] ) ;
}
2022-03-12 15:55:19 +01:00
2022-05-12 17:05:31 +02:00
this . skeletonLines = this . widget === true ? [ . . . Array ( 6 ) . keys ( ) ] : [ . . . Array ( 15 ) . keys ( ) ] ;
2022-03-11 14:54:34 +01:00
this . paginationMaxSize = window . matchMedia ( '(max-width: 670px)' ) . matches ? 3 : 5 ;
2022-03-12 15:55:19 +01:00
2023-08-30 23:59:51 +09:00
this . seoService . setTitle ( $localize ` :@@meta.title.blocks-list:Blocks ` ) ;
if ( this . stateService . network === 'liquid' || this . stateService . network === 'liquidtestnet' ) {
this . seoService . setDescription ( $localize ` :@@meta.description.liquid.blocks:See the most recent Liquid ${ seoDescriptionNetwork ( this . stateService . network ) } blocks along with basic stats such as block height, block size, and more. ` ) ;
} else {
this . seoService . setDescription ( $localize ` :@@meta.description.bitcoin.blocks:See the most recent Bitcoin ${ seoDescriptionNetwork ( this . stateService . network ) } blocks along with basic stats such as block height, block reward, block size, and more. ` ) ;
}
2022-03-12 15:55:19 +01:00
this . blocks $ = combineLatest ( [
this . fromHeightSubject . pipe (
switchMap ( ( fromBlockHeight ) = > {
this . isLoading = true ;
return this . apiService . getBlocks $ ( this . page === 1 ? undefined : fromBlockHeight )
. pipe (
tap ( blocks = > {
if ( this . blocksCount === undefined ) {
2022-03-15 23:49:20 +01:00
this . blocksCount = blocks [ 0 ] . height + 1 ;
2022-03-12 15:55:19 +01:00
}
this . isLoading = false ;
2023-06-15 12:57:20 -04:00
this . lastBlockHeight = Math . max ( . . . blocks . map ( o = > o . height ) ) ;
2022-03-12 15:55:19 +01:00
} ) ,
map ( blocks = > {
2022-05-20 18:11:02 +02:00
if ( this . indexingAvailable ) {
for ( const block of blocks ) {
// @ts-ignore: Need to add an extra field for the template
2022-07-11 13:32:24 +02:00
block . extras . pool . logo = ` /resources/mining-pools/ ` +
2023-07-28 13:45:04 +09:00
block . extras . pool . slug + '.svg' ;
2022-05-20 18:11:02 +02:00
}
2022-03-12 15:55:19 +01:00
}
if ( this . widget ) {
2022-05-12 17:05:31 +02:00
return blocks . slice ( 0 , 6 ) ;
2022-03-12 15:55:19 +01:00
}
return blocks ;
} ) ,
2022-05-20 18:11:02 +02:00
retryWhen ( errors = > errors . pipe ( delayWhen ( ( ) = > timer ( 10000 ) ) ) )
2023-06-15 12:57:20 -04:00
) ;
2022-06-02 21:55:33 +02:00
} )
2022-03-12 15:55:19 +01:00
) ,
this . stateService . blocks $
. pipe (
2023-07-13 11:03:44 +09:00
switchMap ( ( blocks ) = > {
if ( blocks [ 0 ] . height <= this . lastBlockHeight ) {
2023-07-21 18:10:13 +09:00
return of ( [ ] ) ; // Return an empty stream so the last pipe is not executed
2022-06-02 21:55:33 +02:00
}
2023-07-13 11:03:44 +09:00
this . lastBlockHeight = blocks [ 0 ] . height ;
2023-07-20 17:30:26 +09:00
return of ( blocks ) ;
2022-06-02 21:55:33 +02:00
} )
)
2022-03-12 15:55:19 +01:00
] )
. pipe (
scan ( ( acc , blocks ) = > {
if ( this . page > 1 || acc . length === 0 || ( this . page === 1 && this . lastPage !== 1 ) ) {
this . lastPage = this . page ;
return blocks [ 0 ] ;
}
2023-03-10 10:26:30 +09:00
if ( blocks [ 1 ] ) {
this . blocksCount = Math . max ( this . blocksCount , blocks [ 1 ] [ 0 ] . height ) + 1 ;
if ( this . stateService . env . MINING_DASHBOARD ) {
// @ts-ignore: Need to add an extra field for the template
blocks [ 1 ] [ 0 ] . extras . pool . logo = ` /resources/mining-pools/ ` +
2023-07-28 13:45:04 +09:00
blocks [ 1 ] [ 0 ] . extras . pool . slug + '.svg' ;
2023-03-10 10:26:30 +09:00
}
acc . unshift ( blocks [ 1 ] [ 0 ] ) ;
acc = acc . slice ( 0 , this . widget ? 6 : 15 ) ;
2022-05-23 13:02:18 +02:00
}
2022-03-12 15:55:19 +01:00
return acc ;
2023-06-10 12:09:06 -04:00
} , [ ] ) ,
switchMap ( ( blocks ) = > {
blocks . forEach ( block = > {
block . extras . feeDelta = block . extras . expectedFees ? ( block . extras . totalFees - block . extras . expectedFees ) / block.extras.expectedFees : 0 ;
} ) ;
return of ( blocks ) ;
} )
2022-03-12 15:55:19 +01:00
) ;
2022-03-11 14:54:34 +01:00
}
2023-06-15 12:57:20 -04:00
pageChange ( page : number ) : void {
2022-03-15 23:49:20 +01:00
this . fromHeightSubject . next ( ( this . blocksCount - 1 ) - ( page - 1 ) * 15 ) ;
2022-03-10 18:35:37 +01:00
}
2023-06-15 12:57:20 -04:00
trackByBlock ( index : number , block : BlockExtended ) : number {
2022-03-10 18:35:37 +01:00
return block . height ;
}
2022-06-09 15:58:49 +02:00
2023-06-15 12:57:20 -04:00
isEllipsisActive ( e ) : boolean {
2022-06-09 15:58:49 +02:00
return ( e . offsetWidth < e . scrollWidth ) ;
}
2023-08-30 23:59:51 +09:00
}