Redesign top of address page
This commit is contained in:
		
							parent
							
								
									746a045c48
								
							
						
					
					
						commit
						9514bb703b
					
				| @ -4,7 +4,7 @@ | |||||||
|       <a [routerLink]="['/lightning/channel' | relativeUrl, channel.id]"> |       <a [routerLink]="['/lightning/channel' | relativeUrl, channel.id]"> | ||||||
|         <span  |         <span  | ||||||
|           *ngIf="label" |           *ngIf="label" | ||||||
|           class="badge badge-pill badge-warning" |           class="badge badge-pill badge-warning {{ class }}" | ||||||
|         >{{ label }}</span> |         >{{ label }}</span> | ||||||
|       </a> |       </a> | ||||||
|     </div> |     </div> | ||||||
| @ -15,6 +15,6 @@ | |||||||
| <ng-template #default> | <ng-template #default> | ||||||
|   <span |   <span | ||||||
|     *ngIf="label" |     *ngIf="label" | ||||||
|     class="badge badge-pill badge-warning" |     class="badge badge-pill badge-warning {{ class }}" | ||||||
|   >{{ label }}</span> |   >{{ label }}</span> | ||||||
| </ng-template> | </ng-template> | ||||||
| @ -15,6 +15,7 @@ export class AddressLabelsComponent implements OnChanges { | |||||||
|   @Input() vin: Vin; |   @Input() vin: Vin; | ||||||
|   @Input() vout: Vout; |   @Input() vout: Vout; | ||||||
|   @Input() channel: any; |   @Input() channel: any; | ||||||
|  |   @Input() class: string = ''; | ||||||
| 
 | 
 | ||||||
|   label?: string; |   label?: string; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,40 +14,39 @@ | |||||||
|     <div class="box"> |     <div class="box"> | ||||||
| 
 | 
 | ||||||
|       <div class="row"> |       <div class="row"> | ||||||
|         <div class="col-md"> |         @if (isMobile) { | ||||||
|           <table class="table table-borderless table-striped address-table"> |           <div class="col-sm"> | ||||||
|  |             <table class="table table-borderless table-striped"> | ||||||
|               <tbody> |               <tbody> | ||||||
|               <tr *ngIf="addressInfo && addressInfo.unconfidential"> |                 <ng-container *ngTemplateOutlet="balanceRow"></ng-container> | ||||||
|                 <td i18n="address.unconfidential">Unconfidential</td> |                 <ng-container *ngTemplateOutlet="pendingBalanceRow"></ng-container> | ||||||
|                 <td> |                 <ng-container *ngTemplateOutlet="utxoRow"></ng-container> | ||||||
|                   <app-truncate [text]="addressInfo.unconfidential" [lastChars]="8" [link]="['/address/' | relativeUrl, addressInfo.unconfidential]"> |                 <ng-container *ngTemplateOutlet="pendingUtxoRow"></ng-container> | ||||||
|                     <app-clipboard [text]="addressInfo.unconfidential"></app-clipboard> |                 <ng-container *ngTemplateOutlet="volumeRow"></ng-container> | ||||||
|                   </app-truncate> |                 <ng-container *ngTemplateOutlet="typeRow"></ng-container> | ||||||
|                 </td> |  | ||||||
|               </tr> |  | ||||||
|               <ng-template [ngIf]="!address.electrum"> |  | ||||||
|                 <tr> |  | ||||||
|                   <td i18n="address.total-received">Total received</td> |  | ||||||
|                   <td *ngIf="address.chain_stats.funded_txo_sum !== undefined; else confidentialTd"><app-amount [satoshis]="chainStats.funded_txo_sum + mempoolStats.funded_txo_sum" [noFiat]="true"></app-amount></td> |  | ||||||
|                 </tr> |  | ||||||
|                 <tr> |  | ||||||
|                   <td i18n="address.total-sent">Total sent</td> |  | ||||||
|                   <td *ngIf="address.chain_stats.spent_txo_sum !== undefined; else confidentialTd"><app-amount [satoshis]="chainStats.spent_txo_sum + mempoolStats.spent_txo_sum" [noFiat]="true"></app-amount></td> |  | ||||||
|                 </tr> |  | ||||||
|               </ng-template> |  | ||||||
|               <tr> |  | ||||||
|                 <td i18n="address.balance">Balance</td> |  | ||||||
|                 <td *ngIf="address.chain_stats.funded_txo_sum !== undefined; else confidentialTd"><app-amount [satoshis]="chainStats.balance + mempoolStats.balance" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="chainStats.balance + mempoolStats.balance"></app-fiat></span></td> |  | ||||||
|               </tr> |  | ||||||
|               </tbody> |               </tbody> | ||||||
|             </table> |             </table> | ||||||
|           </div> |           </div> | ||||||
|         <div class="w-100 d-block d-md-none"></div> |         } @else { | ||||||
|         <div class="col-md qrcode-col"> |           <div class="col-sm"> | ||||||
|           <div class="qr-wrapper"> |             <table class="table table-borderless table-striped"> | ||||||
|             <app-qrcode [data]="address.address"></app-qrcode> |               <tbody> | ||||||
|  |                 <ng-container *ngTemplateOutlet="balanceRow"></ng-container> | ||||||
|  |                 <ng-container *ngTemplateOutlet="utxoRow"></ng-container> | ||||||
|  |                 <ng-container *ngTemplateOutlet="volumeRow"></ng-container> | ||||||
|  |               </tbody> | ||||||
|  |             </table> | ||||||
|           </div> |           </div> | ||||||
|  |           <div class="col-sm"> | ||||||
|  |             <table class="table table-borderless table-striped"> | ||||||
|  |               <tbody> | ||||||
|  |                 <ng-container *ngTemplateOutlet="pendingBalanceRow"></ng-container> | ||||||
|  |                 <ng-container *ngTemplateOutlet="pendingUtxoRow"></ng-container> | ||||||
|  |                 <ng-container *ngTemplateOutlet="typeRow"></ng-container> | ||||||
|  |               </tbody> | ||||||
|  |             </table> | ||||||
|           </div> |           </div> | ||||||
|  |         } | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
| @ -182,3 +181,57 @@ | |||||||
|     <span class="skeleton-loader"></span> |     <span class="skeleton-loader"></span> | ||||||
|   </div> |   </div> | ||||||
| </ng-template> | </ng-template> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | <ng-template #balanceRow> | ||||||
|  |   <tr> | ||||||
|  |     <td i18n="address.balance">Balance</td> | ||||||
|  |     <td *ngIf="chainStats.funded_txo_sum !== undefined; else confidentialTd"><app-amount [satoshis]="chainStats.balance" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="chainStats.balance"></app-fiat></span></td> | ||||||
|  |   </tr> | ||||||
|  | </ng-template> | ||||||
|  | 
 | ||||||
|  | <ng-template #pendingBalanceRow> | ||||||
|  |   <tr> | ||||||
|  |     <td i18n="address.pending" class="font-italic">pending</td> | ||||||
|  |     <td *ngIf="mempoolStats.funded_txo_sum !== undefined; else confidentialTd" class="font-italic"><app-amount [satoshis]="mempoolStats.balance" [noFiat]="true" [addPlus]="true"></app-amount> <span class="fiat"><app-fiat [value]="mempoolStats.balance"></app-fiat></span></td> | ||||||
|  |   </tr> | ||||||
|  | </ng-template> | ||||||
|  | 
 | ||||||
|  | <ng-template #utxoRow> | ||||||
|  |   <tr> | ||||||
|  |     <td i18n="address.unspent_txos">Unspent TXOs</td> | ||||||
|  |     <td>{{ chainStats.utxos }}</td> | ||||||
|  |   </tr> | ||||||
|  | </ng-template> | ||||||
|  | 
 | ||||||
|  | <ng-template #pendingUtxoRow> | ||||||
|  |   <tr> | ||||||
|  |     <td i18n="address.pending" class="font-italic">pending</td> | ||||||
|  |     <td class="font-italic">{{ mempoolStats.utxos > 0 ? '+' : ''}}{{ mempoolStats.utxos }}</td> | ||||||
|  |   </tr> | ||||||
|  | </ng-template> | ||||||
|  | 
 | ||||||
|  | <ng-template #volumeRow> | ||||||
|  |   <tr> | ||||||
|  |     <td i18n="address.volume">Volume</td> | ||||||
|  |     <td><app-amount [satoshis]="chainStats.volume + mempoolStats.volume"></app-amount></td> | ||||||
|  |   </tr> | ||||||
|  | </ng-template> | ||||||
|  | 
 | ||||||
|  | <ng-template #typeRow> | ||||||
|  |   <tr> | ||||||
|  |     <td i18n="address.type">Type</td> | ||||||
|  |     <td><app-address-type [vout]="exampleVout || exampleVin?.prevout || null"></app-address-type><app-address-labels [channel]="exampleChannel" [vin]="exampleVin" [vout]="exampleVout" class="ml-1"></app-address-labels></td> | ||||||
|  |   </tr> | ||||||
|  | </ng-template> | ||||||
|  | 
 | ||||||
|  | <ng-template #liquidRow> | ||||||
|  |   <tr *ngIf="addressInfo && addressInfo.unconfidential"> | ||||||
|  |     <td i18n="address.unconfidential">Unconfidential</td> | ||||||
|  |     <td> | ||||||
|  |       <app-truncate [text]="addressInfo.unconfidential" [lastChars]="8" [link]="['/address/' | relativeUrl, addressInfo.unconfidential]"> | ||||||
|  |         <app-clipboard [text]="addressInfo.unconfidential"></app-clipboard> | ||||||
|  |       </app-truncate> | ||||||
|  |     </td> | ||||||
|  |   </tr> | ||||||
|  | </ng-template> | ||||||
| @ -25,7 +25,7 @@ | |||||||
|   tr td { |   tr td { | ||||||
|     &:last-child { |     &:last-child { | ||||||
|       text-align: right; |       text-align: right; | ||||||
|       @media (min-width: 576px) { |       @media (min-width: 768px) { | ||||||
|         text-align: left; |         text-align: left; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| import { Component, OnInit, OnDestroy } from '@angular/core'; | import { Component, OnInit, OnDestroy, HostListener } from '@angular/core'; | ||||||
| import { ActivatedRoute, ParamMap } from '@angular/router'; | import { ActivatedRoute, ParamMap } from '@angular/router'; | ||||||
| import { ElectrsApiService } from '../../services/electrs-api.service'; | import { ElectrsApiService } from '../../services/electrs-api.service'; | ||||||
| import { switchMap, filter, catchError, map, tap } from 'rxjs/operators'; | import { switchMap, filter, catchError, map, tap } from 'rxjs/operators'; | ||||||
| import { Address, ChainStats, Transaction } from '../../interfaces/electrs.interface'; | import { Address, ChainStats, Transaction, Vin, Vout } from '../../interfaces/electrs.interface'; | ||||||
| import { WebsocketService } from '../../services/websocket.service'; | import { WebsocketService } from '../../services/websocket.service'; | ||||||
| import { StateService } from '../../services/state.service'; | import { StateService } from '../../services/state.service'; | ||||||
| import { AudioService } from '../../services/audio.service'; | import { AudioService } from '../../services/audio.service'; | ||||||
| @ -79,6 +79,10 @@ class AddressStats implements ChainStats { | |||||||
|     return this.funded_txo_sum - this.spent_txo_sum; |     return this.funded_txo_sum - this.spent_txo_sum; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   get volume(): number { | ||||||
|  |     return this.funded_txo_sum + this.spent_txo_sum; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   get utxos(): number { |   get utxos(): number { | ||||||
|     return this.funded_txo_count - this.spent_txo_count; |     return this.funded_txo_count - this.spent_txo_count; | ||||||
|   } |   } | ||||||
| @ -92,6 +96,8 @@ class AddressStats implements ChainStats { | |||||||
| export class AddressComponent implements OnInit, OnDestroy { | export class AddressComponent implements OnInit, OnDestroy { | ||||||
|   network = ''; |   network = ''; | ||||||
| 
 | 
 | ||||||
|  |   isMobile: boolean; | ||||||
|  | 
 | ||||||
|   address: Address; |   address: Address; | ||||||
|   addressString: string; |   addressString: string; | ||||||
|   isLoadingAddress = true; |   isLoadingAddress = true; | ||||||
| @ -110,6 +116,10 @@ export class AddressComponent implements OnInit, OnDestroy { | |||||||
|   chainStats: AddressStats; |   chainStats: AddressStats; | ||||||
|   mempoolStats: AddressStats; |   mempoolStats: AddressStats; | ||||||
| 
 | 
 | ||||||
|  |   exampleChannel?: any; | ||||||
|  |   exampleVin?: Vin; | ||||||
|  |   exampleVout?: Vout; | ||||||
|  | 
 | ||||||
|   now = Date.now() / 1000; |   now = Date.now() / 1000; | ||||||
|   balancePeriod: 'all' | '1m' = 'all'; |   balancePeriod: 'all' | '1m' = 'all'; | ||||||
| 
 | 
 | ||||||
| @ -147,6 +157,9 @@ export class AddressComponent implements OnInit, OnDestroy { | |||||||
|           this.isLoadingTransactions = true; |           this.isLoadingTransactions = true; | ||||||
|           this.transactions = null; |           this.transactions = null; | ||||||
|           this.addressInfo = null; |           this.addressInfo = null; | ||||||
|  |           this.exampleChannel = null; | ||||||
|  |           this.exampleVin = null; | ||||||
|  |           this.exampleVout = null; | ||||||
|           document.body.scrollTo(0, 0); |           document.body.scrollTo(0, 0); | ||||||
|           this.addressString = params.get('id') || ''; |           this.addressString = params.get('id') || ''; | ||||||
|           if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(this.addressString)) { |           if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(this.addressString)) { | ||||||
| @ -252,6 +265,18 @@ export class AddressComponent implements OnInit, OnDestroy { | |||||||
|         } |         } | ||||||
|         this.isLoadingTransactions = false; |         this.isLoadingTransactions = false; | ||||||
| 
 | 
 | ||||||
|  |         for (const tx of this.transactions) { | ||||||
|  |           if (!this.exampleVin) { | ||||||
|  |             this.exampleVin = tx.vin.find(v => v.prevout?.scriptpubkey_address === this.address.address); | ||||||
|  |           } | ||||||
|  |           if (!this.exampleVout) { | ||||||
|  |             this.exampleVout = tx.vout.find(v => v.scriptpubkey_address === this.address.address); | ||||||
|  |           } | ||||||
|  |           if (this.exampleVin && this.exampleVout) { | ||||||
|  |             break; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (!this.showBalancePeriod()) { |         if (!this.showBalancePeriod()) { | ||||||
|           this.setBalancePeriod('all'); |           this.setBalancePeriod('all'); | ||||||
|         } else { |         } else { | ||||||
| @ -370,6 +395,11 @@ export class AddressComponent implements OnInit, OnDestroy { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   @HostListener('window:resize', ['$event']) | ||||||
|  |   onResize(): void { | ||||||
|  |     this.isMobile = window.innerWidth < 768; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   ngOnDestroy(): void { |   ngOnDestroy(): void { | ||||||
|     this.mainSubscription.unsubscribe(); |     this.mainSubscription.unsubscribe(); | ||||||
|     this.mempoolTxSubscription.unsubscribe(); |     this.mempoolTxSubscription.unsubscribe(); | ||||||
|  | |||||||
| @ -0,0 +1,29 @@ | |||||||
|  | @switch (vout?.scriptpubkey_type || null) { | ||||||
|  |   @case ('fee') { | ||||||
|  |     <span i18n="address.fee">fee</span> | ||||||
|  |   } | ||||||
|  |   @case ('empty') { | ||||||
|  |     <span i18n="address.empty">empty</span> | ||||||
|  |   } | ||||||
|  |   @case ('v0_p2wpkh') { | ||||||
|  |     <span>P2WPKH</span> | ||||||
|  |   } | ||||||
|  |   @case ('v0_p2wsh') { | ||||||
|  |     <span>P2WSH</span> | ||||||
|  |   } | ||||||
|  |   @case ('v1_p2tr') { | ||||||
|  |     <span>P2TR</span> | ||||||
|  |   } | ||||||
|  |   @case ('provably_unspendable') { | ||||||
|  |     <span i18n="address.provably-unspendable">provably unspendable</span> | ||||||
|  |   } | ||||||
|  |   @case ('multisig') { | ||||||
|  |     <span i18n="address.bare-multisig">bare multisig</span> | ||||||
|  |   } | ||||||
|  |   @case (null) { | ||||||
|  |     <span>unknown</span> | ||||||
|  |   } | ||||||
|  |   @default { | ||||||
|  |     <span>{{ vout.scriptpubkey_type.toUpperCase() }}</span> | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,11 @@ | |||||||
|  | import { Component, Input } from '@angular/core'; | ||||||
|  | import { Vout } from '../../../interfaces/electrs.interface'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |   selector: 'app-address-type', | ||||||
|  |   templateUrl: './address-type.component.html', | ||||||
|  |   styleUrls: [] | ||||||
|  | }) | ||||||
|  | export class AddressTypeComponent { | ||||||
|  |   @Input() vout: Vout; | ||||||
|  | } | ||||||
| @ -87,6 +87,7 @@ import { ChangeComponent } from '../components/change/change.component'; | |||||||
| import { SatsComponent } from './components/sats/sats.component'; | import { SatsComponent } from './components/sats/sats.component'; | ||||||
| import { BtcComponent } from './components/btc/btc.component'; | import { BtcComponent } from './components/btc/btc.component'; | ||||||
| import { FeeRateComponent } from './components/fee-rate/fee-rate.component'; | import { FeeRateComponent } from './components/fee-rate/fee-rate.component'; | ||||||
|  | import { AddressTypeComponent } from './components/address-type/address-type.component'; | ||||||
| import { TruncateComponent } from './components/truncate/truncate.component'; | import { TruncateComponent } from './components/truncate/truncate.component'; | ||||||
| import { SearchResultsComponent } from '../components/search-form/search-results/search-results.component'; | import { SearchResultsComponent } from '../components/search-form/search-results/search-results.component'; | ||||||
| import { TimestampComponent } from './components/timestamp/timestamp.component'; | import { TimestampComponent } from './components/timestamp/timestamp.component'; | ||||||
| @ -202,6 +203,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir | |||||||
|     SatsComponent, |     SatsComponent, | ||||||
|     BtcComponent, |     BtcComponent, | ||||||
|     FeeRateComponent, |     FeeRateComponent, | ||||||
|  |     AddressTypeComponent, | ||||||
|     TruncateComponent, |     TruncateComponent, | ||||||
|     SearchResultsComponent, |     SearchResultsComponent, | ||||||
|     TimestampComponent, |     TimestampComponent, | ||||||
| @ -343,6 +345,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir | |||||||
|     SatsComponent, |     SatsComponent, | ||||||
|     BtcComponent, |     BtcComponent, | ||||||
|     FeeRateComponent, |     FeeRateComponent, | ||||||
|  |     AddressTypeComponent, | ||||||
|     TruncateComponent, |     TruncateComponent, | ||||||
|     SearchResultsComponent, |     SearchResultsComponent, | ||||||
|     TimestampComponent, |     TimestampComponent, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user