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
@@ -14,9 +14,11 @@
|
||||
<h3 class="nom-header__title">Family Members</h3>
|
||||
<span class="nom-header__badge">{{ familyMembers.length }}</span>
|
||||
</div>
|
||||
<button mat-flat-button color="primary" class="nom-header__btn" (click)="addFamilyMember()">
|
||||
<mat-icon>add</mat-icon> Add Member
|
||||
</button>
|
||||
@if (canAdd) {
|
||||
<button mat-flat-button color="primary" class="nom-header__btn" (click)="addFamilyMember()">
|
||||
<mat-icon>add</mat-icon> Add Member
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (familyMembers.length === 0) {
|
||||
@@ -44,21 +46,28 @@
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="nom-actions">
|
||||
<div class="nom-actions__buttons">
|
||||
<button mat-stroked-button color="primary" class="nom-actions__edit" (click)="editFamilyMember(member, i)">
|
||||
<fa-icon icon="edit" class="m-r-10"></fa-icon> Edit
|
||||
</button>
|
||||
<button
|
||||
mat-stroked-button
|
||||
color="warn"
|
||||
class="nom-actions__delete"
|
||||
(click)="deleteMember(member, 'Family Member')"
|
||||
>
|
||||
<fa-icon icon="trash" class="m-r-10"></fa-icon> Delete
|
||||
</button>
|
||||
@if (canAdd) {
|
||||
<div class="nom-actions">
|
||||
<div class="nom-actions__buttons">
|
||||
<button
|
||||
mat-stroked-button
|
||||
color="primary"
|
||||
class="nom-actions__edit"
|
||||
(click)="editFamilyMember(member, i)"
|
||||
>
|
||||
<fa-icon icon="edit" class="m-r-10"></fa-icon> Edit
|
||||
</button>
|
||||
<button
|
||||
mat-stroked-button
|
||||
color="warn"
|
||||
class="nom-actions__delete"
|
||||
(click)="deleteMember(member, 'Family Member')"
|
||||
>
|
||||
<fa-icon icon="trash" class="m-r-10"></fa-icon> Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="nom-grid">
|
||||
@if (member.firstName) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ClientsService } from '../../clients.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
import { familyAllowed } from '../../utils/client-rules';
|
||||
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
@@ -71,6 +72,12 @@ export class FamilyMembersTabComponent {
|
||||
clientId: string;
|
||||
/** Family member template options */
|
||||
familyMemberOptions: any;
|
||||
/**
|
||||
* Defensive flag — the route guard already blocks unauthorised clients, but
|
||||
* we re-check here so that if the component is somehow reachable via direct
|
||||
* link or stale state, the Add / Edit buttons stay hidden.
|
||||
*/
|
||||
canAdd = false;
|
||||
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { clientFamilyMembers: any }) => {
|
||||
@@ -80,6 +87,17 @@ export class FamilyMembersTabComponent {
|
||||
// so the clientId param lives two levels up, not one.
|
||||
this.clientId =
|
||||
this.route.parent?.parent?.snapshot.params['clientId'] || this.route.parent?.snapshot.params['clientId'];
|
||||
if (this.clientId) {
|
||||
this.clientsService.getClientData(this.clientId).subscribe({
|
||||
next: (client: any) => {
|
||||
const constitutionLabel = client?.clientNonPersonDetails?.constitution?.name || '';
|
||||
this.canAdd = familyAllowed(client?.legalForm?.id, constitutionLabel);
|
||||
},
|
||||
error: () => {
|
||||
this.canAdd = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Family members (non-nominee entries) */
|
||||
@@ -116,6 +134,7 @@ export class FamilyMembersTabComponent {
|
||||
}
|
||||
|
||||
addFamilyMember() {
|
||||
if (!this.canAdd) return;
|
||||
this.ensureTemplateLoaded().then(() => {
|
||||
const dialogRef = this.dialog.open(ClientFamilyMemberDialogComponent, {
|
||||
width: '640px',
|
||||
@@ -124,7 +143,10 @@ export class FamilyMembersTabComponent {
|
||||
data: {
|
||||
context: 'Add',
|
||||
options: this.familyMemberOptions,
|
||||
existingMembers: this.familyMembers
|
||||
existingMembers: this.familyMembers,
|
||||
// Pass the host client's id so the dialog's self-add guard can
|
||||
// filter the search results and refuse self-link attempts.
|
||||
hostClientId: this.clientId
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
@@ -139,6 +161,7 @@ export class FamilyMembersTabComponent {
|
||||
}
|
||||
|
||||
editFamilyMember(member: any, _index: number) {
|
||||
if (!this.canAdd) return;
|
||||
this.ensureTemplateLoaded().then(() => {
|
||||
const dialogRef = this.dialog.open(ClientFamilyMemberDialogComponent, {
|
||||
width: '640px',
|
||||
@@ -148,7 +171,8 @@ export class FamilyMembersTabComponent {
|
||||
context: 'Edit',
|
||||
options: this.familyMemberOptions,
|
||||
member,
|
||||
existingMembers: this.familyMembers
|
||||
existingMembers: this.familyMembers,
|
||||
hostClientId: this.clientId
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
@@ -226,6 +250,7 @@ export class FamilyMembersTabComponent {
|
||||
// ═══ Common ═══
|
||||
|
||||
deleteMember(member: any, label: string) {
|
||||
if (!this.canAdd) return;
|
||||
const realIndex = this.clientFamilyMembers.indexOf(member);
|
||||
const deleteFamilyMemberDialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `${label} ${member.firstName || ''}` }
|
||||
|
||||
Reference in New Issue
Block a user