diff --git a/apps/client/src/app/components/home-holdings/home-holdings.component.ts b/apps/client/src/app/components/home-holdings/home-holdings.component.ts index f079e1c9c6..333a24d5d6 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.component.ts +++ b/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 { DEFAULT_LOCALE } from '@ghostfolio/common/config'; +import { + DEFAULT_CURRENCY, + DEFAULT_DATE_RANGE, + DEFAULT_LOCALE +} from '@ghostfolio/common/config'; import { AssetProfileIdentifier, PortfolioPosition, @@ -22,10 +26,12 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + computed, CUSTOM_ELEMENTS_SCHEMA, DestroyRef, inject, - OnInit + OnInit, + signal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; @@ -51,9 +57,22 @@ import { DeviceDetectorService } from 'ngx-device-detector'; export class GfHomeHoldingsComponent implements OnInit { 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 hasPermissionToCreateActivity: boolean; protected holdings: PortfolioPosition[] | undefined; @@ -78,9 +97,14 @@ export class GfHomeHoldingsComponent implements OnInit { { label: $localize`Closed`, value: 'CLOSED' } ]; protected isHoldingsViewModeToggleDisabled = true; + + protected readonly locale = computed(() => { + return this.user()?.settings?.locale ?? DEFAULT_LOCALE; + }); + protected readonly routerLinkPortfolioActivities = internalRoutes.portfolio.subRoutes.activities.routerLink; - protected user: User; + protected readonly user = signal(null); private readonly changeDetectorRef = inject(ChangeDetectorRef); private readonly dataService = inject(DataService); @@ -94,22 +118,22 @@ export class GfHomeHoldingsComponent implements OnInit { } public ngOnInit() { - this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType; - this.userService.stateChanged .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { - this.user = state.user; + const user = state.user; + + this.user.set(user); this.hasPermissionToAccessHoldingsChart = hasPermission( - this.user.permissions, + user.permissions, permissions.accessHoldingsChart ); this.hasPermissionToCreateActivity = - hasPermission(this.user.permissions, permissions.createActivity) && - hasScope(this.user.scopes, scopes.activityCreate); + hasPermission(user.permissions, permissions.createActivity) && + hasScope(user.scopes, scopes.activityCreate); this.initialize(); } @@ -129,7 +153,7 @@ export class GfHomeHoldingsComponent implements OnInit { .get(true) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { - this.user = user; + this.user.set(user); this.changeDetectorRef.markForCheck(); }); @@ -144,7 +168,7 @@ export class GfHomeHoldingsComponent implements OnInit { protected onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) { if (dataSource && symbol) { - this.router.navigate([], { + void this.router.navigate([], { queryParams: { dataSource, symbol, holdingDetailDialog: true } }); } @@ -157,7 +181,7 @@ export class GfHomeHoldingsComponent implements OnInit { return this.dataService.fetchPortfolioHoldings({ filters, - range: this.user?.settings?.dateRange + range: this.user()?.settings?.dateRange }); } @@ -171,9 +195,9 @@ export class GfHomeHoldingsComponent implements OnInit { this.isHoldingsViewModeToggleDisabled = false; this.holdingsViewMode = - this.deviceType === 'mobile' + this.deviceType() === 'mobile' ? GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE - : (this.user?.settings?.holdingsViewMode ?? + : (this.user()?.settings?.holdingsViewMode ?? GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE); } else { this.holdingsViewMode = diff --git a/apps/client/src/app/components/home-holdings/home-holdings.html b/apps/client/src/app/components/home-holdings/home-holdings.html index b55b1c54ef..7c533b2835 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -27,18 +27,18 @@ }
@if (hasPermissionToCreateActivity && (holdings?.length ?? 0) > 0) { diff --git a/apps/client/src/app/components/home-overview/home-overview.component.ts b/apps/client/src/app/components/home-overview/home-overview.component.ts index b677f88a39..3cecc5e5de 100644 --- a/apps/client/src/app/components/home-overview/home-overview.component.ts +++ b/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' }) export class GfHomeOverviewComponent implements OnInit { - protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE; protected readonly errors = signal([]); protected readonly hasImpersonationId = signal(false); protected readonly historicalDataItems = signal(null); @@ -61,6 +60,11 @@ export class GfHomeOverviewComponent implements OnInit { undefined ); protected readonly isLoadingPerformance = signal(true); + + protected readonly locale = computed(() => { + return this.user()?.settings?.locale ?? DEFAULT_LOCALE; + }); + protected readonly performance = signal(null); protected readonly performanceLabel = $localize`Performance`; protected readonly precision = signal(2); @@ -147,7 +151,7 @@ export class GfHomeOverviewComponent implements OnInit { protected onHoldingClicked({ dataSource, symbol }: AssetProfileIdentifier) { if (dataSource && symbol) { - this.router.navigate([], { + void this.router.navigate([], { queryParams: { dataSource, symbol, holdingDetailDialog: true } }); } diff --git a/apps/client/src/app/components/home-overview/home-overview.html b/apps/client/src/app/components/home-overview/home-overview.html index 7648777463..6a166f93fd 100644 --- a/apps/client/src/app/components/home-overview/home-overview.html +++ b/apps/client/src/app/components/home-overview/home-overview.html @@ -11,7 +11,10 @@

Welcome to Ghostfolio

Ready to take control of your personal finances?

    -
  1. +
  2. Setup your accounts
    Setup accounts
    - } @else if (user()?.accounts?.length > 1) { + } @else if ((user()?.accounts?.length ?? 0) > 1) { diff --git a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts index 4f7f35dd1e..aade357b78 100644 --- a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts +++ b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts @@ -35,9 +35,9 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; }) export class GfPortfolioPerformanceComponent { public readonly errors = input(); - public readonly isLoading = input(); + public readonly isLoading = input(false); public readonly locale = input(getLocale()); - public readonly performance = input.required(); + public readonly performance = input.required(); public readonly precision = input.required({ transform: (value) => { return value >= 0 ? value : 2; @@ -60,17 +60,19 @@ export class GfPortfolioPerformanceComponent { this.value().nativeElement.innerHTML = ''; } } else { - if (isNumber(this.performance().currentValueInBaseCurrency)) { - new CountUp('value', this.performance().currentValueInBaseCurrency, { + const performance = this.performance(); + + if (isNumber(performance?.currentValueInBaseCurrency)) { + new CountUp('value', performance.currentValueInBaseCurrency, { decimal: getNumberFormatDecimal(this.locale()), decimalPlaces: this.precision(), duration: 1, separator: getNumberFormatGroup(this.locale()) }).start(); - } else if (this.showDetails() === false) { + } else if (this.showDetails() === false && performance) { new CountUp( 'value', - this.performance().netPerformancePercentageWithCurrencyEffect * 100, + performance.netPerformancePercentageWithCurrencyEffect * 100, { decimal: getNumberFormatDecimal(this.locale()), decimalPlaces: 2, diff --git a/libs/ui/src/lib/line-chart/line-chart.component.ts b/libs/ui/src/lib/line-chart/line-chart.component.ts index e6f1b9b2e2..d910033bc0 100644 --- a/libs/ui/src/lib/line-chart/line-chart.component.ts +++ b/libs/ui/src/lib/line-chart/line-chart.component.ts @@ -60,7 +60,7 @@ export class GfLineChartComponent @Input() benchmarkLabel = ''; @Input() colorScheme?: ColorScheme; @Input() currency?: string; - @Input() historicalDataItems: LineChartItem[]; + @Input() historicalDataItems: LineChartItem[] | null; @Input() isAnimated = false; @Input() label: string; @Input() locale = getLocale();