feat: MFA/2FA, OTP audit logs, KYC + client/user enhancements

- Access Control module: SMS/Email/TOTP/Hardware-token MFA factor management
- OTP Audit Logs module under Admin menu (list + detail) with 401/403 handling
- Two-factor authentication login flow updates
- Client KYC, India address, family-members, ckyc, nominee enhancements
- New shared KYC helpers (kyc-proof-types, kyc-upload-helper.service)
- User create/edit/view enhancements
- Shell navigation: OTP Audit Logs entry under real Admin menu
This commit is contained in:
Aditya
2026-05-10 13:24:48 +05:30
parent 2d4fb4237e
commit 3b752dc6ae
56 changed files with 7741 additions and 599 deletions
@@ -216,7 +216,7 @@ export class ClientFamilyMemberDialogComponent implements OnInit {
}
this.searching = true;
this.searchTimer = setTimeout(() => {
this.clientsService.searchByText(text, 0, 8).subscribe({
this.clientsService.searchByText(text, 0, 8, '', '', true).subscribe({
next: (data: any) => {
this.searchResults = data?.content || [];
this.searching = false;
@@ -161,8 +161,13 @@ export class ClientFamilyMembersStepComponent implements OnInit {
panelClass: 'fm-dialog-panel'
});
ref.afterClosed().subscribe((response: any) => {
if (response?.member) {
this.clientFamilyMembers.splice(index, 1, response.member);
if (!response?.member) return;
const updated = response.member;
this.clientFamilyMembers.splice(index, 1, updated);
// Persist to backend if this is an existing (already-saved) member
if (member.id && this.clientId) {
const { id, _linkedClient, _marriageCertFile, ...payload } = updated;
this.clientsService.editFamilyMember(this.clientId, member.id, payload).subscribe({ error: () => {} });
}
});
}
@@ -172,7 +177,15 @@ export class ClientFamilyMembersStepComponent implements OnInit {
data: { deleteContext: `${name}` }
});
ref.afterClosed().subscribe((response: any) => {
if (response?.delete) {
if (!response?.delete) return;
const member = this.clientFamilyMembers[index];
// Persist deletion to backend for existing members; locally-added ones just drop from the array
if (member?.id && this.clientId) {
this.clientsService.deleteFamilyMember(this.clientId, member.id.toString()).subscribe({
next: () => this.clientFamilyMembers.splice(index, 1),
error: () => this.clientFamilyMembers.splice(index, 1)
});
} else {
this.clientFamilyMembers.splice(index, 1);
}
});
@@ -228,7 +241,7 @@ export class ClientFamilyMembersStepComponent implements OnInit {
}
this.nomineeSearching = true;
this.nomineeSearchTimer = setTimeout(() => {
this.clientsService.searchByText(text, 0, 10).subscribe({
this.clientsService.searchByText(text, 0, 10, '', '', true).subscribe({
next: (data: any) => {
this.nomineeSearchResults = data?.content || [];
this.nomineeSearching = false;
@@ -324,7 +337,7 @@ export class ClientFamilyMembersStepComponent implements OnInit {
}
this.guardianSearching = true;
this.guardianSearchTimer = setTimeout(() => {
this.clientsService.searchByText(text, 0, 10).subscribe({
this.clientsService.searchByText(text, 0, 10, '', '', true).subscribe({
next: (data: any) => {
this.guardianSearchResults = data?.content || [];
this.guardianSearching = false;