feat: KYC re-verify UX, family/nominee tab gating, savings dialogs, cfcfrms shell
- KYC tab: fix Verify (PAN) and Send OTP (Aadhaar) being disabled in edit mode; unmask Aadhaar input and show on-file masked value as hint; resolve kycId from id/kycId/resourceId fallbacks. - Client stepper/view: add familyAllowed / nomineeAllowed predicates + CanActivate route guards. Family tab hidden for non-individuals, Nominee tab hidden for non-proprietor entities. Family-members step accepts a nomineeOnly input for proprietorship clients. Add/Edit/Delete buttons inside family-members and nominee tabs gated by canAdd. - cfcfrms: add cfcfrms-shell wrapper, restyle complaint/fraud/mule/escalate pages and dashboard. - Savings: identity-verify and transaction-confirm dialogs, manage / activate / add-charge flows, account preview styling. - Tasks, core shell, account-nominees, icons: minor style and behaviour updates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
bf3e26a0d0
commit
b149fef72e
@@ -220,6 +220,12 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (selfSelectError) {
|
||||
<div class="nom-conflict-error">
|
||||
<mat-icon>error_outline</mat-icon>
|
||||
{{ selfSelectError }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -355,6 +361,12 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (guardianSelfSelectError) {
|
||||
<div class="nom-conflict-error">
|
||||
<mat-icon>error_outline</mat-icon>
|
||||
{{ guardianSelfSelectError }}
|
||||
</div>
|
||||
}
|
||||
} @else {
|
||||
<span class="nom-guardian-selected" [class.nom-guardian-selected--error]="guardianSameAsNominee"
|
||||
>{{ selectedGuardian.displayName }}
|
||||
|
||||
@@ -90,6 +90,11 @@ export class AccountNomineesTabComponent implements OnInit {
|
||||
editShare: number | null = null;
|
||||
editNomType: string = 'DA1';
|
||||
|
||||
/** Inline error shown when the user picks themselves as the nominee. */
|
||||
selfSelectError: string | null = null;
|
||||
/** Inline error shown when the user picks the host client as guardian. */
|
||||
guardianSelfSelectError: string | null = null;
|
||||
|
||||
get totalShare(): number {
|
||||
return this.nominees.reduce((sum, n) => sum + (n.percentageShare || 0), 0);
|
||||
}
|
||||
@@ -169,8 +174,15 @@ export class AccountNomineesTabComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/** True when the given client id is the same as the savings account's
|
||||
* host client — used by the search to refuse self-add as nominee. */
|
||||
isSelfClient(clientId: any): boolean {
|
||||
return clientId != null && this.clientId != null && String(clientId) === String(this.clientId);
|
||||
}
|
||||
|
||||
onSearch(text: string): void {
|
||||
this.searchText = text;
|
||||
this.selfSelectError = null;
|
||||
clearTimeout(this.searchTimer);
|
||||
if (!text || text.length < 2) {
|
||||
this.searchResults = [];
|
||||
@@ -180,7 +192,10 @@ export class AccountNomineesTabComponent implements OnInit {
|
||||
this.searchTimer = setTimeout(() => {
|
||||
this.clientsService.searchByText(text, 0, 8, '', '', true).subscribe({
|
||||
next: (data: any) => {
|
||||
this.searchResults = data?.content || [];
|
||||
const raw: any[] = data?.content || [];
|
||||
// Drop the host client from the result list — a client cannot be
|
||||
// their own nominee.
|
||||
this.searchResults = raw.filter((c: any) => !this.isSelfClient(c.id));
|
||||
this.searching = false;
|
||||
this.clientsService.enrichSearchResults(this.searchResults);
|
||||
},
|
||||
@@ -200,6 +215,16 @@ export class AccountNomineesTabComponent implements OnInit {
|
||||
}
|
||||
|
||||
selectClient(client: any): void {
|
||||
if (this.isSelfClient(client?.id)) {
|
||||
// Belt-and-braces — even if a stale result sneaks through, refuse
|
||||
// the selection and surface an inline message.
|
||||
this.selfSelectError =
|
||||
'You cannot add the account holder as their own nominee. Please choose a different client.';
|
||||
this.searchResults = [];
|
||||
this.searchText = '';
|
||||
return;
|
||||
}
|
||||
this.selfSelectError = null;
|
||||
this.selectedClient = client;
|
||||
this.searchResults = [];
|
||||
this.searchText = '';
|
||||
@@ -281,6 +306,7 @@ export class AccountNomineesTabComponent implements OnInit {
|
||||
|
||||
onGuardianSearch(text: string): void {
|
||||
this.guardianSearchText = text;
|
||||
this.guardianSelfSelectError = null;
|
||||
clearTimeout(this.guardianSearchTimer);
|
||||
if (!text || text.length < 2) {
|
||||
this.guardianSearchResults = [];
|
||||
@@ -290,7 +316,10 @@ export class AccountNomineesTabComponent implements OnInit {
|
||||
this.guardianSearchTimer = setTimeout(() => {
|
||||
this.clientsService.searchByText(text, 0, 8, '', '', true).subscribe({
|
||||
next: (data: any) => {
|
||||
this.guardianSearchResults = data?.content || [];
|
||||
const raw: any[] = data?.content || [];
|
||||
// Drop the host client from the guardian results too — a client
|
||||
// can't be their own minor-nominee's guardian.
|
||||
this.guardianSearchResults = raw.filter((c: any) => !this.isSelfClient(c.id));
|
||||
this.guardianSearching = false;
|
||||
this.clientsService.enrichSearchResults(this.guardianSearchResults);
|
||||
},
|
||||
@@ -304,6 +333,14 @@ export class AccountNomineesTabComponent implements OnInit {
|
||||
|
||||
selectGuardian(client: any): void {
|
||||
if (this.selectedClient && client.id === this.selectedClient.id) return;
|
||||
if (this.isSelfClient(client?.id)) {
|
||||
this.guardianSelfSelectError =
|
||||
'The account holder cannot be selected as the guardian. Please choose a different client.';
|
||||
this.guardianSearchResults = [];
|
||||
this.guardianSearchText = '';
|
||||
return;
|
||||
}
|
||||
this.guardianSelfSelectError = null;
|
||||
this.selectedGuardian = client;
|
||||
this.guardianSearchResults = [];
|
||||
this.guardianSearchText = '';
|
||||
|
||||
@@ -221,7 +221,12 @@ import {
|
||||
faSignature,
|
||||
faPercentage,
|
||||
faCompressAlt,
|
||||
faExpandAlt
|
||||
faExpandAlt,
|
||||
faUserCheck,
|
||||
faUsersCog,
|
||||
faUserCog,
|
||||
faServer,
|
||||
faBox
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
/**
|
||||
@@ -449,7 +454,12 @@ export class IconsModule {
|
||||
faSignature,
|
||||
faPercentage,
|
||||
faCompressAlt,
|
||||
faExpandAlt
|
||||
faExpandAlt,
|
||||
faUserCheck,
|
||||
faUsersCog,
|
||||
faUserCog,
|
||||
faServer,
|
||||
faBox
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user