diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index c7982b75f..79a8e1c02 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -280,7 +280,7 @@ let routes: Routes = [ component: RbfList, }, { - path: 'calculator', + path: 'tools/calculator', component: CalculatorComponent }, { diff --git a/frontend/src/app/components/calculator/calculator.component.html b/frontend/src/app/components/calculator/calculator.component.html index 62026566f..da8e77e79 100644 --- a/frontend/src/app/components/calculator/calculator.component.html +++ b/frontend/src/app/components/calculator/calculator.component.html @@ -3,37 +3,62 @@

Calculator

-
-
+ + +
{{ currency$ | async }}
- +
- +
- +
- +
- +
-
+ +
+ +
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+ Fiat price last updated +
+
+ + +
diff --git a/frontend/src/app/components/calculator/calculator.component.scss b/frontend/src/app/components/calculator/calculator.component.scss index bc3ca2665..649af4934 100644 --- a/frontend/src/app/components/calculator/calculator.component.scss +++ b/frontend/src/app/components/calculator/calculator.component.scss @@ -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; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/calculator/calculator.component.ts b/frontend/src/app/components/calculator/calculator.component.ts index f857bbd8c..838afbbd4 100644 --- a/frontend/src/app/components/calculator/calculator.component.ts +++ b/frontend/src/app/components/calculator/calculator.component.ts @@ -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; price$: Observable; + lastFiatPrice$: Observable; 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}`; + } } diff --git a/frontend/src/app/shared/pipes/bitcoinsatoshis.pipe.ts b/frontend/src/app/shared/pipes/bitcoinsatoshis.pipe.ts new file mode 100644 index 000000000..7065b5138 --- /dev/null +++ b/frontend/src/app/shared/pipes/bitcoinsatoshis.pipe.ts @@ -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( + `${firstPart}${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); + } + +} diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 4a114faa7..c06b1dc8f 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -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,