From c2ff6a996ab447dae6a971205ecaa4e091724964 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 3 Jan 2023 11:58:09 -0600 Subject: [PATCH] Multi-currency fiat formatting pipes & components --- frontend/src/app/app.module.ts | 2 ++ frontend/src/app/fiat/fiat.component.html | 2 +- frontend/src/app/fiat/fiat.component.ts | 20 ++++++++++--- .../app/shared/pipes/fiat-currency.pipe.ts | 28 +++++++++++++++++++ .../app/shared/pipes/fiat-shortener.pipe.ts | 22 +++++++++++---- frontend/src/app/shared/shared.module.ts | 3 ++ 6 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 frontend/src/app/shared/pipes/fiat-currency.pipe.ts diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index b7bd1526f..f26b4a924 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -17,6 +17,7 @@ import { StorageService } from './services/storage.service'; import { HttpCacheInterceptor } from './services/http-cache.interceptor'; import { LanguageService } from './services/language.service'; import { FiatShortenerPipe } from './shared/pipes/fiat-shortener.pipe'; +import { FiatCurrencyPipe } from './shared/pipes/fiat-currency.pipe'; import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe'; import { CapAddressPipe } from './shared/pipes/cap-address-pipe/cap-address-pipe'; import { AppPreloadingStrategy } from './app.preloading-strategy'; @@ -34,6 +35,7 @@ const providers = [ LanguageService, ShortenStringPipe, FiatShortenerPipe, + FiatCurrencyPipe, CapAddressPipe, AppPreloadingStrategy, { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true } diff --git a/frontend/src/app/fiat/fiat.component.html b/frontend/src/app/fiat/fiat.component.html index 19a5c8aa0..1adde8120 100644 --- a/frontend/src/app/fiat/fiat.component.html +++ b/frontend/src/app/fiat/fiat.component.html @@ -1 +1 @@ -{{ (conversions$ | async)?.USD * value / 100000000 | currency:'USD':'symbol':digitsInfo }} \ No newline at end of file +{{ (conversions$ | async)[currency] * value / 100000000 | fiatCurrency : digitsInfo : currency }} \ No newline at end of file diff --git a/frontend/src/app/fiat/fiat.component.ts b/frontend/src/app/fiat/fiat.component.ts index 9d22355d8..bc0f6a0de 100644 --- a/frontend/src/app/fiat/fiat.component.ts +++ b/frontend/src/app/fiat/fiat.component.ts @@ -1,5 +1,5 @@ -import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnDestroy } from '@angular/core'; +import { Observable, Subscription } from 'rxjs'; import { StateService } from '../services/state.service'; @Component({ @@ -8,18 +8,30 @@ import { StateService } from '../services/state.service'; styleUrls: ['./fiat.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class FiatComponent implements OnInit { +export class FiatComponent implements OnInit, OnDestroy { conversions$: Observable; + currencySubscription: Subscription; + currency: string; @Input() value: number; @Input() digitsInfo = '1.2-2'; constructor( private stateService: StateService, - ) { } + private cd: ChangeDetectorRef, + ) { + this.currencySubscription = this.stateService.fiatCurrency$.subscribe((fiat) => { + this.currency = fiat; + this.cd.markForCheck(); + }); + } ngOnInit(): void { this.conversions$ = this.stateService.conversions$.asObservable(); } + ngOnDestroy(): void { + this.currencySubscription.unsubscribe(); + } + } diff --git a/frontend/src/app/shared/pipes/fiat-currency.pipe.ts b/frontend/src/app/shared/pipes/fiat-currency.pipe.ts new file mode 100644 index 000000000..3cd825291 --- /dev/null +++ b/frontend/src/app/shared/pipes/fiat-currency.pipe.ts @@ -0,0 +1,28 @@ +import { formatCurrency, getCurrencySymbol } from '@angular/common'; +import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { StateService } from '../../services/state.service'; + +@Pipe({ + name: 'fiatCurrency' +}) +export class FiatCurrencyPipe implements PipeTransform { + fiatSubscription: Subscription; + currency: string; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private stateService: StateService, + ) { + this.fiatSubscription = this.stateService.fiatCurrency$.subscribe((fiat) => { + this.currency = fiat; + }); + } + + transform(num: number, ...args: any[]): unknown { + const digits = args[0] || 1; + const currency = args[1] || this.currency || 'USD'; + + return new Intl.NumberFormat(this.locale, { style: 'currency', currency }).format(num); + } +} \ No newline at end of file diff --git a/frontend/src/app/shared/pipes/fiat-shortener.pipe.ts b/frontend/src/app/shared/pipes/fiat-shortener.pipe.ts index 8c534f93f..93ab5cf8f 100644 --- a/frontend/src/app/shared/pipes/fiat-shortener.pipe.ts +++ b/frontend/src/app/shared/pipes/fiat-shortener.pipe.ts @@ -1,20 +1,30 @@ import { formatCurrency, getCurrencySymbol } from '@angular/common'; import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { StateService } from '../../services/state.service'; @Pipe({ name: 'fiatShortener' }) export class FiatShortenerPipe implements PipeTransform { + fiatSubscription: Subscription; + currency: string; + constructor( - @Inject(LOCALE_ID) public locale: string - ) {} + @Inject(LOCALE_ID) public locale: string, + private stateService: StateService, + ) { + this.fiatSubscription = this.stateService.fiatCurrency$.subscribe((fiat) => { + this.currency = fiat; + }); + } transform(num: number, ...args: any[]): unknown { const digits = args[0] || 1; - const unit = args[1] || undefined; + const currency = args[1] || this.currency || 'USD'; if (num < 1000) { - return num.toFixed(digits); + return new Intl.NumberFormat(this.locale, { style: 'currency', currency, maximumFractionDigits: 1 }).format(num); } const lookup = [ @@ -30,8 +40,8 @@ export class FiatShortenerPipe implements PipeTransform { const item = lookup.slice().reverse().find((item) => num >= item.value); let result = item ? (num / item.value).toFixed(digits).replace(rx, '$1') : '0'; - result = formatCurrency(parseInt(result, 10), this.locale, getCurrencySymbol('USD', 'narrow'), 'USD', '1.0-0'); - + result = new Intl.NumberFormat(this.locale, { style: 'currency', currency, maximumFractionDigits: 0 }).format(item ? num / item.value : 0); + return result + item.symbol; } } \ No newline at end of file diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index e87107fe5..fd257db85 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -23,6 +23,7 @@ import { RelativeUrlPipe } from './pipes/relative-url/relative-url.pipe'; import { ScriptpubkeyTypePipe } from './pipes/scriptpubkey-type-pipe/scriptpubkey-type.pipe'; import { BytesPipe } from './pipes/bytes-pipe/bytes.pipe'; import { WuBytesPipe } from './pipes/bytes-pipe/wubytes.pipe'; +import { FiatCurrencyPipe } from './pipes/fiat-currency.pipe'; import { BlockchainComponent } from '../components/blockchain/blockchain.component'; import { TimeSinceComponent } from '../components/time-since/time-since.component'; import { TimeUntilComponent } from '../components/time-until/time-until.component'; @@ -109,6 +110,7 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati CapAddressPipe, Decimal2HexPipe, FeeRoundingPipe, + FiatCurrencyPipe, ColoredPriceDirective, BlockchainComponent, MempoolBlocksComponent, @@ -210,6 +212,7 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati BytesPipe, VbytesPipe, WuBytesPipe, + FiatCurrencyPipe, CeilPipe, ShortenStringPipe, CapAddressPipe,