From a04099b12d23e2cbf71274aadd2868ff6826cd32 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sat, 2 May 2026 15:02:43 +0700 Subject: [PATCH] Task/improve type safety in fire page component (#6807) * Improve type safety --- .../portfolio/fire/fire-page.component.ts | 121 ++++++++++-------- .../app/pages/portfolio/fire/fire-page.html | 2 +- 2 files changed, 66 insertions(+), 57 deletions(-) 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 7b5b10c7d..4ab7d6392 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 @@ -16,7 +16,9 @@ import { CommonModule, NgStyle } from '@angular/common'; import { ChangeDetectorRef, Component, + computed, DestroyRef, + inject, OnInit } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @@ -42,33 +44,40 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; templateUrl: './fire-page.html' }) export class GfFirePageComponent implements OnInit { - public deviceType: string; - public fireWealth: FireWealth; - public hasImpersonationId: boolean; - public hasPermissionToUpdateUserSettings: boolean; - public isLoading = false; - public projectedTotalAmount: number; - public retirementDate: Date; - public safeWithdrawalRateControl = new FormControl(undefined); - public safeWithdrawalRateOptions = [0.025, 0.03, 0.035, 0.04, 0.045]; - public user: User; - public withdrawalRatePerMonth: Big; - public withdrawalRatePerMonthProjected: Big; - public withdrawalRatePerYear: Big; - public withdrawalRatePerYearProjected: Big; - - public constructor( - private changeDetectorRef: ChangeDetectorRef, - private dataService: DataService, - private destroyRef: DestroyRef, - private deviceService: DeviceDetectorService, - private impersonationStorageService: ImpersonationStorageService, - private userService: UserService - ) {} + protected readonly deviceType = computed( + () => this.deviceDetectorService.deviceInfo().deviceType + ); + + protected fireWealth: FireWealth; + protected hasImpersonationId: boolean; + protected hasPermissionToUpdateUserSettings: boolean; + protected isLoading = false; + protected retirementDate: Date; + protected readonly safeWithdrawalRateControl = new FormControl< + number | undefined + >(undefined); + protected readonly safeWithdrawalRateOptions = [ + 0.025, 0.03, 0.035, 0.04, 0.045 + ] as const; + protected user: User; + protected withdrawalRatePerMonth: Big; + protected withdrawalRatePerMonthProjected: Big; + protected withdrawalRatePerYear: Big; + protected withdrawalRatePerYearProjected: Big; + + private projectedTotalAmount: number; + + private readonly changeDetectorRef = inject(ChangeDetectorRef); + private readonly dataService = inject(DataService); + private readonly destroyRef = inject(DestroyRef); + private readonly deviceDetectorService = inject(DeviceDetectorService); + private readonly impersonationStorageService = inject( + ImpersonationStorageService + ); + private readonly userService = inject(UserService); public ngOnInit() { this.isLoading = true; - this.deviceType = this.deviceService.getDeviceInfo().deviceType; this.dataService .fetchPortfolioDetails() @@ -76,7 +85,7 @@ export class GfFirePageComponent implements OnInit { .subscribe(({ summary }) => { this.fireWealth = { today: { - valueInBaseCurrency: summary.fireWealth + valueInBaseCurrency: summary?.fireWealth ? summary.fireWealth.today.valueInBaseCurrency : 0 } @@ -104,7 +113,7 @@ export class GfFirePageComponent implements OnInit { this.safeWithdrawalRateControl.valueChanges .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((value) => { - this.onSafeWithdrawalRateChange(Number(value)); + this.updateSafeWithdrawalRate(Number(value)); }); this.userService.stateChanged @@ -133,7 +142,7 @@ export class GfFirePageComponent implements OnInit { }); } - public onAnnualInterestRateChange(annualInterestRate: number) { + protected onAnnualInterestRateChange(annualInterestRate: number) { this.dataService .putUserSetting({ annualInterestRate }) .pipe(takeUntilDestroyed(this.destroyRef)) @@ -149,7 +158,7 @@ export class GfFirePageComponent implements OnInit { }); } - public onCalculationComplete({ + protected onCalculationComplete({ projectedTotalAmount, retirementDate }: FireCalculationCompleteEvent) { @@ -161,11 +170,11 @@ export class GfFirePageComponent implements OnInit { this.isLoading = false; } - public onRetirementDateChange(retirementDate: Date) { + protected onProjectedTotalAmountChange(projectedTotalAmount: number) { this.dataService .putUserSetting({ - retirementDate: retirementDate.toISOString(), - projectedTotalAmount: null + projectedTotalAmount, + retirementDate: undefined }) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { @@ -180,9 +189,12 @@ export class GfFirePageComponent implements OnInit { }); } - public onSafeWithdrawalRateChange(safeWithdrawalRate: number) { + protected onRetirementDateChange(retirementDate: Date) { this.dataService - .putUserSetting({ safeWithdrawalRate }) + .putUserSetting({ + projectedTotalAmount: undefined, + retirementDate: retirementDate.toISOString() + }) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService @@ -191,15 +203,12 @@ export class GfFirePageComponent implements OnInit { .subscribe((user) => { this.user = user; - this.calculateWithdrawalRates(); - this.calculateWithdrawalRatesProjected(); - this.changeDetectorRef.markForCheck(); }); }); } - public onSavingsRateChange(savingsRate: number) { + protected onSavingsRateChange(savingsRate: number) { this.dataService .putUserSetting({ savingsRate }) .pipe(takeUntilDestroyed(this.destroyRef)) @@ -215,25 +224,6 @@ export class GfFirePageComponent implements OnInit { }); } - public onProjectedTotalAmountChange(projectedTotalAmount: number) { - this.dataService - .putUserSetting({ - projectedTotalAmount, - retirementDate: null - }) - .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(() => { - this.userService - .get(true) - .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe((user) => { - this.user = user; - - this.changeDetectorRef.markForCheck(); - }); - }); - } - private calculateWithdrawalRates() { if (this.fireWealth && this.user?.settings?.safeWithdrawalRate) { this.withdrawalRatePerYear = new Big( @@ -258,4 +248,23 @@ export class GfFirePageComponent implements OnInit { this.withdrawalRatePerYearProjected.div(12); } } + + private updateSafeWithdrawalRate(safeWithdrawalRate: number) { + this.dataService + .putUserSetting({ safeWithdrawalRate }) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((user) => { + this.user = user; + + this.calculateWithdrawalRates(); + this.calculateWithdrawalRatesProjected(); + + this.changeDetectorRef.markForCheck(); + }); + }); + } } diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.html b/apps/client/src/app/pages/portfolio/fire/fire-page.html index b441b2563..cabd7fcb4 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.html +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -13,7 +13,7 @@ [annualInterestRate]="user?.settings?.annualInterestRate" [colorScheme]="user?.settings?.colorScheme" [currency]="user?.settings?.baseCurrency" - [deviceType]="deviceType" + [deviceType]="deviceType()" [fireWealth]="fireWealth?.today.valueInBaseCurrency" [hasPermissionToUpdateUserSettings]=" !hasImpersonationId && hasPermissionToUpdateUserSettings