Browse Source

Bugfix/fix initialization of fire calculator (#3470)

* Fix initialization

* Update changelog
pull/3471/head
Thomas Kaul 7 months ago
committed by GitHub
parent
commit
f5e6f7dcfe
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 7
      apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
  3. 50
      libs/ui/src/lib/fire-calculator/fire-calculator.component.ts

4
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`) - Improved the language localization for German (`de`)
- Upgraded `prisma` from version `5.14.0` to `5.15.0` - 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 ## 2.86.0 - 2024-06-07
### Added ### Added

7
apps/client/src/app/pages/portfolio/fire/fire-page.component.ts

@ -50,7 +50,12 @@ export class FirePageComponent implements OnDestroy, OnInit {
.subscribe(({ summary }) => { .subscribe(({ summary }) => {
this.fireWealth = summary.fireWealth this.fireWealth = summary.fireWealth
? new Big(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.withdrawalRatePerYear = this.fireWealth.mul(4).div(100);
this.withdrawalRatePerMonth = this.withdrawalRatePerYear.div(12); this.withdrawalRatePerMonth = this.withdrawalRatePerYear.div(12);

50
libs/ui/src/lib/fire-calculator/fire-calculator.component.ts

@ -11,6 +11,7 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
ElementRef,
EventEmitter, EventEmitter,
Input, Input,
OnChanges, OnChanges,
@ -75,23 +76,23 @@ import { FireCalculatorService } from './fire-calculator.service';
templateUrl: './fire-calculator.component.html' templateUrl: './fire-calculator.component.html'
}) })
export class GfFireCalculatorComponent implements OnChanges, OnDestroy { export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
@Input() annualInterestRate = 5; @Input() annualInterestRate: number;
@Input() colorScheme: ColorScheme; @Input() colorScheme: ColorScheme;
@Input() currency: string; @Input() currency: string;
@Input() deviceType: string; @Input() deviceType: string;
@Input() fireWealth: number; @Input() fireWealth: number;
@Input() hasPermissionToUpdateUserSettings: boolean; @Input() hasPermissionToUpdateUserSettings: boolean;
@Input() locale = getLocale(); @Input() locale = getLocale();
@Input() projectedTotalAmount = 0; @Input() projectedTotalAmount: number;
@Input() retirementDate: Date; @Input() retirementDate: Date;
@Input() savingsRate = 0; @Input() savingsRate: number;
@Output() annualInterestRateChanged = new EventEmitter<number>(); @Output() annualInterestRateChanged = new EventEmitter<number>();
@Output() projectedTotalAmountChanged = new EventEmitter<number>(); @Output() projectedTotalAmountChanged = new EventEmitter<number>();
@Output() retirementDateChanged = new EventEmitter<Date>(); @Output() retirementDateChanged = new EventEmitter<Date>();
@Output() savingsRateChanged = new EventEmitter<number>(); @Output() savingsRateChanged = new EventEmitter<number>();
@ViewChild('chartCanvas') chartCanvas; @ViewChild('chartCanvas') chartCanvas: ElementRef<HTMLCanvasElement>;
public calculatorForm = this.formBuilder.group({ public calculatorForm = this.formBuilder.group({
annualInterestRate: new FormControl<number>(undefined), annualInterestRate: new FormControl<number>(undefined),
@ -159,10 +160,10 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
if (isNumber(this.fireWealth) && this.fireWealth >= 0) { if (isNumber(this.fireWealth) && this.fireWealth >= 0) {
this.calculatorForm.setValue( this.calculatorForm.setValue(
{ {
annualInterestRate: this.annualInterestRate, annualInterestRate: this.annualInterestRate ?? 5,
paymentPerPeriod: this.savingsRate, paymentPerPeriod: this.savingsRate ?? 0,
principalInvestmentAmount: 0, principalInvestmentAmount: this.fireWealth,
projectedTotalAmount: this.projectedTotalAmount, projectedTotalAmount: this.projectedTotalAmount ?? 0,
retirementDate: this.retirementDate ?? this.DEFAULT_RETIREMENT_DATE retirementDate: this.retirementDate ?? this.DEFAULT_RETIREMENT_DATE
}, },
{ {
@ -176,9 +177,12 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
// Wait for the chartCanvas // Wait for the chartCanvas
this.calculatorForm.patchValue( this.calculatorForm.patchValue(
{ {
annualInterestRate: this.annualInterestRate, annualInterestRate:
principalInvestmentAmount: this.fireWealth, this.calculatorForm.get('annualInterestRate').value,
paymentPerPeriod: this.savingsRate ?? 0, paymentPerPeriod: this.getPMT(),
principalInvestmentAmount: this.calculatorForm.get(
'principalInvestmentAmount'
).value,
projectedTotalAmount: projectedTotalAmount:
Number(this.getProjectedTotalAmount().toFixed(0)) ?? 0, Number(this.getProjectedTotalAmount().toFixed(0)) ?? 0,
retirementDate: retirementDate:
@ -406,14 +410,18 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
} }
private getPeriodsToRetire(): number { private getPeriodsToRetire(): number {
if (this.projectedTotalAmount) { if (this.calculatorForm.get('projectedTotalAmount').value) {
const periods = this.fireCalculatorService.calculatePeriodsToRetire({ let periods = this.fireCalculatorService.calculatePeriodsToRetire({
P: this.getP(), P: this.getP(),
PMT: this.getPMT(), PMT: this.getPMT(),
r: this.getR(), r: this.getR(),
totalAmount: this.projectedTotalAmount totalAmount: this.calculatorForm.get('projectedTotalAmount').value
}); });
if (periods === Infinity) {
periods = Number.MAX_SAFE_INTEGER;
}
return periods; return periods;
} else { } else {
const today = new Date(); const today = new Date();
@ -429,13 +437,14 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
} }
private getPMT() { private getPMT() {
return this.savingsRate ?? 0; return this.calculatorForm.get('paymentPerPeriod').value;
} }
private getProjectedTotalAmount() { private getProjectedTotalAmount() {
if (this.projectedTotalAmount) { if (this.calculatorForm.get('projectedTotalAmount').value) {
return this.projectedTotalAmount || 0; return this.calculatorForm.get('projectedTotalAmount').value;
} else { }
const { totalAmount } = const { totalAmount } =
this.fireCalculatorService.calculateCompoundInterest({ this.fireCalculatorService.calculateCompoundInterest({
P: this.getP(), P: this.getP(),
@ -446,13 +455,16 @@ export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
return totalAmount.toNumber(); return totalAmount.toNumber();
} }
}
private getR() { private getR() {
return this.calculatorForm.get('annualInterestRate').value / 100; return this.calculatorForm.get('annualInterestRate').value / 100;
} }
private getRetirementDate(): Date { private getRetirementDate(): Date {
if (this.periodsToRetire === Number.MAX_SAFE_INTEGER) {
return undefined;
}
const monthsToRetire = this.periodsToRetire % 12; const monthsToRetire = this.periodsToRetire % 12;
const yearsToRetire = Math.floor(this.periodsToRetire / 12); const yearsToRetire = Math.floor(this.periodsToRetire / 12);

Loading…
Cancel
Save