From 1b2d2a9860a2e7d31ba53ffb30264fc747bdceb6 Mon Sep 17 00:00:00 2001 From: TobiasXy Date: Mon, 15 Jan 2024 20:35:45 +0100 Subject: [PATCH] Feature/Add holdings tab to account detail dialog (#2853) (#2864) * Feature/Add holdings tab to account detail dialog (#2853) * Update changelog --- CHANGELOG.md | 6 +++++ .../account-detail-dialog.component.ts | 22 +++++++++++++++++ .../account-detail-dialog.html | 24 ++++++++++++++++--- .../account-detail-dialog.module.ts | 2 ++ .../allocations/allocations-page.component.ts | 4 ++-- .../holdings/holdings-page.component.ts | 12 ++++------ .../portfolio/holdings/holdings-page.html | 4 ++-- .../app/pages/public/public-page.component.ts | 11 ++++----- .../src/app/pages/public/public-page.html | 2 +- apps/client/src/app/services/data.service.ts | 9 +++++++ .../holdings-table.component.ts | 13 ++++------ 11 files changed, 78 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e3a98852..59c1e176a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Added the holdings table to the account detail dialog + ## 2.40.0 - 2024-01-15 ### Changed diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts index d37defe2f..90736d7cf 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts @@ -16,6 +16,7 @@ import { downloadAsFile } from '@ghostfolio/common/helper'; import { AccountBalancesResponse, HistoricalDataItem, + PortfolioPosition, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; @@ -45,6 +46,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit { public hasImpersonationId: boolean; public hasPermissionToDeleteAccountBalance: boolean; public historicalDataItems: HistoricalDataItem[]; + public holdings: PortfolioPosition[]; public isLoadingActivities: boolean; public isLoadingChart: boolean; public name: string; @@ -114,6 +116,26 @@ export class AccountDetailDialog implements OnDestroy, OnInit { } ); + this.dataService + .fetchPortfolioDetails({ + filters: [ + { + type: 'ACCOUNT', + id: this.data.accountId + } + ] + }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ holdings }) => { + this.holdings = []; + + for (const [symbol, holding] of Object.entries(holdings)) { + this.holdings.push(holding); + } + + this.changeDetectorRef.markForCheck(); + }); + this.impersonationStorageService .onChangeHasImpersonation() .pipe(takeUntil(this.unsubscribeSubject)) diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html index 1b9ba761b..11638edaf 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html @@ -70,12 +70,27 @@ [ngClass]="{ 'd-none': isLoadingActivities }" > - Activities + + +
Holdings
+
+ +
+ + + +
Activities
+
- Cash Balances + + +
Cash Balances
+
(); public hasImpersonationId: boolean; public hasPermissionToCreateOrder: boolean; + public holdings: PortfolioPosition[]; public isLoading = false; public placeholder = ''; public portfolioDetails: PortfolioDetails; - public positionsArray: PortfolioPosition[]; public user: User; private unsubscribeSubject = new Subject(); @@ -152,20 +152,16 @@ export class HoldingsPageComponent implements OnDestroy, OnInit { } public initialize() { - this.positionsArray = []; + this.holdings = []; } public initializeAnalysisData() { this.initialize(); - for (const [symbol, position] of Object.entries( + for (const [symbol, holding] of Object.entries( this.portfolioDetails.holdings )) { - this.positionsArray.push({ - ...position, - assetClassLabel: translate(position.assetClass), - assetSubClassLabel: translate(position.assetSubClass) - }); + this.holdings.push(holding); } } diff --git a/apps/client/src/app/pages/portfolio/holdings/holdings-page.html b/apps/client/src/app/pages/portfolio/holdings/holdings-page.html index 98b5dad87..282dc5a00 100644 --- a/apps/client/src/app/pages/portfolio/holdings/holdings-page.html +++ b/apps/client/src/app/pages/portfolio/holdings/holdings-page.html @@ -16,11 +16,11 @@ [baseCurrency]="user?.settings?.baseCurrency" [deviceType]="deviceType" [hasPermissionToCreateActivity]="hasPermissionToCreateOrder" + [holdings]="holdings" [locale]="user?.settings?.locale" - [positions]="positionsArray" > diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 73dceeb77..e6c99dd7f 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -39,6 +39,7 @@ import { } from '@ghostfolio/common/interfaces'; import { filterGlobalPermissions } from '@ghostfolio/common/permissions'; import { AccountWithValue, DateRange, GroupBy } from '@ghostfolio/common/types'; +import { translate } from '@ghostfolio/ui/i18n'; import { DataSource, Order as OrderModel } from '@prisma/client'; import { format, parseISO } from 'date-fns'; import { cloneDeep, groupBy, isNumber } from 'lodash'; @@ -399,6 +400,14 @@ export class DataService { if (response.holdings) { for (const symbol of Object.keys(response.holdings)) { + response.holdings[symbol].assetClassLabel = translate( + response.holdings[symbol].assetClass + ); + + response.holdings[symbol].assetSubClassLabel = translate( + response.holdings[symbol].assetSubClass + ); + response.holdings[symbol].dateOfFirstActivity = response.holdings[ symbol ].dateOfFirstActivity 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 e341e21b2..e931c505e 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -1,12 +1,10 @@ import { ChangeDetectionStrategy, Component, - EventEmitter, Input, OnChanges, OnDestroy, OnInit, - Output, ViewChild } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; @@ -14,7 +12,7 @@ import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { Router } from '@angular/router'; import { PortfolioPosition, UniqueAsset } from '@ghostfolio/common/interfaces'; -import { AssetClass, Order as OrderModel } from '@prisma/client'; +import { AssetClass } from '@prisma/client'; import { Subject, Subscription } from 'rxjs'; @Component({ @@ -28,12 +26,9 @@ export class HoldingsTableComponent implements OnChanges, OnDestroy, OnInit { @Input() deviceType: string; @Input() hasPermissionToCreateActivity: boolean; @Input() hasPermissionToShowValues = true; + @Input() holdings: PortfolioPosition[]; @Input() locale: string; @Input() pageSize = Number.MAX_SAFE_INTEGER; - @Input() positions: PortfolioPosition[]; - - @Output() transactionDeleted = new EventEmitter(); - @Output() transactionToUpdate = new EventEmitter(); @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -63,8 +58,8 @@ export class HoldingsTableComponent implements OnChanges, OnDestroy, OnInit { this.isLoading = true; - if (this.positions) { - this.dataSource = new MatTableDataSource(this.positions); + if (this.holdings) { + this.dataSource = new MatTableDataSource(this.holdings); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort;