Calculator visual results
This commit is contained in:
parent
67a998c69f
commit
120c27d120
@ -280,7 +280,7 @@ let routes: Routes = [
|
|||||||
component: RbfList,
|
component: RbfList,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'calculator',
|
path: 'tools/calculator',
|
||||||
component: CalculatorComponent
|
component: CalculatorComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3,37 +3,62 @@
|
|||||||
<h2>Calculator</h2>
|
<h2>Calculator</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row justify-content-md-center" *ngIf="price$ | async; else loading">
|
<ng-container *ngIf="price$ | async; else loading">
|
||||||
<div class="col-md-auto">
|
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
|
||||||
<form [formGroup]="form">
|
<form [formGroup]="form">
|
||||||
<div class="input-group input-group-lg mb-1">
|
<div class="input-group input-group-lg mb-1">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text">{{ currency$ | async }}</span>
|
<span class="input-group-text">{{ currency$ | async }}</span>
|
||||||
</div>
|
</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>
|
<app-clipboard [button]="true" [text]="form.get('fiat').value" [class]="'btn btn-lg btn-secondary ml-1'"></app-clipboard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group input-group-lg mb-1">
|
<div class="input-group input-group-lg mb-1">
|
||||||
<div class="input-group-prepend">
|
<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>
|
</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>
|
<app-clipboard [button]="true" [text]="form.get('bitcoin').value" [class]="'btn btn-lg btn-secondary ml-1'"></app-clipboard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group input-group-lg mb-1">
|
<div class="input-group input-group-lg mb-1">
|
||||||
<div class="input-group-prepend">
|
<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>
|
</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>
|
<app-clipboard [button]="true" [text]="form.get('satoshis').value" [class]="'btn btn-lg btn-secondary ml-1'"></app-clipboard>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</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>
|
<ng-template #loading>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
.input-group-text {
|
.input-group-text {
|
||||||
width: 75px;
|
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 { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { combineLatest, Observable } from 'rxjs';
|
import { combineLatest, Observable } from 'rxjs';
|
||||||
import { map, switchMap } from 'rxjs/operators';
|
import { map, switchMap } from 'rxjs/operators';
|
||||||
import { Price, PriceService } from '../../services/price.service';
|
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
import { WebsocketService } from '../../services/websocket.service';
|
import { WebsocketService } from '../../services/websocket.service';
|
||||||
|
|
||||||
@ -16,13 +15,11 @@ export class CalculatorComponent implements OnInit {
|
|||||||
satoshis = 10000;
|
satoshis = 10000;
|
||||||
form: FormGroup;
|
form: FormGroup;
|
||||||
|
|
||||||
currency: string;
|
|
||||||
currency$ = this.stateService.fiatCurrency$;
|
currency$ = this.stateService.fiatCurrency$;
|
||||||
mainSubscription$: Observable<any>;
|
|
||||||
price$: Observable<number>;
|
price$: Observable<number>;
|
||||||
|
lastFiatPrice$: Observable<number>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private priceService: PriceService,
|
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private websocketService: WebsocketService,
|
private websocketService: WebsocketService,
|
||||||
@ -35,13 +32,19 @@ export class CalculatorComponent implements OnInit {
|
|||||||
satoshis: [0],
|
satoshis: [0],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.lastFiatPrice$ = this.stateService.conversions$.asObservable()
|
||||||
|
.pipe(
|
||||||
|
map((conversions) => conversions.time)
|
||||||
|
);
|
||||||
|
|
||||||
|
let currency;
|
||||||
this.price$ = this.currency$.pipe(
|
this.price$ = this.currency$.pipe(
|
||||||
switchMap((currency) => {
|
switchMap((result) => {
|
||||||
this.currency = currency;
|
currency = result;
|
||||||
return this.stateService.conversions$.asObservable();
|
return this.stateService.conversions$.asObservable();
|
||||||
}),
|
}),
|
||||||
map((conversions) => {
|
map((conversions) => {
|
||||||
return conversions[this.currency];
|
return conversions[currency];
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -49,8 +52,6 @@ export class CalculatorComponent implements OnInit {
|
|||||||
this.price$,
|
this.price$,
|
||||||
this.form.get('fiat').valueChanges
|
this.form.get('fiat').valueChanges
|
||||||
]).subscribe(([price, value]) => {
|
]).subscribe(([price, value]) => {
|
||||||
value = parseFloat(value.replace(',', '.'));
|
|
||||||
value = value || 0;
|
|
||||||
const rate = (value / price).toFixed(8);
|
const rate = (value / price).toFixed(8);
|
||||||
const satsRate = Math.round(value / price * 100_000_000);
|
const satsRate = Math.round(value / price * 100_000_000);
|
||||||
this.form.get('bitcoin').setValue(rate, { emitEvent: false });
|
this.form.get('bitcoin').setValue(rate, { emitEvent: false });
|
||||||
@ -61,8 +62,6 @@ export class CalculatorComponent implements OnInit {
|
|||||||
this.price$,
|
this.price$,
|
||||||
this.form.get('bitcoin').valueChanges
|
this.form.get('bitcoin').valueChanges
|
||||||
]).subscribe(([price, value]) => {
|
]).subscribe(([price, value]) => {
|
||||||
value = parseFloat(value.replace(',', '.'));
|
|
||||||
value = value || 0;
|
|
||||||
const rate = parseFloat((value * price).toFixed(8));
|
const rate = parseFloat((value * price).toFixed(8));
|
||||||
this.form.get('fiat').setValue(rate, { emitEvent: false } );
|
this.form.get('fiat').setValue(rate, { emitEvent: false } );
|
||||||
this.form.get('satoshis').setValue(Math.round(value * 100_000_000), { 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.price$,
|
||||||
this.form.get('satoshis').valueChanges
|
this.form.get('satoshis').valueChanges
|
||||||
]).subscribe(([price, value]) => {
|
]).subscribe(([price, value]) => {
|
||||||
value = parseFloat(value.replace(',', '.'));
|
|
||||||
value = value || 0;
|
|
||||||
const rate = parseFloat((value / 100_000_000 * price).toFixed(8));
|
const rate = parseFloat((value / 100_000_000 * price).toFixed(8));
|
||||||
const bitcoinRate = (value / 100_000_000).toFixed(8);
|
const bitcoinRate = (value / 100_000_000).toFixed(8);
|
||||||
this.form.get('fiat').setValue(rate, { emitEvent: false } );
|
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 { ClockFaceComponent } from '../components/clock-face/clock-face.component';
|
||||||
import { ClockComponent } from '../components/clock/clock.component';
|
import { ClockComponent } from '../components/clock/clock.component';
|
||||||
import { CalculatorComponent } from '../components/calculator/calculator.component';
|
import { CalculatorComponent } from '../components/calculator/calculator.component';
|
||||||
|
import { BitcoinsatoshisPipe } from '../shared/pipes/bitcoinsatoshis.pipe';
|
||||||
|
|
||||||
import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-directives/weight-directives';
|
import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-directives/weight-directives';
|
||||||
|
|
||||||
@ -190,9 +191,11 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
|||||||
MempoolBlockOverviewComponent,
|
MempoolBlockOverviewComponent,
|
||||||
ClockchainComponent,
|
ClockchainComponent,
|
||||||
ClockComponent,
|
ClockComponent,
|
||||||
|
CalculatorComponent,
|
||||||
ClockFaceComponent,
|
ClockFaceComponent,
|
||||||
OnlyVsizeDirective,
|
OnlyVsizeDirective,
|
||||||
OnlyWeightDirective
|
OnlyWeightDirective,
|
||||||
|
BitcoinsatoshisPipe
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user