feat: accounts list — active-only filter, date range & as-on-date search, modern UI

- Show only active accounts (status=300) for SB/CA/FD/RD lists; status sent as query param
- Add FROM/TO date range filter (API fires only when both are set) and independent AS ON DATE filter
- Restrict date pickers to today max (no future date selection)
- Default sort: latest accounts on top (ORDER BY id DESC)
- Full UI redesign: accent header, monospace account pill, client avatar, modern badges
- AccountsService: added status, fromDate, toDate, asOnDate to AccountListParams and all 4 methods

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jaanu423
2026-05-21 13:53:58 +05:30
co-authored by Claude Sonnet 4.6
parent 45d4397b0e
commit 846b2484d7
4 changed files with 570 additions and 348 deletions
@@ -9,71 +9,105 @@
<div class="acl-page">
<!-- Header -->
<div class="acl-header" [ngClass]="config.accentClass">
<div class="acl-header__left">
<div class="acl-header__icon-wrap">
<fa-icon [icon]="config.icon"></fa-icon>
</div>
<div>
<h2 class="acl-header__title">{{ config.label }}</h2>
<span class="acl-header__subtitle">
@if (!isLoading) {
{{ totalRecords }} total records
} @else {
Loading...
}
</span>
</div>
<div class="acl-header__icon">
<fa-icon [icon]="config.icon"></fa-icon>
</div>
<div class="acl-header__text">
<h2 class="acl-header__title">{{ config.label }}</h2>
<span class="acl-header__count">
@if (isLoading) {
Loading...
} @else {
{{ totalRecords }} active accounts
}
</span>
</div>
</div>
<!-- Toolbar -->
<div class="acl-toolbar">
<div class="acl-search-field">
<fa-icon icon="search" class="acl-search-field__icon"></fa-icon>
<!-- Search Bar -->
<div class="acl-search-wrap">
<div class="acl-search">
<fa-icon icon="search" class="acl-search__icon"></fa-icon>
<input
[formControl]="searchControl"
class="acl-search-field__input"
[placeholder]="searchType === 'accountNo' ? 'Search by account number...' : 'Search by client name...'"
class="acl-search__input"
[placeholder]="searchType === 'accountNo' ? 'Search by account number…' : 'Search by client name…'"
/>
@if (searchControl.value) {
<button class="acl-search-field__clear" (click)="clearSearch()" matTooltip="Clear">
<button class="acl-search__clear" (click)="clearSearch()">
<fa-icon icon="times"></fa-icon>
</button>
}
</div>
<button
class="acl-toggle-btn"
class="acl-btn acl-btn--toggle"
(click)="toggleSearchType()"
[matTooltip]="'Switch to ' + (searchType === 'accountNo' ? 'client name' : 'account number') + ' search'"
>
<fa-icon icon="exchange-alt"></fa-icon>
{{ searchType === 'accountNo' ? 'Acct No' : 'Client' }}
</button>
<button class="acl-refresh-btn" (click)="loadAccounts()" matTooltip="Refresh">
<button class="acl-btn acl-btn--icon" (click)="loadAccounts()" matTooltip="Refresh">
<fa-icon icon="sync-alt"></fa-icon>
</button>
</div>
<!-- Table Card -->
<div class="acl-table-card">
<!-- Date Filters -->
<div class="acl-filters">
<div class="acl-filters__group">
<div class="acl-datepick">
<span class="acl-datepick__label">From</span>
<input type="date" class="acl-datepick__input" [formControl]="fromDateControl" [max]="today" />
</div>
<div class="acl-filters__arrow">
<fa-icon icon="arrow-right"></fa-icon>
</div>
<div class="acl-datepick">
<span class="acl-datepick__label">To</span>
<input type="date" class="acl-datepick__input" [formControl]="toDateControl" [max]="today" />
</div>
</div>
<div class="acl-filters__sep"></div>
<div class="acl-datepick acl-datepick--ason">
<span class="acl-datepick__label">
<fa-icon icon="clock"></fa-icon>
As On Date
</span>
<input type="date" class="acl-datepick__input" [formControl]="asOnDateControl" [max]="today" />
</div>
@if (hasDateFilters) {
<button class="acl-filters__clear" (click)="clearDateFilters()">
<fa-icon icon="times"></fa-icon>
Clear
</button>
}
</div>
<!-- Table -->
<div class="acl-card">
@if (isLoading) {
<div class="acl-loading">
<mat-spinner diameter="36"></mat-spinner>
<span>Loading accounts...</span>
<div class="acl-state acl-state--loading">
<mat-spinner diameter="32"></mat-spinner>
<span>Loading accounts…</span>
</div>
}
@if (!isLoading && dataSource.data.length === 0) {
<div class="acl-empty">
<fa-icon icon="inbox" size="2x" class="acl-empty__icon"></fa-icon>
<p>No accounts found</p>
<div class="acl-state acl-state--empty">
<div class="acl-state__icon">
<fa-icon icon="inbox"></fa-icon>
</div>
<p class="acl-state__title">No active accounts found</p>
<p class="acl-state__sub">Try adjusting your search</p>
</div>
}
@if (!isLoading && dataSource.data.length > 0) {
<div class="acl-table-wrapper">
<div class="acl-table-wrap">
<table mat-table [dataSource]="dataSource" matSort (matSortChange)="onSortChange($event)" class="acl-table">
<!-- Account No -->
<ng-container matColumnDef="accountNo">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="acl-th">Account No</th>
<td mat-cell *matCellDef="let row" class="acl-td">
@@ -81,33 +115,30 @@
</td>
</ng-container>
<!-- Type -->
<ng-container matColumnDef="depositType">
<th mat-header-cell *matHeaderCellDef class="acl-th acl-th--center">Type</th>
<td mat-cell *matCellDef="let row" class="acl-td acl-td--center">
<span class="acl-dtype-badge" [ngClass]="getDepositTypeBadgeClass(row)">
{{ getDepositTypeLabel(row) }}
</span>
<span class="acl-type-badge" [ngClass]="config.typeBadgeClass">{{ config.typeLabel }}</span>
</td>
</ng-container>
<!-- Client -->
<ng-container matColumnDef="clientName">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="acl-th">Client</th>
<td mat-cell *matCellDef="let row" class="acl-td">
<span class="acl-client-name">{{ row.clientName }}</span>
<div class="acl-client">
<div class="acl-client__avatar">{{ (row.clientName || '?')[0] }}</div>
<span class="acl-client__name">{{ row.clientName }}</span>
</div>
</td>
</ng-container>
<!-- Product -->
<ng-container matColumnDef="productName">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="acl-th">Product</th>
<th mat-header-cell *matHeaderCellDef class="acl-th">Product</th>
<td mat-cell *matCellDef="let row" class="acl-td">
<span class="acl-product">{{ row.savingsProductName || row.depositProductName || row.productName }}</span>
</td>
</ng-container>
<!-- Balance -->
<ng-container matColumnDef="balance">
<th mat-header-cell *matHeaderCellDef class="acl-th acl-th--right">Balance</th>
<td mat-cell *matCellDef="let row" class="acl-td acl-td--right">
@@ -115,37 +146,24 @@
</td>
</ng-container>
<!-- Status -->
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef class="acl-th acl-th--center">Status</th>
<td mat-cell *matCellDef="let row" class="acl-td acl-td--center">
<span class="acl-status-badge" [ngClass]="getStatusClass(row)">
{{ getStatusLabel(row) }}
</span>
<span class="acl-status" [ngClass]="getStatusClass(row)">{{ getStatusLabel(row) }}</span>
</td>
</ng-container>
<!-- Actions -->
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="acl-th acl-th--center">Actions</th>
<td mat-cell *matCellDef="let row" class="acl-td acl-td--center">
<button
class="acl-view-btn"
(click)="$event.stopPropagation(); viewAccount(row)"
matTooltip="View Account"
>
<button class="acl-view-btn" (click)="$event.stopPropagation(); viewAccount(row)" matTooltip="View">
<fa-icon icon="eye"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns" class="acl-header-row"></tr>
<tr
mat-row
*matRowDef="let row; columns: displayedColumns"
class="acl-data-row"
(click)="viewAccount(row)"
></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns" class="acl-row" (click)="viewAccount(row)"></tr>
</table>
</div>