feat(digital+toolbar): NEFT/RTGS module, AI menu, polished header icons
- Add /digital/neft-rtgs (entry) and /digital/neft-rtgs-report (analytics): KPIs, tabbed views (Trends, Bank-wise, Date-wise, Pending/Pass/Return, Branch/Mobile, User-wise), filterable transaction table with CSV export, and a non-dismissible Initiate dialog launched from a floating action. - Make BANL verification mandatory before NEFT/RTGS submit; auto-fill and lock beneficiary name from the lookup response, invalidate match on A/C or IFSC edit, demo fallback for unknown accounts. - Add Digital menu links (NEFT/RTGS + Report) in shell top-nav. - Replace toolbar theme toggle with AI / Intelligence Modules mega menu: 4 colour-coded columns covering Lending & Risk, Investment & Profit, Compliance & Advisory, Governance (9 modules total). Wire RBI Notifications Monitoring to /rbi-circulars. - Unify notifications, settings, AI, and profile toolbar buttons into a 26px ring style; colourful gradient bell SVG for notifications, custom gear+petals AI mark, online dot on the avatar. - Trim ISO 27001 chip in the top bar. - Add MPL header to generated .env.ts and its template in version.js. - Bundles other pending working-tree changes (clients family/nominee tab tweaks, auth/2FA fixes, translations) into the same push. 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
6714897688
commit
595054b0b8
+8
-1
@@ -51,7 +51,14 @@ export class AddFamilyMemberComponent implements OnInit {
|
||||
this.route.data.subscribe((data: { clientTemplate: any }) => {
|
||||
this.addFamilyMemberTemplate = data.clientTemplate.familyMemberOptions;
|
||||
});
|
||||
this.clientId = this.route.parent.parent.snapshot.params['clientId'];
|
||||
// Walk up the route tree until we find a clientId param. Hard-coding parent.parent breaks
|
||||
// when Angular flattens componentless intermediate routes (family-members has no component),
|
||||
// which makes the depth unstable — and produces /clients/undefined/familymembers URLs.
|
||||
let r: ActivatedRoute | null = this.route;
|
||||
while (r && !r.snapshot.params['clientId']) {
|
||||
r = r.parent;
|
||||
}
|
||||
this.clientId = r?.snapshot.params['clientId'];
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
/** Custom Components */
|
||||
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
|
||||
import { NomineeDialogComponent } from './nominee-dialog/nominee-dialog.component';
|
||||
import { ClientFamilyMemberDialogComponent } from '../../client-stepper/client-family-members-step/client-family-member-dialog/client-family-member-dialog.component';
|
||||
|
||||
/** Custom Services */
|
||||
import { ClientsService } from '../../clients.service';
|
||||
@@ -75,7 +76,10 @@ export class FamilyMembersTabComponent {
|
||||
this.route.data.subscribe((data: { clientFamilyMembers: any }) => {
|
||||
this.clientFamilyMembers = data.clientFamilyMembers || [];
|
||||
});
|
||||
this.clientId = this.route.parent.snapshot.params['clientId'];
|
||||
// Route hierarchy is :clientId → family-members (wrapper) → this component,
|
||||
// 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'];
|
||||
}
|
||||
|
||||
/** Family members (non-nominee entries) */
|
||||
@@ -101,52 +105,78 @@ export class FamilyMembersTabComponent {
|
||||
|
||||
// ═══ Family Member Actions ═══
|
||||
|
||||
/**
|
||||
* Strip UI-only helper fields (`_linkedClient`, `_marriageCertFile`, `id`)
|
||||
* from the dialog payload so the backend receives a clean DTO. Mirrors the
|
||||
* pattern used in client-family-members-step.editFamilyMember.
|
||||
*/
|
||||
private toApiPayload(formValue: any): any {
|
||||
const { id, _linkedClient, _marriageCertFile, ...payload } = formValue || {};
|
||||
return payload;
|
||||
}
|
||||
|
||||
addFamilyMember() {
|
||||
this.ensureTemplateLoaded().then(() => {
|
||||
const dialogRef = this.dialog.open(NomineeDialogComponent, {
|
||||
width: '700px',
|
||||
const dialogRef = this.dialog.open(ClientFamilyMemberDialogComponent, {
|
||||
width: '640px',
|
||||
maxWidth: '95vw',
|
||||
panelClass: 'fm-dialog-panel',
|
||||
data: {
|
||||
title: 'Add Family Member',
|
||||
familyMemberOptions: this.familyMemberOptions,
|
||||
isFamilyMember: true
|
||||
context: 'Add',
|
||||
options: this.familyMemberOptions,
|
||||
existingMembers: this.familyMembers
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((result: any) => {
|
||||
if (result) {
|
||||
this.clientsService.addFamilyMember(this.clientId, result).subscribe((res: any) => {
|
||||
this.clientsService.getClientFamilyMember(this.clientId, res.resourceId).subscribe((member: any) => {
|
||||
this.clientFamilyMembers.push(member);
|
||||
});
|
||||
});
|
||||
}
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (!response?.member) return;
|
||||
const payload = this.toApiPayload(response.member);
|
||||
this.clientsService.addFamilyMember(this.clientId, payload).subscribe({
|
||||
next: () => this.refreshFamilyMembers(),
|
||||
error: (err) => console.error('[FamilyMembers] add failed', err)
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
editFamilyMember(member: any, index: number) {
|
||||
const realIndex = this.clientFamilyMembers.indexOf(member);
|
||||
editFamilyMember(member: any, _index: number) {
|
||||
this.ensureTemplateLoaded().then(() => {
|
||||
const dialogRef = this.dialog.open(NomineeDialogComponent, {
|
||||
width: '700px',
|
||||
const dialogRef = this.dialog.open(ClientFamilyMemberDialogComponent, {
|
||||
width: '640px',
|
||||
maxWidth: '95vw',
|
||||
panelClass: 'fm-dialog-panel',
|
||||
data: {
|
||||
title: 'Edit Family Member',
|
||||
familyMemberOptions: this.familyMemberOptions,
|
||||
context: 'Edit',
|
||||
options: this.familyMemberOptions,
|
||||
member,
|
||||
isFamilyMember: true
|
||||
existingMembers: this.familyMembers
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((result: any) => {
|
||||
if (result) {
|
||||
this.clientsService.editFamilyMember(member.clientId, member.id, result).subscribe(() => {
|
||||
this.clientsService.getClientFamilyMember(this.clientId, member.id).subscribe((updated: any) => {
|
||||
this.clientFamilyMembers[realIndex] = updated;
|
||||
});
|
||||
});
|
||||
}
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (!response?.member) return;
|
||||
const payload = this.toApiPayload(response.member);
|
||||
this.clientsService.editFamilyMember(member.clientId || this.clientId, member.id, payload).subscribe({
|
||||
next: () => this.refreshFamilyMembers(),
|
||||
error: (err) => console.error('[FamilyMembers] edit failed', err)
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-pull the full family-members list from the backend after any
|
||||
* mutation. More resilient than fetching a single resource by id —
|
||||
* sidesteps cases where the POST response doesn't carry the new id in
|
||||
* the expected `resourceId` field.
|
||||
*/
|
||||
private refreshFamilyMembers(): void {
|
||||
this.clientsService.getClientFamilyMembers(this.clientId).subscribe({
|
||||
next: (data: any) => {
|
||||
this.clientFamilyMembers = Array.isArray(data) ? data : [];
|
||||
},
|
||||
error: (err) => console.error('[FamilyMembers] refresh failed', err)
|
||||
});
|
||||
}
|
||||
|
||||
// ═══ Nominee Actions ═══
|
||||
|
||||
addNominee() {
|
||||
|
||||
Reference in New Issue
Block a user