From 8a50b8c922ad7dedf137268224c24bb4b310b3fd Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Thu, 12 Feb 2026 02:38:13 +0700 Subject: [PATCH] Task/improve type safety in accounts table component (#6307) * fix(lib): prevent table data source to be created every time * fix(lib): remove unused unsubscribeSubject variable * fix(lib): change to protected methods * feat(lib): change locale to signal input * feat(lib): remove unused deviceType input * feat(lib): change hasPermissionToOpenDetails to signal input * feat(lib): change showFooter to signal input * feat(lib): change activitiesCount to signal input * feat(lib): change baseCurrency to signal input * feat(lib): change totalBalanceInBaseCurrency to signal input * feat(lib): change totalValueInBaseCurrency to signal input * feat(lib): change outputs to signal outputs --- .../holding-detail-dialog.html | 1 - .../src/app/pages/accounts/accounts-page.html | 1 - .../accounts-table.component.html | 32 ++++----- .../accounts-table.component.stories.ts | 3 - .../accounts-table.component.ts | 71 +++++++++---------- 5 files changed, 50 insertions(+), 58 deletions(-) diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index 27df91a17..86f4676f3 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -377,7 +377,6 @@ @@ -19,7 +19,7 @@ matSort matSortActive="name" matSortDirection="asc" - [dataSource]="dataSource()" + [dataSource]="dataSource" > - {{ baseCurrency }} + {{ baseCurrency() }} @@ -129,7 +129,7 @@ {{ element.activitiesCount }} - {{ activitiesCount }} + {{ activitiesCount() }} @@ -150,7 +150,7 @@ @@ -162,8 +162,8 @@ @@ -185,7 +185,7 @@ @@ -197,8 +197,8 @@ @@ -220,7 +220,7 @@ @@ -232,8 +232,8 @@ @@ -255,7 +255,7 @@ @@ -341,14 +341,14 @@ *matRowDef="let row; columns: displayedColumns()" mat-row [ngClass]="{ - 'cursor-pointer': hasPermissionToOpenDetails + 'cursor-pointer': hasPermissionToOpenDetails() }" (click)="onOpenAccountDetailDialog(row.id)" > diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts b/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts index 594db4c6a..62a01164f 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts @@ -111,7 +111,6 @@ export const Loading: Story = { args: { accounts: undefined, baseCurrency: 'USD', - deviceType: 'desktop', hasPermissionToOpenDetails: false, locale: 'en-US', showActions: false, @@ -129,7 +128,6 @@ export const Default: Story = { accounts, activitiesCount: 12, baseCurrency: 'USD', - deviceType: 'desktop', hasPermissionToOpenDetails: false, locale: 'en-US', showActions: false, @@ -149,7 +147,6 @@ export const WithoutFooter: Story = { accounts, activitiesCount: 12, baseCurrency: 'USD', - deviceType: 'desktop', hasPermissionToOpenDetails: false, locale: 'en-US', showActions: false, diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.ts b/libs/ui/src/lib/accounts-table/accounts-table.component.ts index 834e33fb3..d486b775f 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.ts +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.ts @@ -8,13 +8,11 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, - EventEmitter, - Input, - OnDestroy, - Output, computed, + effect, inject, input, + output, viewChild } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; @@ -35,7 +33,6 @@ import { walletOutline } from 'ionicons/icons'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -55,35 +52,29 @@ import { Subject } from 'rxjs'; styleUrls: ['./accounts-table.component.scss'], templateUrl: './accounts-table.component.html' }) -export class GfAccountsTableComponent implements OnDestroy { - @Input() activitiesCount: number; - @Input() baseCurrency: string; - @Input() deviceType: string; - @Input() hasPermissionToOpenDetails = true; - @Input() locale = getLocale(); - @Input() showFooter = true; - @Input() totalBalanceInBaseCurrency: number; - @Input() totalValueInBaseCurrency: number; - - @Output() accountDeleted = new EventEmitter(); - @Output() accountToUpdate = new EventEmitter(); - @Output() transferBalance = new EventEmitter(); - +export class GfAccountsTableComponent { public readonly accounts = input.required(); + public readonly activitiesCount = input(); + public readonly baseCurrency = input(); + public readonly hasPermissionToOpenDetails = input(true); + public readonly locale = input(getLocale()); public readonly showActions = input(); public readonly showActivitiesCount = input(true); public readonly showAllocationInPercentage = input(); public readonly showBalance = input(true); + public readonly showFooter = input(true); public readonly showValue = input(true); public readonly showValueInBaseCurrency = input(false); + public readonly totalBalanceInBaseCurrency = input(); + public readonly totalValueInBaseCurrency = input(); + + public readonly accountDeleted = output(); + public readonly accountToUpdate = output(); + public readonly transferBalance = output(); + public readonly sort = viewChild.required(MatSort); - protected readonly dataSource = computed(() => { - const dataSource = new MatTableDataSource(this.accounts()); - dataSource.sortingDataAccessor = getLowercase; - dataSource.sort = this.sort(); - return dataSource; - }); + protected readonly dataSource = new MatTableDataSource([]); protected readonly displayedColumns = computed(() => { const columns = ['status', 'account', 'platform']; @@ -123,7 +114,6 @@ export class GfAccountsTableComponent implements OnDestroy { private readonly notificationService = inject(NotificationService); private readonly router = inject(Router); - private readonly unsubscribeSubject = new Subject(); public constructor() { addIcons({ @@ -135,9 +125,21 @@ export class GfAccountsTableComponent implements OnDestroy { trashOutline, walletOutline }); + + this.dataSource.sortingDataAccessor = getLowercase; + + // Reactive data update + effect(() => { + this.dataSource.data = this.accounts(); + }); + + // Reactive view connection + effect(() => { + this.dataSource.sort = this.sort(); + }); } - public onDeleteAccount(aId: string) { + protected onDeleteAccount(aId: string) { this.notificationService.confirm({ confirmFn: () => { this.accountDeleted.emit(aId); @@ -147,30 +149,25 @@ export class GfAccountsTableComponent implements OnDestroy { }); } - public onOpenAccountDetailDialog(accountId: string) { - if (this.hasPermissionToOpenDetails) { + protected onOpenAccountDetailDialog(accountId: string) { + if (this.hasPermissionToOpenDetails()) { this.router.navigate([], { queryParams: { accountId, accountDetailDialog: true } }); } } - public onOpenComment(aComment: string) { + protected onOpenComment(aComment: string) { this.notificationService.alert({ title: aComment }); } - public onTransferBalance() { + protected onTransferBalance() { this.transferBalance.emit(); } - public onUpdateAccount(aAccount: Account) { + protected onUpdateAccount(aAccount: Account) { this.accountToUpdate.emit(aAccount); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } }