Calculator visual results
This commit is contained in:
		
							parent
							
								
									510e718ba9
								
							
						
					
					
						commit
						6a524b12fc
					
				@ -280,7 +280,7 @@ let routes: Routes = [
 | 
			
		||||
        component: RbfList,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'calculator',
 | 
			
		||||
        path: 'tools/calculator',
 | 
			
		||||
        component: CalculatorComponent
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
 | 
			
		||||
@ -3,37 +3,62 @@
 | 
			
		||||
    <h2>Calculator</h2>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="row justify-content-md-center" *ngIf="price$ | async; else loading">
 | 
			
		||||
    <div class="col-md-auto">
 | 
			
		||||
  <ng-container *ngIf="price$ | async; else loading">
 | 
			
		||||
 | 
			
		||||
    <div class="row justify-content-center">
 | 
			
		||||
 | 
			
		||||
      <form [formGroup]="form">
 | 
			
		||||
        <div class="input-group input-group-lg mb-1">
 | 
			
		||||
          <div class="input-group-prepend">
 | 
			
		||||
            <span class="input-group-text">{{ currency$ | async }}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <input type="text" class="form-control" formControlName="fiat">
 | 
			
		||||
          <input type="text" class="form-control" formControlName="fiat" (input)="transformInput('fiat')">
 | 
			
		||||
          <app-clipboard [button]="true" [text]="form.get('fiat').value" [class]="'btn btn-lg btn-secondary ml-1'"></app-clipboard>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="input-group input-group-lg mb-1">
 | 
			
		||||
          <div class="input-group-prepend">
 | 
			
		||||
            <span class="input-group-text"><app-svg-images name="bitcoin" width="30" height="30" viewBox="0 0 75 80" style="width: 25px; height: 24px; margin-left: 8px;"></app-svg-images></span>
 | 
			
		||||
            <span class="input-group-text"><app-svg-images name="bitcoin" width="50" height="50" viewBox="0 0 120 120" style="width: 25px; height: 24px; margin-left: 6px;"></app-svg-images></span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <input type="text" class="form-control" formControlName="bitcoin">
 | 
			
		||||
          <input type="text" class="form-control" formControlName="bitcoin" (input)="transformInput('bitcoin')">
 | 
			
		||||
          <app-clipboard [button]="true" [text]="form.get('bitcoin').value" [class]="'btn btn-lg btn-secondary ml-1'"></app-clipboard>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="input-group input-group-lg mb-1">
 | 
			
		||||
          <div class="input-group-prepend">
 | 
			
		||||
            <span class="input-group-text"><app-svg-images name="sats" width="30" height="30" viewBox="-9 0 370 450" style="width: 25px; height: 24px; margin-left: 6px;"></app-svg-images></span>
 | 
			
		||||
            <span class="input-group-text"><app-svg-images name="sats" width="50" height="50" viewBox="-9 0 700 700" style="width: 25px; height: 24px; margin-left: 6px;"></app-svg-images></span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <input type="text" class="form-control" formControlName="satoshis">
 | 
			
		||||
          <input type="text" class="form-control" formControlName="satoshis" (input)="transformInput('satoshis')">
 | 
			
		||||
          <app-clipboard [button]="true" [text]="form.get('satoshis').value" [class]="'btn btn-lg btn-secondary ml-1'"></app-clipboard>
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <div class="row justify-content-center">
 | 
			
		||||
      <div class="bitcoin-satoshis-text">
 | 
			
		||||
        <app-svg-images name="bitcoin" width="40" height="40" viewBox="0 0 75 80" style="width: 25px; height: 24px; margin-right: 4px;"></app-svg-images>
 | 
			
		||||
         <span [innerHTML]="form.get('bitcoin').value | bitcoinsatoshis"></span> 
 | 
			
		||||
        <app-svg-images name="sats" width="40" height="40" viewBox="-9 0 370 450" style="width: 25px; height: 24px; margin-left: 6px;"></app-svg-images>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="row justify-content-center">
 | 
			
		||||
      <div class="fiat-text">
 | 
			
		||||
        <app-fiat [value]="form.get('satoshis').value" digitsInfo="1.0-0"></app-fiat>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="row justify-content-center mt-3">
 | 
			
		||||
      <div class="symbol">
 | 
			
		||||
        Fiat price last updated <app-time kind="since" [time]="lastFiatPrice$ | async" [fastRender]="true"></app-time>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  </ng-container>
 | 
			
		||||
 | 
			
		||||
  <ng-template #loading>
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,21 @@
 | 
			
		||||
.input-group-text {
 | 
			
		||||
  width: 75px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bitcoin-satoshis-text {
 | 
			
		||||
  font-size: 40px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.fiat-text {
 | 
			
		||||
  font-size: 24px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.symbol {
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 767.98px) {
 | 
			
		||||
  .bitcoin-satoshis-text {
 | 
			
		||||
    font-size: 30px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -2,7 +2,6 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
 | 
			
		||||
import { FormBuilder, FormGroup } from '@angular/forms';
 | 
			
		||||
import { combineLatest, Observable } from 'rxjs';
 | 
			
		||||
import { map, switchMap } from 'rxjs/operators';
 | 
			
		||||
import { Price, PriceService } from '../../services/price.service';
 | 
			
		||||
import { StateService } from '../../services/state.service';
 | 
			
		||||
import { WebsocketService } from '../../services/websocket.service';
 | 
			
		||||
 | 
			
		||||
@ -16,13 +15,11 @@ export class CalculatorComponent implements OnInit {
 | 
			
		||||
  satoshis = 10000;
 | 
			
		||||
  form: FormGroup;
 | 
			
		||||
 | 
			
		||||
  currency: string;
 | 
			
		||||
  currency$ = this.stateService.fiatCurrency$;
 | 
			
		||||
  mainSubscription$: Observable<any>;
 | 
			
		||||
  price$: Observable<number>;
 | 
			
		||||
  lastFiatPrice$: Observable<number>;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private priceService: PriceService,
 | 
			
		||||
    private stateService: StateService,
 | 
			
		||||
    private formBuilder: FormBuilder,
 | 
			
		||||
    private websocketService: WebsocketService,
 | 
			
		||||
@ -35,13 +32,19 @@ export class CalculatorComponent implements OnInit {
 | 
			
		||||
      satoshis: [0],
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.lastFiatPrice$ = this.stateService.conversions$.asObservable()
 | 
			
		||||
      .pipe(
 | 
			
		||||
        map((conversions) => conversions.time)
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    let currency;
 | 
			
		||||
    this.price$ = this.currency$.pipe(
 | 
			
		||||
      switchMap((currency) => {
 | 
			
		||||
        this.currency = currency; 
 | 
			
		||||
      switchMap((result) => {
 | 
			
		||||
        currency = result; 
 | 
			
		||||
        return this.stateService.conversions$.asObservable();
 | 
			
		||||
      }),
 | 
			
		||||
      map((conversions) => {
 | 
			
		||||
        return conversions[this.currency];
 | 
			
		||||
        return conversions[currency];
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
@ -49,8 +52,6 @@ export class CalculatorComponent implements OnInit {
 | 
			
		||||
      this.price$,
 | 
			
		||||
      this.form.get('fiat').valueChanges
 | 
			
		||||
    ]).subscribe(([price, value]) => {
 | 
			
		||||
      value = parseFloat(value.replace(',', '.'));
 | 
			
		||||
      value = value || 0;
 | 
			
		||||
      const rate = (value / price).toFixed(8);
 | 
			
		||||
      const satsRate = Math.round(value / price * 100_000_000);
 | 
			
		||||
      this.form.get('bitcoin').setValue(rate, { emitEvent: false });
 | 
			
		||||
@ -61,8 +62,6 @@ export class CalculatorComponent implements OnInit {
 | 
			
		||||
      this.price$,
 | 
			
		||||
      this.form.get('bitcoin').valueChanges
 | 
			
		||||
    ]).subscribe(([price, value]) => {
 | 
			
		||||
      value = parseFloat(value.replace(',', '.'));
 | 
			
		||||
      value = value || 0;
 | 
			
		||||
      const rate = parseFloat((value * price).toFixed(8));
 | 
			
		||||
      this.form.get('fiat').setValue(rate, { emitEvent: false } );
 | 
			
		||||
      this.form.get('satoshis').setValue(Math.round(value * 100_000_000), { emitEvent: false } );
 | 
			
		||||
@ -72,8 +71,6 @@ export class CalculatorComponent implements OnInit {
 | 
			
		||||
      this.price$,
 | 
			
		||||
      this.form.get('satoshis').valueChanges
 | 
			
		||||
    ]).subscribe(([price, value]) => {
 | 
			
		||||
      value = parseFloat(value.replace(',', '.'));
 | 
			
		||||
      value = value || 0;
 | 
			
		||||
      const rate = parseFloat((value / 100_000_000 * price).toFixed(8));
 | 
			
		||||
      const bitcoinRate = (value / 100_000_000).toFixed(8);
 | 
			
		||||
      this.form.get('fiat').setValue(rate, { emitEvent: false } );
 | 
			
		||||
@ -82,4 +79,25 @@ export class CalculatorComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  transformInput(name: string): void {
 | 
			
		||||
    const formControl = this.form.get(name);
 | 
			
		||||
    if (!formControl.value) {
 | 
			
		||||
      return formControl.setValue('', {emitEvent: false});
 | 
			
		||||
    }
 | 
			
		||||
    let value = formControl.value.replace(',', '.').replace(/[^0-9.]/g, '');
 | 
			
		||||
    if (value === '.') {
 | 
			
		||||
      value = '0';
 | 
			
		||||
    }
 | 
			
		||||
    const sanitizedValue = this.removeExtraDots(value);
 | 
			
		||||
    formControl.setValue(sanitizedValue, {emitEvent: true});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removeExtraDots(str: string): string {
 | 
			
		||||
    const [beforeDot, afterDot] = str.split('.', 2);
 | 
			
		||||
    if (afterDot === undefined) {
 | 
			
		||||
      return str;
 | 
			
		||||
    }
 | 
			
		||||
    const afterDotReplaced = afterDot.replace(/\./g, '');
 | 
			
		||||
    return `${beforeDot}.${afterDotReplaced}`;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								frontend/src/app/shared/pipes/bitcoinsatoshis.pipe.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								frontend/src/app/shared/pipes/bitcoinsatoshis.pipe.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
import { Pipe, PipeTransform } from '@angular/core';
 | 
			
		||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
 | 
			
		||||
 | 
			
		||||
@Pipe({
 | 
			
		||||
  name: 'bitcoinsatoshis'
 | 
			
		||||
})
 | 
			
		||||
export class BitcoinsatoshisPipe implements PipeTransform {
 | 
			
		||||
 | 
			
		||||
  constructor(private sanitizer: DomSanitizer) { }
 | 
			
		||||
 | 
			
		||||
  transform(value: string): SafeHtml {
 | 
			
		||||
    const newValue = this.insertSpaces(parseFloat(value || '0').toFixed(8));
 | 
			
		||||
    const position = (newValue || '0').search(/[1-9]/);
 | 
			
		||||
 | 
			
		||||
    const firstPart = newValue.slice(0, position);
 | 
			
		||||
    const secondPart = newValue.slice(position);
 | 
			
		||||
 | 
			
		||||
    return this.sanitizer.bypassSecurityTrustHtml(
 | 
			
		||||
      `<span class="text-secondary">${firstPart}</span>${secondPart}`
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  insertSpaces(str: string): string {
 | 
			
		||||
    const length = str.length;
 | 
			
		||||
    return str.slice(0, length - 6) + ' ' + str.slice(length - 6, length - 3) + ' ' + str.slice(length - 3);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -98,6 +98,7 @@ import { ClockchainComponent } from '../components/clockchain/clockchain.compone
 | 
			
		||||
import { ClockFaceComponent } from '../components/clock-face/clock-face.component';
 | 
			
		||||
import { ClockComponent } from '../components/clock/clock.component';
 | 
			
		||||
import { CalculatorComponent } from '../components/calculator/calculator.component';
 | 
			
		||||
import { BitcoinsatoshisPipe } from '../shared/pipes/bitcoinsatoshis.pipe';
 | 
			
		||||
 | 
			
		||||
import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-directives/weight-directives';
 | 
			
		||||
 | 
			
		||||
@ -190,9 +191,11 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
 | 
			
		||||
    MempoolBlockOverviewComponent,
 | 
			
		||||
    ClockchainComponent,
 | 
			
		||||
    ClockComponent,
 | 
			
		||||
    CalculatorComponent,
 | 
			
		||||
    ClockFaceComponent,
 | 
			
		||||
    OnlyVsizeDirective,
 | 
			
		||||
    OnlyWeightDirective
 | 
			
		||||
    OnlyWeightDirective,
 | 
			
		||||
    BitcoinsatoshisPipe
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user