diff --git a/CHANGELOG.md b/CHANGELOG.md index 729b4713b..2aa09c05a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added a historical cash balances table to the account detail dialog + +### Changed + - Respected the `withExcludedAccounts` flag in the account balance time series ## 2.27.1 - 2023-11-28 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 284bfcca2..b3a916da9 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 @@ -29,14 +29,15 @@ import { AccountDetailDialogParams } from './interfaces/interfaces'; styleUrls: ['./account-detail-dialog.component.scss'] }) export class AccountDetailDialog implements OnDestroy, OnInit { + public activities: OrderWithAccount[]; public balance: number; public currency: string; public equity: number; public hasImpersonationId: boolean; public historicalDataItems: HistoricalDataItem[]; + public isLoadingActivities: boolean; public isLoadingChart: boolean; public name: string; - public orders: OrderWithAccount[]; public platformName: string; public transactionCount: number; public user: User; @@ -64,6 +65,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit { } public ngOnInit() { + this.isLoadingActivities = true; this.isLoadingChart = true; this.dataService @@ -103,7 +105,9 @@ export class AccountDetailDialog implements OnDestroy, OnInit { }) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ activities }) => { - this.orders = activities; + this.activities = activities; + + this.isLoadingActivities = false; this.changeDetectorRef.markForCheck(); }); @@ -153,8 +157,8 @@ export class AccountDetailDialog implements OnDestroy, OnInit { public onExport() { this.dataService .fetchExport( - this.orders.map((order) => { - return order.id; + this.activities.map(({ id }) => { + return id; }) ) .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 02d1c917e..7e92eca85 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 @@ -31,7 +31,7 @@ > -
+
-
-
-
Activities
+ + + Activities -
-
+ + + Cash Balances + + +
diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts index c3d45b6ce..83ac5b6ea 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.module.ts @@ -2,9 +2,11 @@ import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatDialogModule } from '@angular/material/dialog'; +import { MatTabsModule } from '@angular/material/tabs'; import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module'; import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module'; import { GfInvestmentChartModule } from '@ghostfolio/client/components/investment-chart/investment-chart.module'; +import { GfAccountBalancesModule } from '@ghostfolio/ui/account-balances/account-balances.module'; import { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module'; import { GfValueModule } from '@ghostfolio/ui/value'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @@ -15,6 +17,7 @@ import { AccountDetailDialog } from './account-detail-dialog.component'; declarations: [AccountDetailDialog], imports: [ CommonModule, + GfAccountBalancesModule, GfActivitiesTableModule, GfDialogFooterModule, GfDialogHeaderModule, @@ -22,6 +25,7 @@ import { AccountDetailDialog } from './account-detail-dialog.component'; GfValueModule, MatButtonModule, MatDialogModule, + MatTabsModule, NgxSkeletonLoaderModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA] diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.html b/apps/client/src/app/pages/portfolio/activities/activities-page.html index a5c9201a0..8c2cf9bd5 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.html +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -1,5 +1,5 @@
-
+

Activities

(`/api/v1/account/${aAccountId}`); } + public fetchAccountBalances(aAccountId: string) { + return this.http.get( + `/api/v1/account/${aAccountId}/balances` + ); + } + public fetchAccounts() { return this.http.get('/api/v1/account'); } diff --git a/libs/ui/src/lib/account-balances/account-balances.component.html b/libs/ui/src/lib/account-balances/account-balances.component.html new file mode 100644 index 000000000..81f8a8192 --- /dev/null +++ b/libs/ui/src/lib/account-balances/account-balances.component.html @@ -0,0 +1,36 @@ + + + + + + + + + + + + + +
+ Date + + + + Value + +
+ +
+
diff --git a/libs/ui/src/lib/account-balances/account-balances.component.scss b/libs/ui/src/lib/account-balances/account-balances.component.scss new file mode 100644 index 000000000..b5b58f67e --- /dev/null +++ b/libs/ui/src/lib/account-balances/account-balances.component.scss @@ -0,0 +1,5 @@ +@import 'apps/client/src/styles/ghostfolio-style'; + +:host { + display: block; +} diff --git a/libs/ui/src/lib/account-balances/account-balances.component.ts b/libs/ui/src/lib/account-balances/account-balances.component.ts new file mode 100644 index 000000000..c552519d6 --- /dev/null +++ b/libs/ui/src/lib/account-balances/account-balances.component.ts @@ -0,0 +1,63 @@ +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + Input, + OnDestroy, + OnInit, + ViewChild +} from '@angular/core'; +import { MatSort } from '@angular/material/sort'; +import { MatTableDataSource } from '@angular/material/table'; +import { DataService } from '@ghostfolio/client/services/data.service'; +import { AccountBalancesResponse } from '@ghostfolio/common/interfaces'; +import { get } from 'lodash'; +import { Subject, takeUntil } from 'rxjs'; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'gf-account-balances', + styleUrls: ['./account-balances.component.scss'], + templateUrl: './account-balances.component.html' +}) +export class AccountBalancesComponent implements OnDestroy, OnInit { + @Input() accountId: string; + @Input() locale: string; + + @ViewChild(MatSort) sort: MatSort; + + public dataSource: MatTableDataSource< + AccountBalancesResponse['balances'][0] + > = new MatTableDataSource(); + public displayedColumns: string[] = ['date', 'value']; + + private unsubscribeSubject = new Subject(); + + public constructor( + private changeDetectorRef: ChangeDetectorRef, + private dataService: DataService + ) {} + + public ngOnInit() { + this.fetchBalances(); + } + + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } + + private fetchBalances() { + this.dataService + .fetchAccountBalances(this.accountId) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ balances }) => { + this.dataSource = new MatTableDataSource(balances); + + this.dataSource.sort = this.sort; + this.dataSource.sortingDataAccessor = get; + + this.changeDetectorRef.markForCheck(); + }); + } +} diff --git a/libs/ui/src/lib/account-balances/account-balances.module.ts b/libs/ui/src/lib/account-balances/account-balances.module.ts new file mode 100644 index 000000000..cc8fb9677 --- /dev/null +++ b/libs/ui/src/lib/account-balances/account-balances.module.ts @@ -0,0 +1,15 @@ +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { MatSortModule } from '@angular/material/sort'; +import { MatTableModule } from '@angular/material/table'; +import { GfValueModule } from '@ghostfolio/ui/value'; + +import { AccountBalancesComponent } from './account-balances.component'; + +@NgModule({ + declarations: [AccountBalancesComponent], + exports: [AccountBalancesComponent], + imports: [CommonModule, GfValueModule, MatSortModule, MatTableModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class GfAccountBalancesModule {}