diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 5b68f58e0..0736735ba 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -417,6 +417,14 @@ export class PortfolioController { filterByTags }); + const { performance } = await this.portfolioService.getPerformance({ + dateRange, + filters, + impersonationId, + userId: this.request.user.id, + withExcludedAccounts: false + }); + const { holdings } = await this.portfolioService.getDetails({ dateRange, filters, @@ -424,7 +432,7 @@ export class PortfolioController { userId: this.request.user.id }); - return { holdings: Object.values(holdings) }; + return { holdings: Object.values(holdings), performance }; } @Get('investments') 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 dd411f6cc..652e2831e 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 @@ -3,6 +3,7 @@ import { ImpersonationStorageService } from '@ghostfolio/client/services/imperso import { UserService } from '@ghostfolio/client/services/user/user.service'; import { AssetProfileIdentifier, + PortfolioPerformance, PortfolioPosition, ToggleOption, User @@ -36,6 +37,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit { { label: $localize`Active`, value: 'ACTIVE' }, { label: $localize`Closed`, value: 'CLOSED' } ]; + public performance: PortfolioPerformance; public user: User; public viewModeFormControl = new FormControl( HomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE @@ -162,8 +164,9 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit { this.fetchHoldings() .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ holdings }) => { + .subscribe(({ holdings, performance }) => { this.holdings = holdings; + this.performance = performance; this.changeDetectorRef.markForCheck(); }); 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 f981e50a1..fe0dc6ec3 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -50,6 +50,7 @@ [deviceType]="deviceType" [holdings]="holdings" [locale]="user?.settings?.locale" + [performance]="performance" (holdingClicked)="onHoldingClicked($event)" /> @if (hasPermissionToCreateOrder && holdings?.length > 0) { diff --git a/libs/common/src/lib/interfaces/responses/portfolio-holdings-response.interface.ts b/libs/common/src/lib/interfaces/responses/portfolio-holdings-response.interface.ts index d2cf38f55..7702bac6c 100644 --- a/libs/common/src/lib/interfaces/responses/portfolio-holdings-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/portfolio-holdings-response.interface.ts @@ -1,5 +1,9 @@ -import { PortfolioPosition } from '@ghostfolio/common/interfaces'; +import { + PortfolioPerformance, + PortfolioPosition +} from '@ghostfolio/common/interfaces'; export interface PortfolioHoldingsResponse { holdings: PortfolioPosition[]; + performance: PortfolioPerformance; } diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index dde103077..99959ca0d 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -16,6 +16,7 @@ [tooltip]="element.name" /> + @@ -38,6 +39,7 @@ {{ element.symbol }} + Total @@ -62,6 +64,11 @@ /> + @@ -86,6 +93,10 @@ /> + + + + @@ -107,6 +118,7 @@ /> + @@ -130,6 +142,16 @@ /> + +
+ +
+
@@ -156,6 +178,16 @@ /> + +
+ +
+
@@ -175,6 +207,11 @@ }) " > + diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index 802cdc69a..b15f776cd 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -3,6 +3,7 @@ import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { getLocale } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier, + PortfolioPerformance, PortfolioPosition } from '@ghostfolio/common/interfaces'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -55,6 +56,7 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { @Input() holdings: PortfolioPosition[]; @Input() locale = getLocale(); @Input() pageSize = Number.MAX_SAFE_INTEGER; + @Input() performance: PortfolioPerformance; @Output() holdingClicked = new EventEmitter(); @@ -67,6 +69,10 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { public isLoading = true; public routeQueryParams: Subscription; + protected totalChange = 0; + protected totalChangePercentage = 0; + protected totalValue = 0; + private unsubscribeSubject = new Subject(); public ngOnChanges() { @@ -90,6 +96,12 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy { this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; + this.totalChange = + this.performance.netPerformancePercentageWithCurrencyEffect; + this.totalChangePercentage = + this.performance.netPerformancePercentageWithCurrencyEffect; + this.totalValue = this.performance.currentValueInBaseCurrency; + if (this.holdings) { this.isLoading = false; }