Add cash balances table to account detail dialog (#2549)

* Add cash balances table to account detail dialog

* Update changelog

---------

Co-authored-by: Thomas <4159106+dtslvr@users.noreply.github.com>
pull/2705/head
Sanjeev Sharma 1 year ago committed by GitHub
parent 6f4fd0826c
commit ed4dd79c72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added a historical cash balances table to the account detail dialog
### Changed
- Respected the `withExcludedAccounts` flag in the account balance time series - Respected the `withExcludedAccounts` flag in the account balance time series
## 2.27.1 - 2023-11-28 ## 2.27.1 - 2023-11-28

@ -29,14 +29,15 @@ import { AccountDetailDialogParams } from './interfaces/interfaces';
styleUrls: ['./account-detail-dialog.component.scss'] styleUrls: ['./account-detail-dialog.component.scss']
}) })
export class AccountDetailDialog implements OnDestroy, OnInit { export class AccountDetailDialog implements OnDestroy, OnInit {
public activities: OrderWithAccount[];
public balance: number; public balance: number;
public currency: string; public currency: string;
public equity: number; public equity: number;
public hasImpersonationId: boolean; public hasImpersonationId: boolean;
public historicalDataItems: HistoricalDataItem[]; public historicalDataItems: HistoricalDataItem[];
public isLoadingActivities: boolean;
public isLoadingChart: boolean; public isLoadingChart: boolean;
public name: string; public name: string;
public orders: OrderWithAccount[];
public platformName: string; public platformName: string;
public transactionCount: number; public transactionCount: number;
public user: User; public user: User;
@ -64,6 +65,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
} }
public ngOnInit() { public ngOnInit() {
this.isLoadingActivities = true;
this.isLoadingChart = true; this.isLoadingChart = true;
this.dataService this.dataService
@ -103,7 +105,9 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
}) })
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ activities }) => { .subscribe(({ activities }) => {
this.orders = activities; this.activities = activities;
this.isLoadingActivities = false;
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });
@ -153,8 +157,8 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
public onExport() { public onExport() {
this.dataService this.dataService
.fetchExport( .fetchExport(
this.orders.map((order) => { this.activities.map(({ id }) => {
return order.id; return id;
}) })
) )
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))

@ -31,7 +31,7 @@
></gf-investment-chart> ></gf-investment-chart>
</div> </div>
<div class="row"> <div class="mb-3 row">
<div class="col-6 mb-3"> <div class="col-6 mb-3">
<gf-value <gf-value
i18n i18n
@ -64,11 +64,15 @@
</div> </div>
</div> </div>
<div class="row" [ngClass]="{ 'd-none': !orders?.length }"> <mat-tab-group
<div class="col mb-3"> animationDuration="0"
<div class="h5 mb-0" i18n>Activities</div> [mat-stretch-tabs]="false"
[ngClass]="{ 'd-none': isLoadingActivities }"
>
<mat-tab>
<ng-template i18n mat-tab-label>Activities</ng-template>
<gf-activities-table <gf-activities-table
[activities]="orders" [activities]="activities"
[baseCurrency]="user?.settings?.baseCurrency" [baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="data.deviceType" [deviceType]="data.deviceType"
[hasPermissionToCreateActivity]="false" [hasPermissionToCreateActivity]="false"
@ -79,8 +83,15 @@
[showActions]="false" [showActions]="false"
(export)="onExport()" (export)="onExport()"
></gf-activities-table> ></gf-activities-table>
</div> </mat-tab>
</div> <mat-tab>
<ng-template i18n mat-tab-label>Cash Balances</ng-template>
<gf-account-balances
[accountId]="data.accountId"
[locale]="user?.settings?.locale"
></gf-account-balances>
</mat-tab>
</mat-tab-group>
</div> </div>
</div> </div>

@ -2,9 +2,11 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog';
import { MatTabsModule } from '@angular/material/tabs';
import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module'; import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-footer/dialog-footer.module';
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module'; import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
import { GfInvestmentChartModule } from '@ghostfolio/client/components/investment-chart/investment-chart.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 { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module';
import { GfValueModule } from '@ghostfolio/ui/value'; import { GfValueModule } from '@ghostfolio/ui/value';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@ -15,6 +17,7 @@ import { AccountDetailDialog } from './account-detail-dialog.component';
declarations: [AccountDetailDialog], declarations: [AccountDetailDialog],
imports: [ imports: [
CommonModule, CommonModule,
GfAccountBalancesModule,
GfActivitiesTableModule, GfActivitiesTableModule,
GfDialogFooterModule, GfDialogFooterModule,
GfDialogHeaderModule, GfDialogHeaderModule,
@ -22,6 +25,7 @@ import { AccountDetailDialog } from './account-detail-dialog.component';
GfValueModule, GfValueModule,
MatButtonModule, MatButtonModule,
MatDialogModule, MatDialogModule,
MatTabsModule,
NgxSkeletonLoaderModule NgxSkeletonLoaderModule
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]

@ -1,5 +1,5 @@
<div class="container"> <div class="container">
<div class="row mb-3"> <div class="mb-3 row">
<div class="col"> <div class="col">
<h1 class="d-none d-sm-block h3 mb-3 text-center" i18n>Activities</h1> <h1 class="d-none d-sm-block h3 mb-3 text-center" i18n>Activities</h1>
<gf-activities-table <gf-activities-table

@ -18,6 +18,7 @@ import { PropertyDto } from '@ghostfolio/api/services/property/property.dto';
import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { import {
Access, Access,
AccountBalancesResponse,
Accounts, Accounts,
BenchmarkMarketDataDetails, BenchmarkMarketDataDetails,
BenchmarkResponse, BenchmarkResponse,
@ -137,6 +138,12 @@ export class DataService {
return this.http.get<AccountWithValue>(`/api/v1/account/${aAccountId}`); return this.http.get<AccountWithValue>(`/api/v1/account/${aAccountId}`);
} }
public fetchAccountBalances(aAccountId: string) {
return this.http.get<AccountBalancesResponse>(
`/api/v1/account/${aAccountId}/balances`
);
}
public fetchAccounts() { public fetchAccounts() {
return this.http.get<Accounts>('/api/v1/account'); return this.http.get<Accounts>('/api/v1/account');
} }

@ -0,0 +1,36 @@
<table
class="gf-table w-100"
mat-table
matSort
matSortActive="date"
matSortDirection="desc"
[dataSource]="dataSource"
>
<ng-container matColumnDef="date">
<th *matHeaderCellDef class="px-2" mat-header-cell mat-sort-header>
<ng-container i18n>Date</ng-container>
</th>
<td *matCellDef="let element" class="px-2" mat-cell>
<gf-value [isDate]="true" [locale]="locale" [value]="element?.date" />
</td>
</ng-container>
<ng-container matColumnDef="value">
<th *matHeaderCellDef class="px-2 text-right" mat-header-cell>
<ng-container i18n>Value</ng-container>
</th>
<td *matCellDef="let element" class="px-2" mat-cell>
<div class="d-flex justify-content-end">
<gf-value
[isCurrency]="true"
[locale]="locale"
[unit]="element?.Account?.currency"
[value]="element?.value"
></gf-value>
</div>
</td>
</ng-container>
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
</table>

@ -0,0 +1,5 @@
@import 'apps/client/src/styles/ghostfolio-style';
:host {
display: block;
}

@ -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<void>();
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();
});
}
}

@ -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 {}
Loading…
Cancel
Save