Browse Source

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
pull/6304/head^2
Kenrick Tandrian 3 weeks ago
committed by GitHub
parent
commit
8a50b8c922
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html
  2. 1
      apps/client/src/app/pages/accounts/accounts-page.html
  3. 32
      libs/ui/src/lib/accounts-table/accounts-table.component.html
  4. 3
      libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts
  5. 71
      libs/ui/src/lib/accounts-table/accounts-table.component.ts

1
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html

@ -377,7 +377,6 @@
<gf-accounts-table <gf-accounts-table
[accounts]="accounts" [accounts]="accounts"
[baseCurrency]="user?.settings?.baseCurrency" [baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="data.deviceType"
[hasPermissionToOpenDetails]="false" [hasPermissionToOpenDetails]="false"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[showActivitiesCount]="false" [showActivitiesCount]="false"

1
apps/client/src/app/pages/accounts/accounts-page.html

@ -6,7 +6,6 @@
[accounts]="accounts" [accounts]="accounts"
[activitiesCount]="activitiesCount" [activitiesCount]="activitiesCount"
[baseCurrency]="user?.settings?.baseCurrency" [baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="deviceType"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[showActions]=" [showActions]="
!hasImpersonationId && !hasImpersonationId &&

32
libs/ui/src/lib/accounts-table/accounts-table.component.html

@ -3,7 +3,7 @@
<button <button
class="align-items-center d-flex" class="align-items-center d-flex"
mat-stroked-button mat-stroked-button
[disabled]="dataSource()?.data.length < 2" [disabled]="dataSource?.data.length < 2"
(click)="onTransferBalance()" (click)="onTransferBalance()"
> >
<ion-icon class="mr-2" name="arrow-redo-outline" /> <ion-icon class="mr-2" name="arrow-redo-outline" />
@ -19,7 +19,7 @@
matSort matSort
matSortActive="name" matSortActive="name"
matSortDirection="asc" matSortDirection="asc"
[dataSource]="dataSource()" [dataSource]="dataSource"
> >
<ng-container matColumnDef="status"> <ng-container matColumnDef="status">
<th <th
@ -79,7 +79,7 @@
{{ element.currency }} {{ element.currency }}
</td> </td>
<td *matFooterCellDef class="d-none d-lg-table-cell px-1" mat-footer-cell> <td *matFooterCellDef class="d-none d-lg-table-cell px-1" mat-footer-cell>
{{ baseCurrency }} {{ baseCurrency() }}
</td> </td>
</ng-container> </ng-container>
@ -129,7 +129,7 @@
{{ element.activitiesCount }} {{ element.activitiesCount }}
</td> </td>
<td *matFooterCellDef class="px-1 text-right" mat-footer-cell> <td *matFooterCellDef class="px-1 text-right" mat-footer-cell>
{{ activitiesCount }} {{ activitiesCount() }}
</td> </td>
</ng-container> </ng-container>
@ -150,7 +150,7 @@
<gf-value <gf-value
class="d-inline-block justify-content-end" class="d-inline-block justify-content-end"
[isCurrency]="true" [isCurrency]="true"
[locale]="locale" [locale]="locale()"
[value]="element.balance" [value]="element.balance"
/> />
</td> </td>
@ -162,8 +162,8 @@
<gf-value <gf-value
class="d-inline-block justify-content-end" class="d-inline-block justify-content-end"
[isCurrency]="true" [isCurrency]="true"
[locale]="locale" [locale]="locale()"
[value]="totalBalanceInBaseCurrency" [value]="totalBalanceInBaseCurrency()"
/> />
</td> </td>
</ng-container> </ng-container>
@ -185,7 +185,7 @@
<gf-value <gf-value
class="d-inline-block justify-content-end" class="d-inline-block justify-content-end"
[isCurrency]="true" [isCurrency]="true"
[locale]="locale" [locale]="locale()"
[value]="element.value" [value]="element.value"
/> />
</td> </td>
@ -197,8 +197,8 @@
<gf-value <gf-value
class="d-inline-block justify-content-end" class="d-inline-block justify-content-end"
[isCurrency]="true" [isCurrency]="true"
[locale]="locale" [locale]="locale()"
[value]="totalValueInBaseCurrency" [value]="totalValueInBaseCurrency()"
/> />
</td> </td>
</ng-container> </ng-container>
@ -220,7 +220,7 @@
<gf-value <gf-value
class="d-inline-block justify-content-end" class="d-inline-block justify-content-end"
[isCurrency]="true" [isCurrency]="true"
[locale]="locale" [locale]="locale()"
[value]="element.valueInBaseCurrency" [value]="element.valueInBaseCurrency"
/> />
</td> </td>
@ -232,8 +232,8 @@
<gf-value <gf-value
class="d-inline-block justify-content-end" class="d-inline-block justify-content-end"
[isCurrency]="true" [isCurrency]="true"
[locale]="locale" [locale]="locale()"
[value]="totalValueInBaseCurrency" [value]="totalValueInBaseCurrency()"
/> />
</td> </td>
</ng-container> </ng-container>
@ -255,7 +255,7 @@
<gf-value <gf-value
class="d-inline-block justify-content-end" class="d-inline-block justify-content-end"
[isPercent]="true" [isPercent]="true"
[locale]="locale" [locale]="locale()"
[precision]="2" [precision]="2"
[value]="element.allocationInPercentage" [value]="element.allocationInPercentage"
/> />
@ -341,14 +341,14 @@
*matRowDef="let row; columns: displayedColumns()" *matRowDef="let row; columns: displayedColumns()"
mat-row mat-row
[ngClass]="{ [ngClass]="{
'cursor-pointer': hasPermissionToOpenDetails 'cursor-pointer': hasPermissionToOpenDetails()
}" }"
(click)="onOpenAccountDetailDialog(row.id)" (click)="onOpenAccountDetailDialog(row.id)"
></tr> ></tr>
<tr <tr
*matFooterRowDef="displayedColumns()" *matFooterRowDef="displayedColumns()"
mat-footer-row mat-footer-row
[ngClass]="{ 'd-none': isLoading() || !showFooter }" [ngClass]="{ 'd-none': isLoading() || !showFooter() }"
></tr> ></tr>
</table> </table>
</div> </div>

3
libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts

@ -111,7 +111,6 @@ export const Loading: Story = {
args: { args: {
accounts: undefined, accounts: undefined,
baseCurrency: 'USD', baseCurrency: 'USD',
deviceType: 'desktop',
hasPermissionToOpenDetails: false, hasPermissionToOpenDetails: false,
locale: 'en-US', locale: 'en-US',
showActions: false, showActions: false,
@ -129,7 +128,6 @@ export const Default: Story = {
accounts, accounts,
activitiesCount: 12, activitiesCount: 12,
baseCurrency: 'USD', baseCurrency: 'USD',
deviceType: 'desktop',
hasPermissionToOpenDetails: false, hasPermissionToOpenDetails: false,
locale: 'en-US', locale: 'en-US',
showActions: false, showActions: false,
@ -149,7 +147,6 @@ export const WithoutFooter: Story = {
accounts, accounts,
activitiesCount: 12, activitiesCount: 12,
baseCurrency: 'USD', baseCurrency: 'USD',
deviceType: 'desktop',
hasPermissionToOpenDetails: false, hasPermissionToOpenDetails: false,
locale: 'en-US', locale: 'en-US',
showActions: false, showActions: false,

71
libs/ui/src/lib/accounts-table/accounts-table.component.ts

@ -8,13 +8,11 @@ import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
EventEmitter,
Input,
OnDestroy,
Output,
computed, computed,
effect,
inject, inject,
input, input,
output,
viewChild viewChild
} from '@angular/core'; } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
@ -35,7 +33,6 @@ import {
walletOutline walletOutline
} from 'ionicons/icons'; } from 'ionicons/icons';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject } from 'rxjs';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
@ -55,35 +52,29 @@ import { Subject } from 'rxjs';
styleUrls: ['./accounts-table.component.scss'], styleUrls: ['./accounts-table.component.scss'],
templateUrl: './accounts-table.component.html' templateUrl: './accounts-table.component.html'
}) })
export class GfAccountsTableComponent implements OnDestroy { export class GfAccountsTableComponent {
@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<string>();
@Output() accountToUpdate = new EventEmitter<Account>();
@Output() transferBalance = new EventEmitter<void>();
public readonly accounts = input.required<Account[] | undefined>(); public readonly accounts = input.required<Account[] | undefined>();
public readonly activitiesCount = input<number>();
public readonly baseCurrency = input<string>();
public readonly hasPermissionToOpenDetails = input(true);
public readonly locale = input(getLocale());
public readonly showActions = input<boolean>(); public readonly showActions = input<boolean>();
public readonly showActivitiesCount = input(true); public readonly showActivitiesCount = input(true);
public readonly showAllocationInPercentage = input<boolean>(); public readonly showAllocationInPercentage = input<boolean>();
public readonly showBalance = input(true); public readonly showBalance = input(true);
public readonly showFooter = input(true);
public readonly showValue = input(true); public readonly showValue = input(true);
public readonly showValueInBaseCurrency = input(false); public readonly showValueInBaseCurrency = input(false);
public readonly totalBalanceInBaseCurrency = input<number>();
public readonly totalValueInBaseCurrency = input<number>();
public readonly accountDeleted = output<string>();
public readonly accountToUpdate = output<Account>();
public readonly transferBalance = output<void>();
public readonly sort = viewChild.required(MatSort); public readonly sort = viewChild.required(MatSort);
protected readonly dataSource = computed(() => { protected readonly dataSource = new MatTableDataSource<Account>([]);
const dataSource = new MatTableDataSource<Account>(this.accounts());
dataSource.sortingDataAccessor = getLowercase;
dataSource.sort = this.sort();
return dataSource;
});
protected readonly displayedColumns = computed(() => { protected readonly displayedColumns = computed(() => {
const columns = ['status', 'account', 'platform']; const columns = ['status', 'account', 'platform'];
@ -123,7 +114,6 @@ export class GfAccountsTableComponent implements OnDestroy {
private readonly notificationService = inject(NotificationService); private readonly notificationService = inject(NotificationService);
private readonly router = inject(Router); private readonly router = inject(Router);
private readonly unsubscribeSubject = new Subject<void>();
public constructor() { public constructor() {
addIcons({ addIcons({
@ -135,9 +125,21 @@ export class GfAccountsTableComponent implements OnDestroy {
trashOutline, trashOutline,
walletOutline 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({ this.notificationService.confirm({
confirmFn: () => { confirmFn: () => {
this.accountDeleted.emit(aId); this.accountDeleted.emit(aId);
@ -147,30 +149,25 @@ export class GfAccountsTableComponent implements OnDestroy {
}); });
} }
public onOpenAccountDetailDialog(accountId: string) { protected onOpenAccountDetailDialog(accountId: string) {
if (this.hasPermissionToOpenDetails) { if (this.hasPermissionToOpenDetails()) {
this.router.navigate([], { this.router.navigate([], {
queryParams: { accountId, accountDetailDialog: true } queryParams: { accountId, accountDetailDialog: true }
}); });
} }
} }
public onOpenComment(aComment: string) { protected onOpenComment(aComment: string) {
this.notificationService.alert({ this.notificationService.alert({
title: aComment title: aComment
}); });
} }
public onTransferBalance() { protected onTransferBalance() {
this.transferBalance.emit(); this.transferBalance.emit();
} }
public onUpdateAccount(aAccount: Account) { protected onUpdateAccount(aAccount: Account) {
this.accountToUpdate.emit(aAccount); this.accountToUpdate.emit(aAccount);
} }
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
} }

Loading…
Cancel
Save