feat: dynamic denomination breakdown in deposit forms + savings menu scroller

Deposit forms (Current/Savings/FD/RD) now load cash denominations from
the Denomination Master instead of a hardcoded list:
- active + discontinued denominations fetched via /denominationmaster
- discontinued rows hidden by default behind a "Show discontinued" toggle,
  rendered faded and disabled (cannot be counted) when revealed
- rows sorted by value descending; redesigned as a Denom/Qty/Amount table
  with circular coin chips and per-row amount (faded at zero)
Also: savings account-actions menu now scrolls (max-height + grouped
sections mirror the current-account menu) and renders all action items.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaanu423
2026-05-27 13:19:23 +05:30
co-authored by Claude Opus 4.7
parent 918a90368c
commit 89e17f561f
16 changed files with 1006 additions and 548 deletions
@@ -104,155 +104,172 @@
</div>
</header>
<!-- Cash movement (Deposit / Withdrawal / Hold Amount) -->
<div class="sav-menu__group">
<div class="sav-menu__group-title">Transact</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'transact') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--transact"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico">
<fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon>
</span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
<div class="sav-menu__body">
<!-- Transact: singleButtons + options of kind 'transact' -->
@if (hasKind('transact')) {
<div class="sav-menu__group">
<div class="sav-menu__group-title">Transact</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'transact') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--transact"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
}
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'transact') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--transact"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(option.name)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
</div>
}
<!-- Restrict: singleButtons + options of kind 'block' -->
@if (hasKind('block')) {
<div class="sav-menu__group">
<div class="sav-menu__group-title">Restrict</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'block') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--block"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
}
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'block') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--block"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(option.name)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
</div>
}
<!-- Interest: singleButtons + options of kind 'interest' -->
@if (hasKind('interest')) {
<div class="sav-menu__group">
<div class="sav-menu__group-title">Interest</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'interest') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--interest"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
}
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'interest') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--interest"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(option.name)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
</div>
}
<!-- Admin: singleButtons + options of kind 'admin', hidden when blocked -->
@if (hasKind('admin') && !savingsAccountData.subStatus.block) {
<div class="sav-menu__group">
<div class="sav-menu__group-title">Admin</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'admin') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--admin"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
}
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'admin') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--admin"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(option.name)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
</div>
}
<!-- Danger zone: singleButtons + options of kind 'danger' -->
@if (hasKind('danger')) {
<div class="sav-menu__group sav-menu__group--danger">
<div class="sav-menu__group-title">Danger zone</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'danger') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--danger"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
}
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'danger') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--danger"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico"><fa-icon [icon]="iconOf(option.name)"></fa-icon></span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
</div>
}
</div>
<!-- Restrictions (Block / Unblock variants) -->
<div class="sav-menu__group">
<div class="sav-menu__group-title">Restrict</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'block') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--block"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico">
<fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon>
</span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
}
</div>
<!-- Interest -->
<div class="sav-menu__group">
<div class="sav-menu__group-title">Interest</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'interest') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--interest"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico">
<fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon>
</span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
}
</div>
<!-- Admin (approval/staff/charges) — drawn from BOTH primary
buttons and the historical "More" options. -->
@if (buttonConfig.options && !savingsAccountData.subStatus.block) {
<div class="sav-menu__group">
<div class="sav-menu__group-title">Admin</div>
@for (item of buttonConfig.singleButtons; track item.name) {
@if (kindOf(item.name) === 'admin') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--admin"
*mifosxHasPermission="item.taskPermissionName"
(click)="doAction(item.name)"
>
<span class="sav-menu__ico">
<fa-icon [icon]="iconOf(item.name, item.icon)"></fa-icon>
</span>
<span class="sav-menu__label">{{ 'labels.menus.' + item.name | translate }}</span>
</button>
}
}
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'admin') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--admin"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico">
<fa-icon [icon]="iconOf(option.name)"></fa-icon>
</span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'interest') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--interest"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico">
<fa-icon [icon]="iconOf(option.name)"></fa-icon>
</span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'transact') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--transact"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico">
<fa-icon [icon]="iconOf(option.name)"></fa-icon>
</span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
</div>
}
<!-- Danger (Close / Reject / Delete) -->
@if (buttonConfig.options && !savingsAccountData.subStatus.block) {
<div class="sav-menu__group sav-menu__group--danger">
<div class="sav-menu__group-title">Danger zone</div>
@for (option of buttonConfig.options; track option.name) {
@if (kindOf(option.name) === 'danger') {
<button
mat-menu-item
class="sav-menu__item sav-menu__item--danger"
*mifosxHasPermission="option.taskPermissionName"
(click)="doAction(option.name)"
>
<span class="sav-menu__ico">
<fa-icon [icon]="iconOf(option.name)"></fa-icon>
</span>
<span class="sav-menu__label">{{ 'labels.menus.' + option.name | translate }}</span>
</button>
}
}
</div>
}
</div>
</mat-menu>
</header>
@@ -170,6 +170,14 @@ export class SavingsAccountViewComponent implements OnInit {
return this.ACTION_ICON[name] ?? fallback ?? 'circle';
}
hasKind(kind: 'transact' | 'block' | 'interest' | 'admin' | 'danger'): boolean {
const all = [
...(this.buttonConfig?.singleButtons ?? []),
...(this.buttonConfig?.options ?? [])
];
return all.some((item) => this.kindOf(item.name) === kind);
}
/**
* Fetches savings account data from `resolve`
* @param {ActivatedRoute} route Activated Route