fix: nominee share & joint ownership validation across all account types

- Block 0% nominee share in all steppers (Savings, FD, RD, Current) —
  Add button disabled via isValid, addNominee() guards < 1, nominee-form
  error condition fixed for value=0
- Joint ownership: default primary share 50%, enforce min 1% on blur,
  max 100% on input with DOM clamp via $event, auto-redistribute
  co-holders proportionally when primary share changes,
  isJointOwnershipValid guards each holder >= 1
- Pending/Rejected account tabs: normalize date format to 22 May 2026
  for both array and string date values from API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jaanu423
2026-05-23 14:05:00 +05:30
co-authored by Claude Sonnet 4.6
parent df96be9a0e
commit ad6f629c3f
25 changed files with 337 additions and 35 deletions
@@ -123,7 +123,12 @@
<button type="button" class="nom-cancel-btn" (click)="showNomineeForm = false; nomineeError = ''">
Cancel
</button>
<button type="button" class="nom-confirm-btn" (click)="addNominee()">
<button
type="button"
class="nom-confirm-btn"
[disabled]="!nomineeFormComp?.isValid"
(click)="addNominee()"
>
<i class="fas fa-plus"></i> Add
</button>
</div>
@@ -83,6 +83,10 @@ export class CurrentAccountCurrencyStepComponent implements OnChanges {
return;
}
}
if (!data.percentageShare || data.percentageShare < 1) {
this.nomineeError = 'Share must be at least 1%.';
return;
}
const newTotal = this.totalShare + (+data.percentageShare || 0);
if (newTotal > 100) {
this.nomineeError = `Total share cannot exceed 100%. Remaining: ${this.remainingShare}%`;
@@ -301,13 +301,18 @@
<input
class="soa-pct-input"
type="number"
min="0"
min="1"
max="100"
[(ngModel)]="primaryHolderShare"
[ngModelOptions]="{ standalone: true }"
placeholder="0"
(input)="onPrimaryShareInput($event)"
(blur)="onPrimaryShareBlur($event)"
/>
<span class="soa-pct-unit">%</span>
@if (primaryHolderShare !== null && primaryHolderShare !== undefined && primaryHolderShare < 1) {
<div class="soa-pct-error">Min 1%</div>
}
</td>
<td class="soa-td soa-td--center">
<span class="soa-sign-toggle soa-sign-toggle--mandatory">
@@ -370,8 +375,8 @@
<td class="soa-td soa-td--center">
<span
class="soa-pct-badge"
[class.soa-pct-badge--ok]="totalJointSharePercentage === 100"
[class.soa-pct-badge--warn]="totalJointSharePercentage !== 100"
[class.soa-pct-badge--ok]="isJointOwnershipValid"
[class.soa-pct-badge--warn]="!isJointOwnershipValid"
>
{{ totalJointSharePercentage }}%
</span>
@@ -395,10 +400,14 @@
</div>
}
@if (totalJointSharePercentage !== 100) {
@if (!isJointOwnershipValid) {
<div class="soa-alert soa-alert--warn" style="margin-top: 8px">
<mat-icon>warning_amber</mat-icon>
Total ownership is {{ totalJointSharePercentage }}%. It must equal 100%.
@if (totalJointSharePercentage !== 100) {
Total ownership is {{ totalJointSharePercentage }}%. It must equal 100%.
} @else {
Each holder must have at least 1% ownership share.
}
</div>
} @else {
<div class="soa-alert soa-alert--ok" style="margin-top: 8px">
@@ -1118,6 +1118,12 @@ $ni-bg: #f9fafb;
margin-left: 2px;
}
.soa-pct-error {
font-size: 11px;
color: #ef4444;
margin-top: 2px;
}
.soa-no-action {
color: #cbd5e1;
font-size: 16px;
@@ -99,7 +99,7 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
primaryClientName = '';
primaryClientCif = '';
primaryClientId: number | null = null;
primaryHolderShare = 0;
primaryHolderShare = 50;
// ── Status of Account (RBI) ────────────────────────────────────────────
readonly accountStatusOptions = [
@@ -412,6 +412,53 @@ export class CurrentAccountDetailsStepComponent implements OnInit {
return (this.primaryHolderShare || 0) + this.jointHolders.reduce((sum, h) => sum + (h.sharePercentage || 0), 0);
}
onPrimaryShareInput(event: Event): void {
const input = event.target as HTMLInputElement;
let val = +input.value;
if (val > 100) {
val = 100;
input.value = '100';
}
this.primaryHolderShare = val;
if (val >= 1) this.redistributeCoHolders();
}
onPrimaryShareBlur(event: Event): void {
const input = event.target as HTMLInputElement;
let val = +input.value;
if (!val || val < 1) {
val = 1;
input.value = '1';
this.primaryHolderShare = 1;
this.redistributeCoHolders();
}
}
private redistributeCoHolders(): void {
if (this.jointHolders.length === 0) return;
const remaining = 100 - this.primaryHolderShare;
const totalCo = this.jointHolders.reduce((sum, h) => sum + (h.sharePercentage || 0), 0);
if (totalCo === 0) return;
let allocated = 0;
this.jointHolders.forEach((h, i) => {
if (i === this.jointHolders.length - 1) {
h.sharePercentage = Math.max(0, remaining - allocated);
} else {
const share = Math.round((h.sharePercentage / totalCo) * remaining);
h.sharePercentage = Math.max(0, share);
allocated += h.sharePercentage;
}
});
}
get isJointOwnershipValid(): boolean {
return (
this.totalJointSharePercentage === 100 &&
this.primaryHolderShare >= 1 &&
this.jointHolders.every((h) => h.sharePercentage >= 1)
);
}
get mandatoryJointCount(): number {
return this.jointHolders.filter((h) => h.isMandatory).length;
}