feat: non-individual entity UI improvements — hide individual-only sections, fix legal form display, send extended fields to API

- Hide Family Members tab/section for non-individual entities in client view, create flow, and preview
- Hide Financial & Classification section for non-individual entities in personal data and preview
- Fix legal form column in clients list — fetch legalForm from client API for correct display
- Add person/business icon before client name in list rows
- Remove unsupportedNpd filter — send authorizedSignatory, additionalInfo, dateOfRegistration to API
- Add registration number format hint (mat-hint) based on constitution type
- Add spacing between verification row and constitution type dropdowns
- Reduce table cell padding and prevent action buttons from being clipped
- Add missing MPL-2.0 license headers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aditya
2026-04-04 15:10:51 +05:30
co-authored by Claude Opus 4.6
parent ab01111424
commit b890d24bb7
522 changed files with 51991 additions and 21885 deletions
+107 -7
View File
@@ -12,6 +12,7 @@ import { HttpClient, HttpParams, HttpBackend, HttpHeaders } from '@angular/commo
/** rxjs Imports */
import { Observable, of, throwError } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { map, catchError } from 'rxjs/operators';
import { environment } from 'environments/environment';
@@ -191,13 +192,9 @@ export class ClientsService {
})
.pipe(
// Handle the error here and return null when no image is found (404)
catchError((error) => {
if (error.status === 404) {
// Client has no profile image - return null without propagating error
return of(null);
}
// For other errors, rethrow the error
return throwError(() => error);
catchError(() => {
// Client has no profile image (404/403) - return null
return of(null);
})
);
}
@@ -233,6 +230,43 @@ export class ClientsService {
return this.http.get(`/clients/${clientId}/familymembers`);
}
/**
* Enrich search results with DOB and father/spouse name.
* Fetches client data (for DOB) and family members (for father/spouse).
*/
enrichSearchResults(results: any[]): void {
const getRelName = (m: any): string => {
if (typeof m.relationshipId === 'object' && m.relationshipId?.name) {
return m.relationshipId.name.toUpperCase();
}
return '';
};
for (const client of results) {
// Fetch DOB from client data
this.getClientData(client.id.toString()).pipe(
catchError(() => of(null))
).subscribe((data: any) => {
if (data?.dateOfBirth) {
client.dateOfBirth = data.dateOfBirth;
}
});
// Fetch father/spouse from family members
this.getClientFamilyMembers(client.id.toString()).pipe(
catchError(() => of([]))
).subscribe((members: any) => {
const list = Array.isArray(members) ? members : [];
const spouse = list.find((m: any) => getRelName(m) === 'SPOUSE');
const father = list.find((m: any) => getRelName(m) === 'FATHER');
if (spouse) {
client.fatherSpouseName = `S/o: ${spouse.firstName}`;
} else if (father) {
client.fatherSpouseName = `F/o: ${father.firstName}`;
}
});
}
}
getClientFamilyMember(clientId: string, familyMemberId: string) {
return this.http.get(`/clients/${clientId}/familymembers/${familyMemberId}`);
}
@@ -249,6 +283,35 @@ export class ClientsService {
return this.http.delete(`/clients/${clientId}/familymembers/${familyMemberId}`);
}
uploadFamilyMemberDocument(clientId: string, familyMemberId: string, formData: FormData): Observable<any> {
return this.http.post(`/clients/${clientId}/familymembers/${familyMemberId}/documents`, formData);
}
// ═══ Nominee APIs ═══
getClientNominees(clientId: string, accountNo?: string, accountType?: string): Observable<any> {
let params = new HttpParams();
if (accountNo) { params = params.set('accountNo', accountNo); }
if (accountType) { params = params.set('accountType', accountType); }
return this.http.get(`/clients/${clientId}/nominees`, { params });
}
getClientNomineeTemplate(clientId: string): Observable<any> {
return this.http.get(`/clients/${clientId}/nominees/template`);
}
addNominee(clientId: string, data: any): Observable<any> {
return this.http.post(`/clients/${clientId}/nominees`, data);
}
updateNominee(clientId: string, nomineeId: string, data: any): Observable<any> {
return this.http.put(`/clients/${clientId}/nominees/${nomineeId}`, data);
}
deleteNominee(clientId: string, nomineeId: string): Observable<any> {
return this.http.delete(`/clients/${clientId}/nominees/${nomineeId}`);
}
getClientIdentifiers(clientId: string) {
return this.http.get(`/clients/${clientId}/identifiers`);
}
@@ -481,6 +544,33 @@ export class ClientsService {
return this.http.get(`/clients/${clientId}/kyc`);
}
/**
* Gets KYC template for a client — returns required documents based on client type.
* @param clientId Client ID
*/
getClientKycTemplate(clientId: string): Observable<any> {
return this.http.get(`/clients/${clientId}/kyc/template`);
}
/** Fetch code values by code ID */
getCodeValuesById(codeId: number): Observable<any[]> {
return this.http.get<any[]>(`/codes/${codeId}/codevalues`).pipe(catchError(() => of([])));
}
/** Fetch code values by code name (e.g. 'FORM_60_PURPOSE') */
getCodeValuesByName(codeName: string): Observable<any[]> {
return this.http.get<any[]>('/codes').pipe(
switchMap((codes: any[]) => {
const code = codes.find((c: any) => c.name === codeName);
if (code) {
return this.http.get<any[]>(`/codes/${code.id}/codevalues`);
}
return of([]);
}),
catchError(() => of([]))
);
}
/**
* Saves KYC details for a client.
* @param clientId Client ID
@@ -551,6 +641,16 @@ export class ClientsService {
return this.http.post(`/clients/${clientId}/kyc/${kycId}?command=verify-gstin`, {});
}
// ═══ Entity Classification APIs ═══
getEntityClassifications(clientId: string): Observable<any> {
return this.http.get(`/clients/${clientId}/entityclassification`);
}
saveEntityClassification(clientId: string, category: string, data: any): Observable<any> {
return this.http.post(`/clients/${clientId}/entityclassification/${category}`, data);
}
getClientCkyc(clientId: string): Observable<any> {
return this.http.get(`/clients/${clientId}/ckyc`);
}