From f5e6f7dcfebf72f1658e67fecf5916ab7f2cad85 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 8 Jun 2024 18:44:57 +0200 Subject: [PATCH] Bugfix/fix initialization of fire calculator (#3470) * Fix initialization * Update changelog --- CHANGELOG.md | 4 ++ .../portfolio/fire/fire-page.component.ts | 7 +- .../fire-calculator.component.ts | 66 +++++++++++-------- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93142484a..d65761ca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the language localization for German (`de`) - Upgraded `prisma` from version `5.14.0` to `5.15.0` +### Fixed + +- Fixed an issue in the _FIRE_ calculator + ## 2.86.0 - 2024-06-07 ### Added diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts index e963a7bd9..c33b2c3f5 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts @@ -50,7 +50,12 @@ export class FirePageComponent implements OnDestroy, OnInit { .subscribe(({ summary }) => { this.fireWealth = summary.fireWealth ? new Big(summary.fireWealth) - : new Big(10000); + : new Big(0); + + if (this.user.subscription?.type === 'Basic') { + this.fireWealth = new Big(10000); + } + this.withdrawalRatePerYear = this.fireWealth.mul(4).div(100); this.withdrawalRatePerMonth = this.withdrawalRatePerYear.div(12); diff --git a/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts b/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts index bd52d8b79..aa8b2b90b 100644 --- a/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts +++ b/libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -11,6 +11,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + ElementRef, EventEmitter, Input, OnChanges, @@ -75,23 +76,23 @@ import { FireCalculatorService } from './fire-calculator.service'; templateUrl: './fire-calculator.component.html' }) export class GfFireCalculatorComponent implements OnChanges, OnDestroy { - @Input() annualInterestRate = 5; + @Input() annualInterestRate: number; @Input() colorScheme: ColorScheme; @Input() currency: string; @Input() deviceType: string; @Input() fireWealth: number; @Input() hasPermissionToUpdateUserSettings: boolean; @Input() locale = getLocale(); - @Input() projectedTotalAmount = 0; + @Input() projectedTotalAmount: number; @Input() retirementDate: Date; - @Input() savingsRate = 0; + @Input() savingsRate: number; @Output() annualInterestRateChanged = new EventEmitter(); @Output() projectedTotalAmountChanged = new EventEmitter(); @Output() retirementDateChanged = new EventEmitter(); @Output() savingsRateChanged = new EventEmitter(); - @ViewChild('chartCanvas') chartCanvas; + @ViewChild('chartCanvas') chartCanvas: ElementRef; public calculatorForm = this.formBuilder.group({ annualInterestRate: new FormControl(undefined), @@ -159,10 +160,10 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy { if (isNumber(this.fireWealth) && this.fireWealth >= 0) { this.calculatorForm.setValue( { - annualInterestRate: this.annualInterestRate, - paymentPerPeriod: this.savingsRate, - principalInvestmentAmount: 0, - projectedTotalAmount: this.projectedTotalAmount, + annualInterestRate: this.annualInterestRate ?? 5, + paymentPerPeriod: this.savingsRate ?? 0, + principalInvestmentAmount: this.fireWealth, + projectedTotalAmount: this.projectedTotalAmount ?? 0, retirementDate: this.retirementDate ?? this.DEFAULT_RETIREMENT_DATE }, { @@ -176,9 +177,12 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy { // Wait for the chartCanvas this.calculatorForm.patchValue( { - annualInterestRate: this.annualInterestRate, - principalInvestmentAmount: this.fireWealth, - paymentPerPeriod: this.savingsRate ?? 0, + annualInterestRate: + this.calculatorForm.get('annualInterestRate').value, + paymentPerPeriod: this.getPMT(), + principalInvestmentAmount: this.calculatorForm.get( + 'principalInvestmentAmount' + ).value, projectedTotalAmount: Number(this.getProjectedTotalAmount().toFixed(0)) ?? 0, retirementDate: @@ -406,14 +410,18 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy { } private getPeriodsToRetire(): number { - if (this.projectedTotalAmount) { - const periods = this.fireCalculatorService.calculatePeriodsToRetire({ + if (this.calculatorForm.get('projectedTotalAmount').value) { + let periods = this.fireCalculatorService.calculatePeriodsToRetire({ P: this.getP(), PMT: this.getPMT(), r: this.getR(), - totalAmount: this.projectedTotalAmount + totalAmount: this.calculatorForm.get('projectedTotalAmount').value }); + if (periods === Infinity) { + periods = Number.MAX_SAFE_INTEGER; + } + return periods; } else { const today = new Date(); @@ -429,23 +437,23 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy { } private getPMT() { - return this.savingsRate ?? 0; + return this.calculatorForm.get('paymentPerPeriod').value; } private getProjectedTotalAmount() { - if (this.projectedTotalAmount) { - return this.projectedTotalAmount || 0; - } else { - const { totalAmount } = - this.fireCalculatorService.calculateCompoundInterest({ - P: this.getP(), - periodInMonths: this.periodsToRetire, - PMT: this.getPMT(), - r: this.getR() - }); - - return totalAmount.toNumber(); + if (this.calculatorForm.get('projectedTotalAmount').value) { + return this.calculatorForm.get('projectedTotalAmount').value; } + + const { totalAmount } = + this.fireCalculatorService.calculateCompoundInterest({ + P: this.getP(), + periodInMonths: this.periodsToRetire, + PMT: this.getPMT(), + r: this.getR() + }); + + return totalAmount.toNumber(); } private getR() { @@ -453,6 +461,10 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy { } private getRetirementDate(): Date { + if (this.periodsToRetire === Number.MAX_SAFE_INTEGER) { + return undefined; + } + const monthsToRetire = this.periodsToRetire % 12; const yearsToRetire = Math.floor(this.periodsToRetire / 12);