Browse Source

Task/improve type safety in portfolio performance component (#7265)

Improve type safety
pull/7266/head^2
Kenrick Tandrian 1 week ago
committed by GitHub
parent
commit
6278cf6691
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      apps/client/src/app/components/home-overview/home-overview.html
  2. 22
      apps/client/src/app/components/portfolio-performance/portfolio-performance.component.html
  3. 103
      apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts

1
apps/client/src/app/components/home-overview/home-overview.html

@ -86,7 +86,6 @@
<div class="col">
<gf-portfolio-performance
class="pb-4"
[deviceType]="deviceType()"
[errors]="errors()"
[isLoading]="isLoadingPerformance()"
[locale]="user()?.settings?.locale"

22
apps/client/src/app/components/portfolio-performance/portfolio-performance.component.html

@ -1,7 +1,7 @@
<div class="container p-0">
<div class="no-gutters row">
<div class="status-container text-muted text-right">
@if (errors?.length > 0 && !isLoading) {
@if (errors()?.length > 0 && !isLoading()) {
<ion-icon
i18n-title
name="time-outline"
@ -10,7 +10,7 @@
/>
}
</div>
@if (isLoading) {
@if (isLoading()) {
<div class="align-items-center d-flex">
<ngx-skeleton-loader
animation="pulse"
@ -24,25 +24,25 @@
}
<div
class="display-4 font-weight-bold m-0 text-center value-container"
[hidden]="isLoading"
[hidden]="isLoading()"
>
<span #value id="value"></span>
</div>
<div class="currency-container flex-grow-1 px-1">
{{ unit }}
{{ unit() }}
</div>
</div>
@if (showDetails) {
@if (showDetails()) {
<div class="row">
<div class="d-flex col justify-content-end">
<gf-value
[colorizeSign]="true"
[isCurrency]="true"
[locale]="locale"
[locale]="locale()"
[value]="
isLoading
isLoading()
? undefined
: performance?.netPerformanceWithCurrencyEffect
: performance().netPerformanceWithCurrencyEffect
"
/>
</div>
@ -50,11 +50,11 @@
<gf-value
[colorizeSign]="true"
[isPercent]="true"
[locale]="locale"
[locale]="locale()"
[value]="
isLoading
isLoading()
? undefined
: performance?.netPerformancePercentageWithCurrencyEffect
: performance().netPerformancePercentageWithCurrencyEffect
"
/>
</div>

103
apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts

@ -13,10 +13,11 @@ import { GfValueComponent } from '@ghostfolio/ui/value';
import {
ChangeDetectionStrategy,
Component,
effect,
ElementRef,
Input,
OnChanges,
ViewChild
inject,
input,
viewChild
} from '@angular/core';
import { IonIcon } from '@ionic/angular/standalone';
import { CountUp } from 'countup.js';
@ -32,58 +33,68 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
styleUrls: ['./portfolio-performance.component.scss'],
templateUrl: './portfolio-performance.component.html'
})
export class GfPortfolioPerformanceComponent implements OnChanges {
@Input() deviceType: string;
@Input() errors: ResponseError['errors'];
@Input() isLoading: boolean;
@Input() locale = getLocale();
@Input() performance: PortfolioPerformance;
@Input() precision: number;
@Input() showDetails: boolean;
@Input() unit: string;
export class GfPortfolioPerformanceComponent {
public readonly errors = input<ResponseError['errors']>();
public readonly isLoading = input<boolean>();
public readonly locale = input<string>(getLocale());
public readonly performance = input.required<PortfolioPerformance>();
public readonly precision = input.required<number, number>({
transform: (value) => {
return value >= 0 ? value : 2;
}
});
public readonly showDetails = input<boolean>(false);
public readonly unit = input.required<string>();
@ViewChild('value') value: ElementRef;
private readonly value =
viewChild.required<ElementRef<HTMLSpanElement>>('value');
public constructor(private notificationService: NotificationService) {
addIcons({ timeOutline });
}
private readonly notificationService = inject(NotificationService);
public ngOnChanges() {
this.precision = this.precision >= 0 ? this.precision : 2;
public constructor() {
addIcons({ timeOutline });
if (this.isLoading) {
if (this.value?.nativeElement) {
this.value.nativeElement.innerHTML = '';
}
} else {
if (isNumber(this.performance?.currentValueInBaseCurrency)) {
new CountUp('value', this.performance?.currentValueInBaseCurrency, {
decimal: getNumberFormatDecimal(this.locale),
decimalPlaces: this.precision,
duration: 1,
separator: getNumberFormatGroup(this.locale)
}).start();
} else if (this.showDetails === false) {
new CountUp(
'value',
this.performance?.netPerformancePercentageWithCurrencyEffect * 100,
{
decimal: getNumberFormatDecimal(this.locale),
decimalPlaces: 2,
duration: 1,
separator: getNumberFormatGroup(this.locale)
}
).start();
effect(() => {
if (this.isLoading()) {
if (this.value().nativeElement) {
this.value().nativeElement.innerHTML = '';
}
} else {
this.value.nativeElement.innerHTML = '*****';
if (isNumber(this.performance().currentValueInBaseCurrency)) {
new CountUp('value', this.performance().currentValueInBaseCurrency, {
decimal: getNumberFormatDecimal(this.locale()),
decimalPlaces: this.precision(),
duration: 1,
separator: getNumberFormatGroup(this.locale())
}).start();
} else if (this.showDetails() === false) {
new CountUp(
'value',
this.performance().netPerformancePercentageWithCurrencyEffect * 100,
{
decimal: getNumberFormatDecimal(this.locale()),
decimalPlaces: 2,
duration: 1,
separator: getNumberFormatGroup(this.locale())
}
).start();
} else {
this.value().nativeElement.innerHTML = '*****';
}
}
}
});
}
public onShowErrors() {
const errorMessageParts = [];
protected onShowErrors() {
const errors = this.errors();
if (!errors?.length) {
return;
}
const errorMessageParts: string[] = [];
for (const error of this.errors) {
for (const error of errors) {
errorMessageParts.push(`${error.symbol} (${error.dataSource})`);
}

Loading…
Cancel
Save