+
+
@if (!selectedGuardian) {
-
-
-
- @if (guardianSearchResults.length > 0 || guardianSearching) {
-
- @if (guardianSearching) {
-
-
-
- }
- @for (client of guardianSearchResults; track client.id) {
-
- person
- {{ client.displayName }}
-
- }
+
+
+ Search Guardian by Name or Client ID
+ search
+
+
+
+ @if (guardianSearchResults.length > 0 || guardianSearching) {
+
+ @if (guardianSearching) {
+
+
+ Searching...
+
+ }
+ @for (client of guardianSearchResults; track client.id) {
+
+
person
+
+ {{ client.displayName }}
+ ID: {{ client.id }}
+ @if (client.mobileNo) {
+ · {{ client.mobileNo }}
+ }
+
+
+ @if (selectedClient && client.id === selectedClient.id) {
+
Same as nominee
+ }
+
+ }
+ @if (
+ !guardianSearching && guardianSearchText.length >= 2 && guardianSearchResults.length === 0
+ ) {
+
No clients found
+ }
+
+ }
+
+ } @else {
+
+
person
+
+ {{ selectedGuardian.displayName }}
+ ID: {{ selectedGuardian.id }}
+ @if (selectedGuardian.mobileNo) {
+ · {{ selectedGuardian.mobileNo }}
+ }
+
+
+
+
+ @if (guardianSameAsNominee) {
+
+ error_outline
+ Guardian and nominee cannot be the same client (same Client ID / CIF).
}
- } @else {
-
{{ selectedGuardian.displayName }}
-
}
}
@@ -439,7 +489,8 @@
!nomineeShare ||
nomineeSaving ||
nomineeShare > maxAllowedShare ||
- (nomineeIsMinor && !selectedGuardian)
+ (nomineeIsMinor && !selectedGuardian) ||
+ guardianSameAsNominee
"
(click)="saveNominee()"
>
diff --git a/src/app/clients/clients-view/nominee-tab/nominee-tab.component.scss b/src/app/clients/clients-view/nominee-tab/nominee-tab.component.scss
index c5980ff99..3396f6492 100644
--- a/src/app/clients/clients-view/nominee-tab/nominee-tab.component.scss
+++ b/src/app/clients/clients-view/nominee-tab/nominee-tab.component.scss
@@ -620,6 +620,16 @@ $primary-light: #e8f0fe;
color: #16a34a;
}
+.nom-minor-badge {
+ font-size: 10px;
+ font-weight: 700;
+ color: #92400e;
+ background: #fef3c7;
+ border: 1px solid #fcd34d;
+ border-radius: 4px;
+ padding: 1px 6px;
+}
+
/* Nominee fields */
.nom-fields-row {
display: flex;
@@ -654,44 +664,141 @@ $primary-light: #e8f0fe;
margin-top: 4px;
}
-/* Guardian */
-.nom-guardian-section {
- display: flex;
- align-items: center;
- gap: 8px;
- flex-wrap: wrap;
- margin-bottom: 8px;
-}
+/* Guardian box — matches nominee-form style */
+.nom-guardian-box {
+ border: 1px solid #fde68a;
+ border-radius: 8px;
+ background: #fffbeb;
+ padding: 12px 14px;
+ margin-bottom: 12px;
-.nom-guardian-label {
- display: flex;
- align-items: center;
- gap: 4px;
- font-size: 12px;
- font-weight: 600;
- color: #92400e;
+ &__header {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ margin-bottom: 10px;
+ }
- mat-icon {
+ &__icon {
font-size: 16px;
+ width: 16px;
+ height: 16px;
+ color: #92400e;
+ }
+
+ &__title {
+ font-size: 13px;
+ font-weight: 700;
+ color: #92400e;
+ }
+
+ &__hint {
+ font-size: 11px;
+ color: #b45309;
}
}
-.nom-guardian-selected {
+.nom-guardian-search-wrap {
+ position: relative;
+}
+
+.nom-guardian-search-field {
+ width: 100%;
+}
+
+.nom-guardian-prefix-icon {
+ color: #94a3b8;
+ font-size: 18px;
+}
+
+.nom-guardian-results {
+ position: absolute;
+ top: 56px;
+ left: 0;
+ right: 0;
+ z-index: 100;
+ background: #fff;
+ border: 1px solid #e2e8f0;
+ border-radius: 6px;
+ box-shadow: 0 6px 20px rgb(0 0 0 / 10%);
+ max-height: 200px;
+ overflow-y: auto;
+}
+
+.nom-guardian-card {
display: flex;
align-items: center;
- gap: 4px;
- font-size: 13px;
+ gap: 10px;
+ padding: 8px 12px;
+ background: #fff;
+ border: 1px solid #fcd34d;
+ border-radius: 6px;
+
+ &--error {
+ border-color: #ef4444;
+ background: #fef2f2;
+ }
+
+ &__icon {
+ color: #92400e;
+ font-size: 20px;
+ flex-shrink: 0;
+ }
+
+ &__info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+
+ &__name {
+ font-size: 13px;
+ font-weight: 600;
+ color: #1e293b;
+ }
+
+ &__meta {
+ font-size: 11px;
+ color: #64748b;
+ }
+}
+
+/* Conflict validation */
+.nom-search-item--disabled {
+ opacity: 0.45;
+ cursor: not-allowed;
+ pointer-events: none;
+}
+
+.nom-conflict-tag {
+ font-size: 10px;
+ font-weight: 600;
+ color: #dc2626;
+ background: #fef2f2;
+ border: 1px solid #fecaca;
+ border-radius: 4px;
+ padding: 1px 6px;
+ white-space: nowrap;
+ margin-left: auto;
+}
+
+.nom-guardian-selected--error {
+ color: #dc2626 !important;
+}
+
+.nom-conflict-error {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ margin-top: 4px;
+ font-size: 12px;
font-weight: 500;
- color: #1e293b;
+ color: #dc2626;
- button {
- width: 24px !important;
- height: 24px !important;
- line-height: 24px !important;
-
- mat-icon {
- font-size: 14px;
- }
+ mat-icon {
+ font-size: 15px;
+ width: 15px;
+ height: 15px;
}
}
diff --git a/src/app/clients/clients-view/nominee-tab/nominee-tab.component.ts b/src/app/clients/clients-view/nominee-tab/nominee-tab.component.ts
index 99731db5f..039315fb2 100644
--- a/src/app/clients/clients-view/nominee-tab/nominee-tab.component.ts
+++ b/src/app/clients/clients-view/nominee-tab/nominee-tab.component.ts
@@ -75,6 +75,7 @@ export class NomineeTabComponent implements OnInit {
nomineeRelationshipId: number | null = null;
nomineeShare: number | null = null;
nomineeIsMinor = false;
+ minorToggleLocked = false;
nomineeSaving = false;
nomineeRemarks = '';
@@ -153,13 +154,35 @@ export class NomineeTabComponent implements OnInit {
this.clientsService.getClientAccountData(this.clientId).subscribe({
next: (data: any) => {
this.loading = false;
+ const allSavings: any[] = data.savingsAccounts || [];
+ const savingsOnly = allSavings.filter(
+ (a: any) =>
+ !a.depositType ||
+ a.depositType?.code === 'depositAccountType.savingsDeposit' ||
+ a.depositType?.value === 'Savings Deposit'
+ );
+ const fdAccounts = [
+ ...(data.fixedDepositAccounts || []),
+ ...allSavings.filter(
+ (a: any) =>
+ a.depositType?.code === 'depositAccountType.fixedDeposit' || a.depositType?.value === 'Fixed Deposit'
+ )
+ ];
+ const rdAccounts = [
+ ...(data.recurringDepositAccounts || []),
+ ...allSavings.filter(
+ (a: any) =>
+ a.depositType?.code === 'depositAccountType.recurringDeposit' ||
+ a.depositType?.value === 'Recurring Deposit'
+ )
+ ];
this.accountGroups = [
{
type: 'savings',
apiType: 'SB',
label: 'Savings Account',
icon: 'savings',
- accounts: this.filterActive(data.savingsAccounts)
+ accounts: this.filterActive(savingsOnly)
},
{
type: 'current',
@@ -173,14 +196,14 @@ export class NomineeTabComponent implements OnInit {
apiType: 'FD',
label: 'Fixed Deposit',
icon: 'lock',
- accounts: this.filterActive(data.fixedDepositAccounts)
+ accounts: this.filterActive(fdAccounts)
},
{
type: 'rd',
apiType: 'RD',
label: 'Recurring Deposit',
icon: 'autorenew',
- accounts: this.filterActive(data.recurringDepositAccounts)
+ accounts: this.filterActive(rdAccounts)
},
{
type: 'loan',
@@ -327,6 +350,9 @@ export class NomineeTabComponent implements OnInit {
this.linkedProfileImage = null;
this.linkedSignatureImage = null;
this.linkedKycStatus = null;
+ this.nomineeIsMinor = false;
+ this.minorToggleLocked = false;
+ this.selectedGuardian = null;
}
private fetchClientDetails(clientId: number): void {
@@ -346,6 +372,7 @@ export class NomineeTabComponent implements OnInit {
next: (data: any) => {
if (data?.dateOfBirth) {
this.selectedClient = { ...this.selectedClient, dateOfBirth: data.dateOfBirth };
+ this.checkMinorFromDob(data.dateOfBirth);
}
done();
},
@@ -401,6 +428,22 @@ export class NomineeTabComponent implements OnInit {
});
}
+ private checkMinorFromDob(dob: any): void {
+ let birthDate: Date;
+ if (Array.isArray(dob)) {
+ birthDate = new Date(dob[0], dob[1] - 1, dob[2]);
+ } else {
+ birthDate = new Date(dob);
+ }
+ if (isNaN(birthDate.getTime())) return;
+ const today = new Date();
+ let age = today.getFullYear() - birthDate.getFullYear();
+ const m = today.getMonth() - birthDate.getMonth();
+ if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) age--;
+ this.nomineeIsMinor = age < 18;
+ this.minorToggleLocked = true;
+ }
+
// ═══ Guardian ═══
onGuardianSearch(text: string): void {
@@ -426,17 +469,29 @@ export class NomineeTabComponent implements OnInit {
}, 400);
}
+ dismissGuardianSearch(): void {
+ setTimeout(() => {
+ this.guardianSearchResults = [];
+ }, 200);
+ }
+
selectGuardian(client: any): void {
+ if (this.selectedClient && client.id === this.selectedClient.id) return;
this.selectedGuardian = client;
this.guardianSearchResults = [];
this.guardianSearchText = '';
}
+ get guardianSameAsNominee(): boolean {
+ return !!(this.selectedGuardian && this.selectedClient && this.selectedGuardian.id === this.selectedClient.id);
+ }
+
// ═══ Save Nominee ═══
saveNominee(): void {
if (!this.selectedClient || !this.nomineeRelationshipId || !this.nomineeShare) return;
if (this.totalShare + this.nomineeShare > 100) return;
+ if (this.guardianSameAsNominee) return;
this.nomineeSaving = true;
const account = this.selectedAccount;
@@ -579,6 +634,7 @@ export class NomineeTabComponent implements OnInit {
this.nomineeRelationshipId = null;
this.nomineeShare = null;
this.nomineeIsMinor = false;
+ this.minorToggleLocked = false;
this.nomineeRemarks = '';
this.selectedGuardian = null;
this.searchText = '';
diff --git a/src/app/current-accounts/create-current-account/create-current-account.component.html b/src/app/current-accounts/create-current-account/create-current-account.component.html
index 6a81d16b6..2b60f9cf0 100644
--- a/src/app/current-accounts/create-current-account/create-current-account.component.html
+++ b/src/app/current-accounts/create-current-account/create-current-account.component.html
@@ -52,6 +52,7 @@
diff --git a/src/app/current-accounts/create-current-account/create-current-account.component.ts b/src/app/current-accounts/create-current-account/create-current-account.component.ts
index b221ea374..0a1bda31f 100644
--- a/src/app/current-accounts/create-current-account/create-current-account.component.ts
+++ b/src/app/current-accounts/create-current-account/create-current-account.component.ts
@@ -119,7 +119,7 @@ export class CreateCurrentAccountComponent {
}
get currentAccountNominee() {
- return this.currentAccountCurrencyStep?.nomineeData ?? null;
+ return this.currentAccountCurrencyStep?.liveNomineeData ?? null;
}
get currentAccountCurrencyFlags() {
@@ -185,7 +185,18 @@ export class CreateCurrentAccountComponent {
currentAccount.groupId = this.currentAccountTemplate.groupId;
}
- console.log('Current Account Payload:', JSON.stringify(currentAccount, null, 2));
+ const nominee = this.currentAccountNominee;
+ if (nominee) {
+ currentAccount.nominee = {
+ nomineeClientId: nominee.nomineeClientId,
+ nominationType: nominee.nominationType,
+ relationshipId: nominee.relationshipId,
+ percentageShare: nominee.percentageShare,
+ nomineeIsMinor: nominee.nomineeIsMinor,
+ ...(nominee.guardianClientId ? { guardianClientId: nominee.guardianClientId } : {}),
+ remarks: nominee.remarks
+ };
+ }
this.currentAccountsService.createCurrentAccount(currentAccount).subscribe((response: any) => {
this.router.navigate(
diff --git a/src/app/current-accounts/current-account-stepper/current-account-currency-step/current-account-currency-step.component.html b/src/app/current-accounts/current-account-stepper/current-account-currency-step/current-account-currency-step.component.html
index 935e312dd..b55b3cfba 100644
--- a/src/app/current-accounts/current-account-stepper/current-account-currency-step/current-account-currency-step.component.html
+++ b/src/app/current-accounts/current-account-stepper/current-account-currency-step/current-account-currency-step.component.html
@@ -73,7 +73,11 @@
@if (currentAccountProductTemplate?.nominationFacility) {
-
+
}