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:
co-authored by
Claude Sonnet 4.6
parent
45d4397b0e
commit
846b2484d7
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user