From 9493f79f8e288581e0e9f2b539b69041731c0028 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sat, 28 Feb 2026 13:46:37 +0400 Subject: [PATCH] Task/improve type safety in portfolio filter form component (#6404) * fix(lib): resolve typescript errors in portfolio filter form * fix(lib): type safety in template * feat(lib): implement takeUntilDestroyed * feat(lib): replace constructor params with injections * feat(lib): change accounts to input signal * feat(lib): change assetClasses to input signal * feat(lib): change holdings to input signal * feat(lib): change tags to input signal * fix(lib): implement signal for disabled * fix(lib): implement model signal for disabled * fix(lib): reduce any types --- .../portfolio-filter-form.component.html | 12 ++-- ...portfolio-filter-form.component.stories.ts | 4 +- .../portfolio-filter-form.component.ts | 69 ++++++++++--------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html b/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html index e017d33d6..f5dbac698 100644 --- a/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html +++ b/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html @@ -4,14 +4,14 @@ Account - @for (account of accounts; track account.id) { + @for (account of accounts(); track account.id) {
@if (account.platform?.url) { } {{ account.name }} @@ -32,7 +32,7 @@ filterForm.get('holding')?.value?.name }} - @for (holding of holdings; track holding.name) { + @for (holding of holdings(); track holding.name) {
Tag - @for (tag of tags; track tag.id) { + @for (tag of tags(); track tag.id) { {{ tag.label }} } @@ -64,7 +64,7 @@ Asset Class - @for (assetClass of assetClasses; track assetClass.id) { + @for (assetClass of assetClasses(); track assetClass.id) { {{ assetClass.label }} diff --git a/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.stories.ts b/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.stories.ts index 710a4e9c5..665bec3e4 100644 --- a/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.stories.ts +++ b/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.stories.ts @@ -40,7 +40,7 @@ export const Default: Story = { { id: 'COMMODITY', label: 'Commodity', type: 'ASSET_CLASS' }, { id: 'EQUITY', label: 'Equity', type: 'ASSET_CLASS' }, { id: 'FIXED_INCOME', label: 'Fixed Income', type: 'ASSET_CLASS' } - ] as any, + ], holdings: [ { currency: 'USD', @@ -66,7 +66,7 @@ export const Default: Story = { label: 'Retirement Fund', type: 'TAG' } - ] as any, + ], disabled: false } }; diff --git a/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.ts b/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.ts index afbe5af4e..c1f82315c 100644 --- a/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.ts +++ b/libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.ts @@ -8,12 +8,15 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - Input, + DestroyRef, OnChanges, - OnDestroy, OnInit, - forwardRef + forwardRef, + inject, + input, + model } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ControlValueAccessor, FormBuilder, @@ -25,7 +28,6 @@ import { } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatSelectModule } from '@angular/material/select'; -import { Subject, takeUntil } from 'rxjs'; import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component'; import { PortfolioFilterFormValue } from './interfaces'; @@ -53,33 +55,37 @@ import { PortfolioFilterFormValue } from './interfaces'; templateUrl: './portfolio-filter-form.component.html' }) export class GfPortfolioFilterFormComponent - implements ControlValueAccessor, OnInit, OnChanges, OnDestroy + implements ControlValueAccessor, OnChanges, OnInit { - @Input() accounts: AccountWithPlatform[] = []; - @Input() assetClasses: Filter[] = []; - @Input() holdings: PortfolioPosition[] = []; - @Input() tags: Filter[] = []; - @Input() disabled = false; - - public filterForm: FormGroup; - - private unsubscribeSubject = new Subject(); - - public constructor( - private changeDetectorRef: ChangeDetectorRef, - private formBuilder: FormBuilder - ) { + public readonly accounts = input([]); + public readonly assetClasses = input([]); + public readonly disabled = model(false); + public readonly holdings = input([]); + public readonly tags = input([]); + + public filterForm: FormGroup<{ + account: FormControl; + assetClass: FormControl; + holding: FormControl; + tag: FormControl; + }>; + + private readonly changeDetectorRef = inject(ChangeDetectorRef); + private readonly destroyRef = inject(DestroyRef); + private readonly formBuilder = inject(FormBuilder); + + public constructor() { this.filterForm = this.formBuilder.group({ - account: new FormControl(null), - assetClass: new FormControl(null), - holding: new FormControl(null), - tag: new FormControl(null) + account: new FormControl(null), + assetClass: new FormControl(null), + holding: new FormControl(null), + tag: new FormControl(null) }); } public ngOnInit() { this.filterForm.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((value) => { this.onChange(value as PortfolioFilterFormValue); this.onTouched(); @@ -108,7 +114,7 @@ export class GfPortfolioFilterFormComponent } public ngOnChanges() { - if (this.disabled) { + if (this.disabled()) { this.filterForm.disable({ emitEvent: false }); } else { this.filterForm.enable({ emitEvent: false }); @@ -116,9 +122,9 @@ export class GfPortfolioFilterFormComponent const tagControl = this.filterForm.get('tag'); - if (this.tags.length === 0) { + if (this.tags().length === 0) { tagControl?.disable({ emitEvent: false }); - } else if (!this.disabled) { + } else if (!this.disabled()) { tagControl?.enable({ emitEvent: false }); } @@ -134,9 +140,9 @@ export class GfPortfolioFilterFormComponent } public setDisabledState(isDisabled: boolean) { - this.disabled = isDisabled; + this.disabled.set(isDisabled); - if (this.disabled) { + if (this.disabled()) { this.filterForm.disable({ emitEvent: false }); } else { this.filterForm.enable({ emitEvent: false }); @@ -161,11 +167,6 @@ export class GfPortfolioFilterFormComponent } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars private onChange = (_value: PortfolioFilterFormValue): void => { // ControlValueAccessor onChange callback