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
@@ -7,9 +7,10 @@
-->
@if (loans && loans.length > 0) {
<div class="tab-container mat-typography">
<div class="tasks-header">
<mat-form-field class="tasks-search-field">
<div class="cv-tab-content">
<div class="cv-action-bar">
<mat-form-field appearance="outline" class="cv-search-field">
<mat-icon matPrefix>search</mat-icon>
<input
#filterInput
matInput
@@ -17,91 +18,92 @@
(keyup)="applyFilter(filterInput.value)"
/>
</mat-form-field>
<button
mat-raised-button
color="success"
*mifosxHasPermission="'APPROVE_LOANRESCHEDULE'"
(click)="bulkLoanReschedule('Approve')"
class="tasks-action-btn"
>
<fa-icon icon="check" class="m-r-10"></fa-icon>{{ 'labels.buttons.Approve' | translate }}
</button>
<button
mat-raised-button
color="reject"
*mifosxHasPermission="'APPROVE_LOANRESCHEDULE'"
(click)="bulkLoanReschedule('Reject')"
class="tasks-action-btn"
>
<fa-icon icon="times" class="m-r-10"></fa-icon>{{ 'labels.buttons.Reject' | translate }}
</button>
<div class="cv-action-buttons">
<button
mat-stroked-button
class="cv-btn cv-btn-approve"
*mifosxHasPermission="'APPROVE_LOANRESCHEDULE'"
(click)="bulkLoanReschedule('Approve')"
>
<fa-icon icon="check" class="m-r-10"></fa-icon>{{ 'labels.buttons.Approve' | translate }}
</button>
<button
mat-stroked-button
class="cv-btn cv-btn-reject"
*mifosxHasPermission="'APPROVE_LOANRESCHEDULE'"
(click)="bulkLoanReschedule('Reject')"
>
<fa-icon icon="times" class="m-r-10"></fa-icon>{{ 'labels.buttons.Reject' | translate }}
</button>
</div>
</div>
<table mat-table [dataSource]="dataSource">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
[aria-label]="checkboxLabel()"
<div class="table-container">
<table mat-table [dataSource]="dataSource" class="modern-table">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox
(change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
[aria-label]="checkboxLabel()"
>
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
[aria-label]="checkboxLabel(row)"
>
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="client">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Client' | translate }}</th>
<td
mat-cell
*matCellDef="let loan"
class="cell-link"
[routerLink]="['../../clients', loan.clientId, 'general']"
>
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox
(click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
[aria-label]="checkboxLabel(row)"
{{ loan.clientName }}
</td>
</ng-container>
<ng-container matColumnDef="rescheduleRequestNo">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Reschedule Request' | translate }}#</th>
<td mat-cell *matCellDef="let loan" class="cell-mono">{{ loan.id }}</td>
</ng-container>
<ng-container matColumnDef="loanAccountNo">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Loan Account' | translate }}#</th>
<td
mat-cell
*matCellDef="let loan"
class="cell-mono"
style="cursor: pointer;"
[routerLink]="['../../clients', loan.clientId, 'loans', loan.loanId, 'general']"
>
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="client">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Client' | translate }}</th>
<td
mat-cell
*matCellDef="let loan"
class="view-details"
[routerLink]="['../../clients', loan.clientId, 'general']"
>
{{ loan.clientName }}
</td>
</ng-container>
<ng-container matColumnDef="rescheduleRequestNo">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Reschedule Request' | translate }}#</th>
<td mat-cell *matCellDef="let loan">{{ loan.id }}</td>
</ng-container>
<ng-container matColumnDef="loanAccountNo">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Loan Account' | translate }}#</th>
<td
mat-cell
*matCellDef="let loan"
class="view-details"
[routerLink]="['../../clients', loan.clientId, 'loans', loan.loanId, 'general']"
>
{{ loan.loanAccountNumber }}
</td>
</ng-container>
<ng-container matColumnDef="rescheduleForm">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Reschedule Form' | translate }}</th>
<td mat-cell *matCellDef="let loan">{{ loan.rescheduleFromDate | dateFormat }}</td>
</ng-container>
<ng-container matColumnDef="rescheduleReason">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Reschedule Reason' | translate }}</th>
<td mat-cell *matCellDef="let loan">{{ loan.rescheduleReasonCodeValue.name }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns" (click)="selection.toggle(row)"></tr>
</table>
{{ loan.loanAccountNumber }}
</td>
</ng-container>
<ng-container matColumnDef="rescheduleForm">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Reschedule Form' | translate }}</th>
<td mat-cell *matCellDef="let loan">{{ loan.rescheduleFromDate | dateFormat }}</td>
</ng-container>
<ng-container matColumnDef="rescheduleReason">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Reschedule Reason' | translate }}</th>
<td mat-cell *matCellDef="let loan">{{ loan.rescheduleReasonCodeValue.name }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns" (click)="selection.toggle(row)" class="table-row"></tr>
</table>
</div>
</div>
}
@if (loans?.length === 0) {
<div class="alert">
<div class="message">
<i class="fa fa-exclamation-circle alert-check"></i>
{{ 'labels.text.No pending rescheduled loan available for this account' | translate }}
</div>
<div class="empty-state">
<i class="fas fa-calendar-alt empty-icon"></i>
<p class="empty-text">{{ 'labels.text.No pending rescheduled loan available for this account' | translate }}</p>
</div>
}
@@ -6,83 +6,107 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
.tab-container {
padding: 1%;
margin: 1%;
@use '../../../shared/styles/list-layout' as *;
$brand: #1353a0;
$border: #e2e8f0;
$text: #0f172a;
$text-muted: #64748b;
.cv-tab-content {
padding: 16px 0;
}
.cv-action-bar {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.cv-search-field {
flex: 1;
min-width: 200px;
max-width: 320px;
::ng-deep {
.mat-mdc-form-field-flex { height: 32px; }
.mat-mdc-form-field-infix {
padding: 4px 0;
min-height: 32px;
}
::ng-deep mat-form-field {
.mat-mdc-form-field-subscript-wrapper {
height: 0;
min-height: 0;
}
.mat-mdc-text-field-wrapper {
margin-bottom: 0;
.mdc-notched-outline {
.mdc-notched-outline__leading { border-radius: 8px 0 0 8px; }
.mdc-notched-outline__trailing { border-radius: 0 8px 8px 0; }
}
.mat-mdc-form-field-infix {
padding-top: 8px;
padding-bottom: 8px;
min-height: 48px;
.mat-mdc-form-field-icon-prefix {
padding: 0 6px 0 8px;
color: $text-muted;
}
input {
height: 48px;
}
}
button.mat-mdc-raised-button {
height: 48px;
line-height: 48px;
padding: 0 16px;
min-height: 48px;
}
.mat-raised-button.mat-success {
color: #fff;
background-color: #008000ab;
}
.view-details {
cursor: pointer;
}
.tasks-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
}
.tasks-search-field {
width: 280px;
margin: 0;
}
.tasks-action-btn {
margin: 0;
input { font-size: 13px; }
}
}
.alert {
background-color: #e8f4fd;
padding: 6px 16px;
font-size: 0.875rem;
font-family: Roboto, 'Helvetica Neue', sans-serif;
font-weight: 400;
line-height: 1.43;
border-radius: 4px;
letter-spacing: normal;
margin: 10px;
.cv-action-buttons {
display: flex;
gap: 8px;
margin-left: auto;
flex-shrink: 0;
}
.message {
padding: 8px 0;
font-size: 18px;
}
.cv-btn {
font-size: 12px;
font-weight: 500;
border-radius: 8px;
height: 32px;
padding: 0 14px;
font-family: 'DM Sans', 'Roboto', sans-serif;
.alert-check {
color: #359ff4;
margin-right: 2px;
font-size: 1.4rem;
fa-icon {
margin-right: 4px;
font-size: 11px;
}
}
.cv-btn-approve {
border-color: #16a34a;
color: #16a34a;
&:hover {
background: #f0fdf4;
}
}
.cv-btn-reject {
border-color: #64748b;
color: #64748b;
&:hover {
background: #f8fafc;
}
}
@media (max-width: 768px) {
.cv-action-bar {
flex-direction: column;
align-items: stretch;
}
.cv-search-field {
max-width: 100%;
}
.cv-action-buttons {
margin-left: 0;
}
}