Browse Source

Task/resolve strict template errors in home components (#8101)

Resolve strict template errors
pull/8070/head^2
Kenrick Tandrian 12 hours ago
committed by GitHub
parent
commit
59e990c743
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 56
      apps/client/src/app/components/home-holdings/home-holdings.component.ts
  2. 10
      apps/client/src/app/components/home-holdings/home-holdings.html
  3. 8
      apps/client/src/app/components/home-overview/home-overview.component.ts
  4. 13
      apps/client/src/app/components/home-overview/home-overview.html
  5. 14
      apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts
  6. 2
      libs/ui/src/lib/line-chart/line-chart.component.ts

56
apps/client/src/app/components/home-holdings/home-holdings.component.ts

@ -1,5 +1,9 @@
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { DEFAULT_LOCALE } from '@ghostfolio/common/config'; import {
DEFAULT_CURRENCY,
DEFAULT_DATE_RANGE,
DEFAULT_LOCALE
} from '@ghostfolio/common/config';
import { import {
AssetProfileIdentifier, AssetProfileIdentifier,
PortfolioPosition, PortfolioPosition,
@ -22,10 +26,12 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
computed,
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
DestroyRef, DestroyRef,
inject, inject,
OnInit OnInit,
signal
} from '@angular/core'; } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
@ -51,9 +57,22 @@ import { DeviceDetectorService } from 'ngx-device-detector';
export class GfHomeHoldingsComponent implements OnInit { export class GfHomeHoldingsComponent implements OnInit {
public static DEFAULT_HOLDINGS_VIEW_MODE: HoldingsViewMode = 'TABLE'; public static DEFAULT_HOLDINGS_VIEW_MODE: HoldingsViewMode = 'TABLE';
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE; protected readonly baseCurrency = computed(() => {
return this.user()?.settings?.baseCurrency ?? DEFAULT_CURRENCY;
});
protected readonly colorScheme = computed(() => {
return this.user()?.settings?.colorScheme;
});
protected readonly dateRange = computed(() => {
return this.user()?.settings?.dateRange ?? DEFAULT_DATE_RANGE;
});
protected readonly deviceType = computed(() => {
return this.deviceDetectorService.deviceInfo().deviceType;
});
protected deviceType: string;
protected hasPermissionToAccessHoldingsChart: boolean; protected hasPermissionToAccessHoldingsChart: boolean;
protected hasPermissionToCreateActivity: boolean; protected hasPermissionToCreateActivity: boolean;
protected holdings: PortfolioPosition[] | undefined; protected holdings: PortfolioPosition[] | undefined;
@ -78,9 +97,14 @@ export class GfHomeHoldingsComponent implements OnInit {
{ label: $localize`Closed`, value: 'CLOSED' } { label: $localize`Closed`, value: 'CLOSED' }
]; ];
protected isHoldingsViewModeToggleDisabled = true; protected isHoldingsViewModeToggleDisabled = true;
protected readonly locale = computed(() => {
return this.user()?.settings?.locale ?? DEFAULT_LOCALE;
});
protected readonly routerLinkPortfolioActivities = protected readonly routerLinkPortfolioActivities =
internalRoutes.portfolio.subRoutes.activities.routerLink; internalRoutes.portfolio.subRoutes.activities.routerLink;
protected user: User; protected readonly user = signal<User | null>(null);
private readonly changeDetectorRef = inject(ChangeDetectorRef); private readonly changeDetectorRef = inject(ChangeDetectorRef);
private readonly dataService = inject(DataService); private readonly dataService = inject(DataService);
@ -94,22 +118,22 @@ export class GfHomeHoldingsComponent implements OnInit {
} }
public ngOnInit() { public ngOnInit() {
this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;
this.userService.stateChanged this.userService.stateChanged
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((state) => { .subscribe((state) => {
if (state?.user) { if (state?.user) {
this.user = state.user; const user = state.user;
this.user.set(user);
this.hasPermissionToAccessHoldingsChart = hasPermission( this.hasPermissionToAccessHoldingsChart = hasPermission(
this.user.permissions, user.permissions,
permissions.accessHoldingsChart permissions.accessHoldingsChart
); );
this.hasPermissionToCreateActivity = this.hasPermissionToCreateActivity =
hasPermission(this.user.permissions, permissions.createActivity) && hasPermission(user.permissions, permissions.createActivity) &&
hasScope(this.user.scopes, scopes.activityCreate); hasScope(user.scopes, scopes.activityCreate);
this.initialize(); this.initialize();
} }
@ -129,7 +153,7 @@ export class GfHomeHoldingsComponent implements OnInit {
.get(true) .get(true)
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((user) => { .subscribe((user) => {
this.user = user; this.user.set(user);
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });
@ -144,7 +168,7 @@ export class GfHomeHoldingsComponent implements OnInit {
protected onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) { protected onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) {
if (dataSource && symbol) { if (dataSource && symbol) {
this.router.navigate([], { void this.router.navigate([], {
queryParams: { dataSource, symbol, holdingDetailDialog: true } queryParams: { dataSource, symbol, holdingDetailDialog: true }
}); });
} }
@ -157,7 +181,7 @@ export class GfHomeHoldingsComponent implements OnInit {
return this.dataService.fetchPortfolioHoldings({ return this.dataService.fetchPortfolioHoldings({
filters, filters,
range: this.user?.settings?.dateRange range: this.user()?.settings?.dateRange
}); });
} }
@ -171,9 +195,9 @@ export class GfHomeHoldingsComponent implements OnInit {
this.isHoldingsViewModeToggleDisabled = false; this.isHoldingsViewModeToggleDisabled = false;
this.holdingsViewMode = this.holdingsViewMode =
this.deviceType === 'mobile' this.deviceType() === 'mobile'
? GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE ? GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE
: (this.user?.settings?.holdingsViewMode ?? : (this.user()?.settings?.holdingsViewMode ??
GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE); GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE);
} else { } else {
this.holdingsViewMode = this.holdingsViewMode =

10
apps/client/src/app/components/home-holdings/home-holdings.html

@ -27,18 +27,18 @@
<gf-treemap-chart <gf-treemap-chart
class="mt-3" class="mt-3"
cursor="pointer" cursor="pointer"
[baseCurrency]="user?.settings?.baseCurrency" [baseCurrency]="baseCurrency()"
[colorScheme]="user?.settings?.colorScheme" [colorScheme]="colorScheme()"
[dateRange]="user?.settings?.dateRange" [dateRange]="dateRange()"
[holdings]="holdings" [holdings]="holdings"
[locale]="user?.settings?.locale" [locale]="locale()"
(treemapChartClicked)="onHoldingClicked($event)" (treemapChartClicked)="onHoldingClicked($event)"
/> />
} }
<div [class.d-none]="holdingsViewMode !== 'TABLE'"> <div [class.d-none]="holdingsViewMode !== 'TABLE'">
<gf-holdings-table <gf-holdings-table
[holdings]="holdings" [holdings]="holdings"
[locale]="user?.settings?.locale ?? DEFAULT_LOCALE" [locale]="locale()"
(holdingClicked)="onHoldingClicked($event)" (holdingClicked)="onHoldingClicked($event)"
/> />
@if (hasPermissionToCreateActivity && (holdings?.length ?? 0) > 0) { @if (hasPermissionToCreateActivity && (holdings?.length ?? 0) > 0) {

8
apps/client/src/app/components/home-overview/home-overview.component.ts

@ -53,7 +53,6 @@ import { DeviceDetectorService } from 'ngx-device-detector';
templateUrl: './home-overview.html' templateUrl: './home-overview.html'
}) })
export class GfHomeOverviewComponent implements OnInit { export class GfHomeOverviewComponent implements OnInit {
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE;
protected readonly errors = signal<AssetProfileIdentifier[]>([]); protected readonly errors = signal<AssetProfileIdentifier[]>([]);
protected readonly hasImpersonationId = signal(false); protected readonly hasImpersonationId = signal(false);
protected readonly historicalDataItems = signal<LineChartItem[] | null>(null); protected readonly historicalDataItems = signal<LineChartItem[] | null>(null);
@ -61,6 +60,11 @@ export class GfHomeOverviewComponent implements OnInit {
undefined undefined
); );
protected readonly isLoadingPerformance = signal(true); protected readonly isLoadingPerformance = signal(true);
protected readonly locale = computed(() => {
return this.user()?.settings?.locale ?? DEFAULT_LOCALE;
});
protected readonly performance = signal<PortfolioPerformance | null>(null); protected readonly performance = signal<PortfolioPerformance | null>(null);
protected readonly performanceLabel = $localize`Performance`; protected readonly performanceLabel = $localize`Performance`;
protected readonly precision = signal(2); protected readonly precision = signal(2);
@ -147,7 +151,7 @@ export class GfHomeOverviewComponent implements OnInit {
protected onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) { protected onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) {
if (dataSource && symbol) { if (dataSource && symbol) {
this.router.navigate([], { void this.router.navigate([], {
queryParams: { dataSource, symbol, holdingDetailDialog: true } queryParams: { dataSource, symbol, holdingDetailDialog: true }
}); });
} }

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

@ -11,7 +11,10 @@
<h4 i18n>Welcome to Ghostfolio</h4> <h4 i18n>Welcome to Ghostfolio</h4>
<p i18n>Ready to take control of your personal finances?</p> <p i18n>Ready to take control of your personal finances?</p>
<ol class="font-weight-bold"> <ol class="font-weight-bold">
<li class="mb-2" [class.text-muted]="user()?.accounts?.length > 1"> <li
class="mb-2"
[class.text-muted]="(user()?.accounts?.length ?? 0) > 1"
>
<a class="d-block" [routerLink]="routerLinkAccounts" <a class="d-block" [routerLink]="routerLinkAccounts"
><span i18n>Setup your accounts</span><br /> ><span i18n>Setup your accounts</span><br />
<span class="font-weight-normal" i18n <span class="font-weight-normal" i18n
@ -48,7 +51,7 @@
> >
<ng-container i18n>Setup accounts</ng-container> <ng-container i18n>Setup accounts</ng-container>
</a> </a>
} @else if (user()?.accounts?.length > 1) { } @else if ((user()?.accounts?.length ?? 0) > 1) {
<a <a
color="primary" color="primary"
mat-flat-button mat-flat-button
@ -73,7 +76,7 @@
[historicalDataItems]="historicalDataItems()" [historicalDataItems]="historicalDataItems()"
[isAnimated]="user()?.settings?.dateRange === '1d' ? false : true" [isAnimated]="user()?.settings?.dateRange === '1d' ? false : true"
[label]="performanceLabel" [label]="performanceLabel"
[locale]="user()?.settings?.locale" [locale]="locale()"
[showGradient]="true" [showGradient]="true"
[showLoader]="false" [showLoader]="false"
[showXAxis]="false" [showXAxis]="false"
@ -85,7 +88,7 @@
<gf-portfolio-performance <gf-portfolio-performance
[errors]="errors()" [errors]="errors()"
[isLoading]="isLoadingPerformance()" [isLoading]="isLoadingPerformance()"
[locale]="user()?.settings?.locale" [locale]="locale()"
[performance]="performance()" [performance]="performance()"
[precision]="precision()" [precision]="precision()"
[showDetails]="showDetails()" [showDetails]="showDetails()"
@ -107,7 +110,7 @@
<gf-holdings-table <gf-holdings-table
mode="simple" mode="simple"
[holdings]="holdings()" [holdings]="holdings()"
[locale]="user()?.settings?.locale ?? DEFAULT_LOCALE" [locale]="locale()"
(holdingClicked)="onHoldingClicked($event)" (holdingClicked)="onHoldingClicked($event)"
/> />
</mat-card-content> </mat-card-content>

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

@ -35,9 +35,9 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
}) })
export class GfPortfolioPerformanceComponent { export class GfPortfolioPerformanceComponent {
public readonly errors = input<ResponseError['errors']>(); public readonly errors = input<ResponseError['errors']>();
public readonly isLoading = input<boolean>(); public readonly isLoading = input<boolean>(false);
public readonly locale = input<string>(getLocale()); public readonly locale = input<string>(getLocale());
public readonly performance = input.required<PortfolioPerformance>(); public readonly performance = input.required<PortfolioPerformance | null>();
public readonly precision = input.required<number, number>({ public readonly precision = input.required<number, number>({
transform: (value) => { transform: (value) => {
return value >= 0 ? value : 2; return value >= 0 ? value : 2;
@ -60,17 +60,19 @@ export class GfPortfolioPerformanceComponent {
this.value().nativeElement.innerHTML = ''; this.value().nativeElement.innerHTML = '';
} }
} else { } else {
if (isNumber(this.performance().currentValueInBaseCurrency)) { const performance = this.performance();
new CountUp('value', this.performance().currentValueInBaseCurrency, {
if (isNumber(performance?.currentValueInBaseCurrency)) {
new CountUp('value', performance.currentValueInBaseCurrency, {
decimal: getNumberFormatDecimal(this.locale()), decimal: getNumberFormatDecimal(this.locale()),
decimalPlaces: this.precision(), decimalPlaces: this.precision(),
duration: 1, duration: 1,
separator: getNumberFormatGroup(this.locale()) separator: getNumberFormatGroup(this.locale())
}).start(); }).start();
} else if (this.showDetails() === false) { } else if (this.showDetails() === false && performance) {
new CountUp( new CountUp(
'value', 'value',
this.performance().netPerformancePercentageWithCurrencyEffect * 100, performance.netPerformancePercentageWithCurrencyEffect * 100,
{ {
decimal: getNumberFormatDecimal(this.locale()), decimal: getNumberFormatDecimal(this.locale()),
decimalPlaces: 2, decimalPlaces: 2,

2
libs/ui/src/lib/line-chart/line-chart.component.ts

@ -60,7 +60,7 @@ export class GfLineChartComponent
@Input() benchmarkLabel = ''; @Input() benchmarkLabel = '';
@Input() colorScheme?: ColorScheme; @Input() colorScheme?: ColorScheme;
@Input() currency?: string; @Input() currency?: string;
@Input() historicalDataItems: LineChartItem[]; @Input() historicalDataItems: LineChartItem[] | null;
@Input() isAnimated = false; @Input() isAnimated = false;
@Input() label: string; @Input() label: string;
@Input() locale = getLocale(); @Input() locale = getLocale();

Loading…
Cancel
Save