Browse Source

Exclude cash in base currency from portfolio performance calculation

pull/7443/head
Thomas Kaul 1 month ago
parent
commit
cd71ed8852
  1. 160
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html
  2. 8
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.scss
  3. 27
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts

160
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html

@ -9,7 +9,7 @@
class="flex-nowrap px-3 py-1 row" class="flex-nowrap px-3 py-1 row"
[hidden]="summary?.activityCount === null" [hidden]="summary?.activityCount === null"
> >
<div class="d-flex flex-grow-1 ml-3 text-truncate"> <div class="d-flex flex-grow-1 indent-1 text-truncate">
{{ summary?.activityCount }} {{ summary?.activityCount }}
<ng-container i18n>{summary?.activityCount, plural, <ng-container i18n>{summary?.activityCount, plural,
=1 {activity} =1 {activity}
@ -123,7 +123,7 @@
</div> </div>
</div> </div>
<div class="flex-nowrap px-3 py-1 row"> <div class="flex-nowrap px-3 py-1 row">
<div class="flex-grow-1 text-truncate ml-3"> <div class="flex-grow-1 indent-1 text-truncate">
<ng-container i18n>Net Performance</ng-container> <ng-container i18n>Net Performance</ng-container>
<abbr <abbr
class="d-none d-sm-inline-block initialism ml-2 text-muted" class="d-none d-sm-inline-block initialism ml-2 text-muted"
@ -164,7 +164,17 @@
</div> </div>
</div> </div>
<div class="flex-nowrap px-3 py-1 row"> <div class="flex-nowrap px-3 py-1 row">
<div class="flex-grow-1 ml-3 text-truncate" i18n>Cash</div> <div class="align-items-center d-flex flex-grow-1 indent-1">
<ng-container i18n>Cash</ng-container>
@if (!hasImpersonationId && summary?.totalValueInBaseCurrency > 0) {
<gf-value
class="d-lg-inline-block d-none ml-2 small text-muted"
[isPercent]="true"
[locale]="locale"
[value]="isLoading ? undefined : cashPercentage"
/>
}
</div>
<div class="flex-column flex-wrap justify-content-end"> <div class="flex-column flex-wrap justify-content-end">
<gf-value <gf-value
class="justify-content-end" class="justify-content-end"
@ -177,85 +187,48 @@
/> />
</div> </div>
</div> </div>
<div class="flex-nowrap px-3 py-1 row"> @if (isLoading || summary?.emergencyFund?.cash > 0) {
<div class="align-items-center d-flex flex-grow-1 ml-4"> <div class="flex-nowrap px-3 py-1 row small">
<ng-container i18n>Buying Power</ng-container> <div class="flex-grow-1 indent-2 text-truncate" i18n>Buying Power</div>
@if ( <div class="flex-column flex-wrap justify-content-end">
!hasImpersonationId &&
summary?.totalValueInBaseCurrency > 0 &&
user?.settings?.isExperimentalFeatures
) {
<gf-value <gf-value
class="d-lg-inline-block d-none ml-2 small text-muted" class="justify-content-end"
[isPercent]="true" position="end"
[isCurrency]="true"
[locale]="locale" [locale]="locale"
[value]="isLoading ? undefined : buyingPowerPercentage" [precision]="precision"
[unit]="baseCurrency"
[value]="isLoading ? undefined : summary?.cash"
/> />
}
</div> </div>
<div class="align-items-center d-flex justify-content-end"> </div>
<div class="flex-nowrap px-3 py-1 row small">
<div class="flex-grow-1 indent-2 text-truncate" i18n>Emergency Fund</div>
<div class="flex-column flex-wrap justify-content-end">
<gf-value <gf-value
class="justify-content-end"
position="end"
[isCurrency]="true" [isCurrency]="true"
[locale]="locale" [locale]="locale"
[precision]="precision" [precision]="precision"
[unit]="baseCurrency" [unit]="baseCurrency"
[value]="isLoading ? undefined : summary?.cash" [value]="isLoading ? undefined : summary?.emergencyFund?.cash"
/> />
</div> </div>
</div> </div>
}
<div class="flex-nowrap px-3 py-1 row"> <div class="flex-nowrap px-3 py-1 row">
<div class="align-items-center d-flex flex-grow-1 ml-3"> <div class="align-items-center d-flex flex-grow-1 indent-1">
<ng-container i18n>Emergency Fund</ng-container> <ng-container i18n>Holdings</ng-container>
@if ( @if (!hasImpersonationId && summary?.totalValueInBaseCurrency > 0) {
!hasImpersonationId &&
summary?.totalValueInBaseCurrency > 0 &&
user?.settings?.isExperimentalFeatures
) {
<gf-value <gf-value
class="d-lg-inline-block d-none ml-2 small text-muted" class="d-lg-inline-block d-none ml-2 small text-muted"
[isPercent]="true" [isPercent]="true"
[locale]="locale" [locale]="locale"
[value]="isLoading ? undefined : emergencyFundPercentage" [value]="isLoading ? undefined : holdingsPercentage"
/> />
} }
</div> </div>
<div
class="align-items-center d-flex justify-content-end"
[class.cursor-pointer]="
hasPermissionToUpdateUserSettings &&
!user?.settings?.isRestrictedView &&
user?.subscription?.type !== 'Basic'
"
(click)="
hasPermissionToUpdateUserSettings &&
!user?.settings?.isRestrictedView &&
user?.subscription?.type !== 'Basic' &&
onEditEmergencyFund()
"
>
@if (
hasPermissionToUpdateUserSettings &&
!isLoading &&
!user?.settings?.isRestrictedView &&
user?.subscription?.type !== 'Basic'
) {
<ion-icon
class="mr-1 text-muted"
name="ellipsis-horizontal-circle-outline"
/>
}
<gf-value
class="justify-content-end"
[isCurrency]="true"
[locale]="locale"
[precision]="precision"
[unit]="baseCurrency"
[value]="isLoading ? undefined : summary?.emergencyFund?.total"
/>
</div>
</div>
<div class="flex-nowrap px-3 py-1 row">
<div class="flex-grow-1 ml-4 text-truncate" i18n>in Cash</div>
<div class="flex-column flex-wrap justify-content-end"> <div class="flex-column flex-wrap justify-content-end">
<gf-value <gf-value
class="justify-content-end" class="justify-content-end"
@ -264,12 +237,13 @@
[locale]="locale" [locale]="locale"
[precision]="precision" [precision]="precision"
[unit]="baseCurrency" [unit]="baseCurrency"
[value]="isLoading ? undefined : summary?.emergencyFund?.cash" [value]="isLoading ? undefined : holdingsInBaseCurrency"
/> />
</div> </div>
</div> </div>
<div class="flex-nowrap px-3 py-1 row"> @if (isLoading || summary?.emergencyFund?.assets > 0) {
<div class="flex-grow-1 ml-4 text-truncate" i18n>in Holdings</div> <div class="flex-nowrap px-3 py-1 row small">
<div class="flex-grow-1 indent-2 text-truncate" i18n>Emergency Fund</div>
<div class="flex-column flex-wrap justify-content-end"> <div class="flex-column flex-wrap justify-content-end">
<gf-value <gf-value
class="justify-content-end" class="justify-content-end"
@ -282,14 +256,11 @@
/> />
</div> </div>
</div> </div>
}
<div class="flex-nowrap px-3 py-1 row"> <div class="flex-nowrap px-3 py-1 row">
<div class="align-items-center d-flex flex-grow-1"> <div class="align-items-center d-flex flex-grow-1">
<ng-container i18n>Excluded from Analysis</ng-container> <ng-container i18n>Excluded from Analysis</ng-container>
@if ( @if (!hasImpersonationId && summary?.totalValueInBaseCurrency > 0) {
!hasImpersonationId &&
summary?.totalValueInBaseCurrency > 0 &&
user?.settings?.isExperimentalFeatures
) {
<gf-value <gf-value
class="d-lg-inline-block d-none ml-2 small text-muted" class="d-lg-inline-block d-none ml-2 small text-muted"
[isPercent]="true" [isPercent]="true"
@ -347,7 +318,7 @@
</div> </div>
</div> </div>
<div class="flex-nowrap px-3 py-1 row"> <div class="flex-nowrap px-3 py-1 row">
<div class="flex-grow-1 ml-3 text-truncate"> <div class="flex-grow-1 indent-1 text-truncate">
<ng-container i18n>Annualized Performance</ng-container> <ng-container i18n>Annualized Performance</ng-container>
</div> </div>
<div class="flex-column flex-wrap justify-content-end"> <div class="flex-column flex-wrap justify-content-end">
@ -368,6 +339,53 @@
<div class="row"> <div class="row">
<div class="col"><hr /></div> <div class="col"><hr /></div>
</div> </div>
<div class="flex-nowrap px-3 py-1 row">
<div class="align-items-center d-flex flex-grow-1">
<ng-container i18n>Emergency Fund</ng-container>
@if (!hasImpersonationId && summary?.totalValueInBaseCurrency > 0) {
<gf-value
class="d-lg-inline-block d-none ml-2 small text-muted"
[isPercent]="true"
[locale]="locale"
[value]="isLoading ? undefined : emergencyFundPercentage"
/>
}
</div>
<div
class="align-items-center d-flex justify-content-end"
[class.cursor-pointer]="
hasPermissionToUpdateUserSettings &&
!user?.settings?.isRestrictedView &&
user?.subscription?.type !== 'Basic'
"
(click)="
hasPermissionToUpdateUserSettings &&
!user?.settings?.isRestrictedView &&
user?.subscription?.type !== 'Basic' &&
onEditEmergencyFund()
"
>
@if (
hasPermissionToUpdateUserSettings &&
!isLoading &&
!user?.settings?.isRestrictedView &&
user?.subscription?.type !== 'Basic'
) {
<ion-icon
class="mr-1 text-muted"
name="ellipsis-horizontal-circle-outline"
/>
}
<gf-value
class="justify-content-end"
[isCurrency]="true"
[locale]="locale"
[precision]="precision"
[unit]="baseCurrency"
[value]="isLoading ? undefined : summary?.emergencyFund?.total"
/>
</div>
</div>
<div class="flex-nowrap px-3 py-1 row"> <div class="flex-nowrap px-3 py-1 row">
<div class="flex-grow-1 text-truncate" i18n>Interest</div> <div class="flex-grow-1 text-truncate" i18n>Interest</div>
<div class="justify-content-end"> <div class="justify-content-end">

8
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.scss

@ -1,3 +1,11 @@
:host { :host {
display: block; display: block;
.indent-1 {
margin-left: 1rem;
}
.indent-2 {
margin-left: 2rem;
}
} }

27
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts

@ -21,6 +21,7 @@ import {
ellipsisHorizontalCircleOutline, ellipsisHorizontalCircleOutline,
informationCircleOutline informationCircleOutline
} from 'ionicons/icons'; } from 'ionicons/icons';
import { isNumber } from 'lodash';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
@ -55,9 +56,10 @@ export class GfPortfolioSummaryComponent implements OnChanges {
addIcons({ ellipsisHorizontalCircleOutline, informationCircleOutline }); addIcons({ ellipsisHorizontalCircleOutline, informationCircleOutline });
} }
protected get buyingPowerPercentage() { protected get cashPercentage() {
return this.summary?.totalValueInBaseCurrency return this.summary?.totalValueInBaseCurrency
? this.summary.cash / this.summary.totalValueInBaseCurrency ? this.summary.totalCashInBaseCurrency /
this.summary.totalValueInBaseCurrency
: 0; : 0;
} }
@ -75,6 +77,27 @@ export class GfPortfolioSummaryComponent implements OnChanges {
: 0; : 0;
} }
protected get holdingsInBaseCurrency() {
if (
!isNumber(this.summary?.currentValueInBaseCurrency) ||
!isNumber(this.summary?.totalCashInBaseCurrency)
) {
return null;
}
return (
this.summary.currentValueInBaseCurrency -
this.summary.totalCashInBaseCurrency
);
}
protected get holdingsPercentage() {
return this.summary?.totalValueInBaseCurrency &&
isNumber(this.holdingsInBaseCurrency)
? this.holdingsInBaseCurrency / this.summary.totalValueInBaseCurrency
: 0;
}
public ngOnChanges() { public ngOnChanges() {
if (this.summary) { if (this.summary) {
if ( if (

Loading…
Cancel
Save