Browse Source

Add percentage visualization of the active filter

pull/1268/head
Thomas 3 years ago
parent
commit
597b1608b2
  1. 15
      apps/api/src/app/portfolio/portfolio.controller.ts
  2. 49
      apps/api/src/app/portfolio/portfolio.service.ts
  3. 8
      apps/api/src/interceptors/redact-values-in-response.interceptor.ts
  4. 11
      apps/client/src/app/pages/portfolio/allocations/allocations-page.html
  5. 4
      apps/client/src/app/pages/portfolio/allocations/allocations-page.module.ts
  6. 5
      apps/client/src/app/pages/portfolio/allocations/allocations-page.scss
  7. 3
      libs/common/src/lib/interfaces/portfolio-details.interface.ts

15
apps/api/src/app/portfolio/portfolio.controller.ts

@ -168,8 +168,14 @@ export class PortfolioController {
}) })
]; ];
const { accounts, holdings, hasErrors } = const {
await this.portfolioService.getDetails( accounts,
filteredValueInBaseCurrency,
filteredValueInPercentage,
hasErrors,
holdings,
totalValueInBaseCurrency
} = await this.portfolioService.getDetails(
impersonationId, impersonationId,
this.request.user.id, this.request.user.id,
range, range,
@ -234,8 +240,11 @@ export class PortfolioController {
return { return {
accounts, accounts,
filteredValueInBaseCurrency,
filteredValueInPercentage,
hasError, hasError,
holdings holdings,
totalValueInBaseCurrency
}; };
} }

49
apps/api/src/app/portfolio/portfolio.service.ts

@ -474,12 +474,21 @@ export class PortfolioService {
}); });
const holdings: PortfolioDetails['holdings'] = {}; const holdings: PortfolioDetails['holdings'] = {};
const totalInvestment = currentPositions.totalInvestment.plus( const totalInvestmentInBaseCurrency = currentPositions.totalInvestment.plus(
cashDetails.balanceInBaseCurrency cashDetails.balanceInBaseCurrency
); );
const totalValue = currentPositions.currentValue.plus( let filteredValueInBaseCurrency = currentPositions.currentValue;
if (
aFilters?.length === 0 ||
(aFilters?.length === 1 &&
aFilters[0].type === 'ASSET_CLASS' &&
aFilters[0].id === 'CASH')
) {
filteredValueInBaseCurrency = filteredValueInBaseCurrency.plus(
cashDetails.balanceInBaseCurrency cashDetails.balanceInBaseCurrency
); );
}
const dataGatheringItems = currentPositions.positions.map((position) => { const dataGatheringItems = currentPositions.positions.map((position) => {
return { return {
@ -540,10 +549,12 @@ export class PortfolioService {
holdings[item.symbol] = { holdings[item.symbol] = {
markets, markets,
allocationCurrent: totalValue.eq(0) allocationCurrent: filteredValueInBaseCurrency.eq(0)
? 0 ? 0
: value.div(totalValue).toNumber(), : value.div(filteredValueInBaseCurrency).toNumber(),
allocationInvestment: item.investment.div(totalInvestment).toNumber(), allocationInvestment: item.investment
.div(totalInvestmentInBaseCurrency)
.toNumber(),
assetClass: symbolProfile.assetClass, assetClass: symbolProfile.assetClass,
assetSubClass: symbolProfile.assetSubClass, assetSubClass: symbolProfile.assetSubClass,
countries: symbolProfile.countries, countries: symbolProfile.countries,
@ -577,8 +588,8 @@ export class PortfolioService {
cashDetails, cashDetails,
emergencyFund, emergencyFund,
userCurrency, userCurrency,
investment: totalInvestment, investment: totalInvestmentInBaseCurrency,
value: totalValue value: filteredValueInBaseCurrency
}); });
for (const symbol of Object.keys(cashPositions)) { for (const symbol of Object.keys(cashPositions)) {
@ -594,7 +605,18 @@ export class PortfolioService {
filters: aFilters filters: aFilters
}); });
return { accounts, holdings, hasErrors: currentPositions.hasErrors }; const summary = await this.getSummary(userId);
return {
accounts,
holdings,
filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(),
filteredValueInPercentage: summary.netWorth
? filteredValueInBaseCurrency.div(summary.netWorth).toNumber()
: 0,
hasErrors: currentPositions.hasErrors,
totalValueInBaseCurrency: summary.netWorth
};
} }
public async getPosition( public async getPosition(
@ -920,11 +942,9 @@ export class PortfolioService {
} }
public async getPerformance( public async getPerformance(
aImpersonationId: string, userId: string,
aDateRange: DateRange = 'max' aDateRange: DateRange = 'max'
): Promise<PortfolioPerformanceResponse> { ): Promise<PortfolioPerformanceResponse> {
const userId = await this.getUserId(aImpersonationId, this.request.user.id);
const { portfolioOrders, transactionPoints } = const { portfolioOrders, transactionPoints } =
await this.getTransactionPoints({ await this.getTransactionPoints({
userId userId
@ -1082,12 +1102,11 @@ export class PortfolioService {
}; };
} }
public async getSummary(aImpersonationId: string): Promise<PortfolioSummary> { public async getSummary(userId: string): Promise<PortfolioSummary> {
const userCurrency = this.request.user.Settings.settings.baseCurrency;
const userId = await this.getUserId(aImpersonationId, this.request.user.id);
const user = await this.userService.user({ id: userId }); const user = await this.userService.user({ id: userId });
const userCurrency = this.request.user.Settings.settings.baseCurrency;
const performanceInformation = await this.getPerformance(aImpersonationId); const performanceInformation = await this.getPerformance(userId);
const { balanceInBaseCurrency } = await this.accountService.getCashDetails({ const { balanceInBaseCurrency } = await this.accountService.getCashDetails({
userId, userId,

8
apps/api/src/interceptors/redact-values-in-response.interceptor.ts

@ -41,6 +41,14 @@ export class RedactValuesInResponseInterceptor<T>
return activity; return activity;
}); });
} }
if (data.filteredValueInBaseCurrency) {
data.filteredValueInBaseCurrency = null;
}
if (data.totalValueInBaseCurrency) {
data.totalValueInBaseCurrency = null;
}
} }
return data; return data;

11
apps/client/src/app/pages/portfolio/allocations/allocations-page.html

@ -10,6 +10,17 @@
></gf-activities-filter> ></gf-activities-filter>
</div> </div>
</div> </div>
<div class="row mb-4">
<div class="col">
<div class="px-1">
<mat-progress-bar
mode="determinate"
[title]="(portfolioDetails?.filteredValueInPercentage * 100) + '%'"
[value]="portfolioDetails?.filteredValueInPercentage * 100"
></mat-progress-bar>
</div>
</div>
</div>
<div class="proportion-charts row"> <div class="proportion-charts row">
<div class="col-md-4"> <div class="col-md-4">
<mat-card class="mb-3"> <mat-card class="mb-3">

4
apps/client/src/app/pages/portfolio/allocations/allocations-page.module.ts

@ -1,6 +1,7 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module'; import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module'; import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module';
import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module'; import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module';
@ -22,7 +23,8 @@ import { AllocationsPageComponent } from './allocations-page.component';
GfToggleModule, GfToggleModule,
GfWorldMapChartModule, GfWorldMapChartModule,
GfValueModule, GfValueModule,
MatCardModule MatCardModule,
MatProgressBarModule
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA] schemas: [CUSTOM_ELEMENTS_SCHEMA]
}) })

5
apps/client/src/app/pages/portfolio/allocations/allocations-page.scss

@ -28,4 +28,9 @@
} }
} }
} }
.mat-progress-bar {
border-radius: 0.25rem;
height: 0.5rem;
}
} }

3
libs/common/src/lib/interfaces/portfolio-details.interface.ts

@ -10,5 +10,8 @@ export interface PortfolioDetails {
original: number; original: number;
}; };
}; };
filteredValueInBaseCurrency?: number;
filteredValueInPercentage: number;
holdings: { [symbol: string]: PortfolioPosition }; holdings: { [symbol: string]: PortfolioPosition };
totalValueInBaseCurrency?: number;
} }

Loading…
Cancel
Save