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
+158 -141
View File
@@ -6,179 +6,196 @@
file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<!-- Modern Glassmorphism Login with Animated Gradient Background -->
<div class="login-wrapper">
<!-- Animated Gradient Background -->
<div class="gradient-bg">
<div class="gradient-orb orb-1"></div>
<div class="gradient-orb orb-2"></div>
<div class="gradient-orb orb-3"></div>
<div class="gradient-orb orb-4"></div>
</div>
<div class="login-page">
<div class="login-split">
<!-- Settings Icon - Top Right -->
<button
class="settings-trigger"
(click)="toggleSettingsPanel()"
matTooltip="Settings"
attr.aria-label="Settings"
>
<mifosx-m3-icon [name]="settingsPanelOpen ? 'close' : 'settings'"></mifosx-m3-icon>
</button>
<!-- ══ LEFT PANEL — SLIDER ══ -->
<div class="left-panel">
<div class="left-panel__dots-bg"></div>
<!-- Settings Popup Panel -->
@if (settingsPanelOpen) {
<div class="settings-overlay" (click)="toggleSettingsPanel()"></div>
<div class="settings-panel" @settingsAnimation>
<div class="settings-panel-header">
<h3 class="settings-title">
<mifosx-m3-icon name="tune"></mifosx-m3-icon>
{{ 'labels.heading.Settings' | translate }}
</h3>
</div>
<div class="settings-panel-body">
<!-- Theme Toggle -->
<div class="settings-item">
<span class="settings-label">
<mifosx-m3-icon name="dark_mode"></mifosx-m3-icon>
{{ 'labels.heading.Theme' | translate }}
</span>
<mifosx-theme-toggle></mifosx-theme-toggle>
</div>
<!-- Slides -->
<div class="slides-wrap">
@for (slide of slides; track slide.tag; let i = $index) {
<div class="slide" [class.active]="currentSlide === i" [ngClass]="'s' + (i + 1)">
<div class="slide__glow"></div>
<span class="slide__tag"><span class="slide__pulse"></span>{{ slide.tag }}</span>
<!-- Language Selector -->
<div class="settings-item">
<span class="settings-label">
<mifosx-m3-icon name="language"></mifosx-m3-icon>
{{ 'labels.heading.Language' | translate }}
</span>
<mifosx-language-selector appearance="outline" [showLabel]="false"></mifosx-language-selector>
</div>
<!-- LincShield SVG for FRM slide -->
@if (i === 1) {
<div class="lincshield-logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 180" width="420" height="100">
<defs>
<linearGradient id="blueGD2" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#4D90E8"/><stop offset="100%" style="stop-color:#2563C8"/>
</linearGradient>
<linearGradient id="greenGD2" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#34D05C"/><stop offset="100%" style="stop-color:#28B84E"/>
</linearGradient>
<linearGradient id="shieldGD2" x1="0%" y1="0%" x2="60%" y2="100%">
<stop offset="0%" style="stop-color:#34D05C"/><stop offset="100%" style="stop-color:#1A9040"/>
</linearGradient>
<filter id="glow3">
<feGaussianBlur stdDeviation="3" result="b"/>
<feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
</filter>
</defs>
<path d="M14 22 Q14 19 17 17 L44 8 Q47 7 50 8 L77 17 Q80 19 80 22 L80 72 Q80 100 47 114 Q14 100 14 72 Z" fill="url(#shieldGD2)" filter="url(#glow3)"/>
<path d="M22 28 Q22 26 24 25 L46 18 Q48 17 50 18 L72 25 Q74 26 74 28 L74 71 Q74 93 47 105 Q20 93 20 71 Z" fill="none" stroke="rgba(255,255,255,0.15)" stroke-width="1.5"/>
<path d="M33 65 L44 76 L66 50" stroke="white" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
<path d="M35 42 Q47 34 59 42" stroke="rgba(255,255,255,0.7)" stroke-width="3" stroke-linecap="round" fill="none"/>
<polygon points="59,37 59,47 65,42" fill="rgba(255,255,255,0.7)"/>
<text x="98" y="105" font-family="Georgia, 'Times New Roman', serif" font-size="96" font-weight="900" font-style="italic" fill="url(#blueGD2)" letter-spacing="-2">Linc</text>
<path d="M334 48 Q344 35 358 46" stroke="#34D05C" stroke-width="6.5" stroke-linecap="round" fill="none"/>
<polygon points="356,38 362,50 350,49" fill="#34D05C"/>
<text x="356" y="105" font-family="Georgia, 'Times New Roman', serif" font-size="96" font-weight="900" font-style="italic" fill="url(#greenGD2)" letter-spacing="-2">Shield</text>
<line x1="98" y1="122" x2="752" y2="122" stroke="#1a2d47" stroke-width="1"/>
<text x="98" y="148" font-family="'Trebuchet MS', 'Segoe UI', sans-serif" font-size="18" font-weight="700" letter-spacing="6" fill="#4D90E8">LINK</text>
<circle cx="178" cy="140" r="3" fill="#34D05C"/>
<text x="190" y="148" font-family="'Trebuchet MS', 'Segoe UI', sans-serif" font-size="18" font-weight="700" letter-spacing="6" fill="#8899bb">DETECT</text>
<circle cx="312" cy="140" r="3" fill="#34D05C"/>
<text x="324" y="148" font-family="'Trebuchet MS', 'Segoe UI', sans-serif" font-size="18" font-weight="700" letter-spacing="6" fill="#34D05C">PROTECT.</text>
</svg>
</div>
} @else {
<span class="slide__icon">{{ slide.icon }}</span>
}
<!-- Server Selector -->
@if (allowServerSwitch()) {
<div class="settings-item">
<span class="settings-label">
<mifosx-m3-icon name="dns"></mifosx-m3-icon>
{{ 'labels.heading.Server' | translate }}
</span>
<mifosx-server-selector appearance="outline" [showLabel]="false"></mifosx-server-selector>
<h2 class="slide__title" [innerHTML]="slide.title"></h2>
<p class="slide__desc">{{ slide.desc }}</p>
<div class="slide__stats">
@for (stat of slide.stats; track stat.label) {
<div class="stat-chip">
<div class="stat-chip__value">{{ stat.value }}</div>
<div class="stat-chip__label">{{ stat.label }}</div>
</div>
}
</div>
<!-- Flow diagram -->
<div class="slide__flow">
@for (node of slide.flow; track node; let last = $last) {
<div class="flow-node">{{ node }}</div>
@if (!last) {
<div class="flow-arrow"></div>
}
}
</div>
</div>
}
</div>
<div class="settings-panel-footer">
<button
mat-button
(click)="reloadSettings()"
class="reload-settings-btn"
>
<mifosx-m3-icon name="refresh"></mifosx-m3-icon>
{{ 'labels.buttons.Reload' | translate }}
</button>
</div>
</div>
}
<!-- Floating Glass Login Card -->
<div class="glass-card-container">
<div class="glass-card" @cardAnimation>
<!-- Logo Section -->
<div class="logo-section">
@if (!themeDarkEnabled) {
<img [src]="logoPath" (error)="onLogoError()" alt="{{ 'APP_NAME' | translate }} Logo" class="logo-image" />
} @else {
<img
[src]="logoPathDark"
(error)="onLogoErrorDark()"
alt="{{ 'APP_NAME' | translate }} Logo"
class="logo-image"
/>
<!-- Nav dots -->
<div class="slide-nav">
@for (slide of slides; track slide.tag; let i = $index) {
<button class="slide-dot" [class.active]="currentSlide === i" (click)="goToSlide(i)"></button>
}
</div>
<div class="slide-progress" [style.animation-duration]="slideDuration + 'ms'"></div>
</div>
<!-- Welcome Text -->
<div class="welcome-section">
<h1 class="welcome-title">{{ 'labels.heading.Welcome Back' | translate }}</h1>
<p class="welcome-subtitle">{{ 'labels.text.Sign in to continue' | translate }}</p>
</div>
<!-- ══ RIGHT PANEL — LOGIN ══ -->
<div class="right-panel">
<!-- Tenant Selector -->
@if (showTenantSelector) {
<div class="tenant-section">
<mifosx-tenant-selector></mifosx-tenant-selector>
<!-- Settings trigger -->
<button class="settings-btn" (click)="toggleSettingsPanel()" matTooltip="Settings">
<mifosx-m3-icon [name]="settingsPanelOpen ? 'close' : 'settings'"></mifosx-m3-icon>
</button>
<!-- Settings panel -->
@if (settingsPanelOpen) {
<div class="settings-overlay" (click)="toggleSettingsPanel()"></div>
<div class="settings-panel" @settingsAnimation>
<div class="settings-panel__header">
<mifosx-m3-icon name="tune"></mifosx-m3-icon>
<h3>{{ 'labels.heading.Settings' | translate }}</h3>
</div>
<div class="settings-panel__body">
@if (showTenantSelector) {
<div class="settings-item">
<span class="settings-item__label">
<mifosx-m3-icon name="domain"></mifosx-m3-icon>
{{ 'labels.inputs.Tenant' | translate }}
</span>
<mifosx-tenant-selector></mifosx-tenant-selector>
</div>
}
<div class="settings-item">
<span class="settings-item__label">
<mifosx-m3-icon name="dark_mode"></mifosx-m3-icon>
{{ 'labels.heading.Theme' | translate }}
</span>
<mifosx-theme-toggle></mifosx-theme-toggle>
</div>
<div class="settings-item">
<span class="settings-item__label">
<mifosx-m3-icon name="language"></mifosx-m3-icon>
{{ 'labels.heading.Language' | translate }}
</span>
<mifosx-language-selector appearance="outline" [showLabel]="false"></mifosx-language-selector>
</div>
@if (allowServerSwitch()) {
<div class="settings-item">
<span class="settings-item__label">
<mifosx-m3-icon name="dns"></mifosx-m3-icon>
{{ 'labels.heading.Server' | translate }}
</span>
<mifosx-server-selector appearance="outline" [showLabel]="false"></mifosx-server-selector>
</div>
}
</div>
</div>
}
<!-- Brand -->
<div class="brand">
<div class="brand__logo">
@if (!themeDarkEnabled) {
<img [src]="logoPath" (error)="onLogoError()" alt="{{ 'APP_NAME' | translate }}" />
} @else {
<img [src]="logoPathDark" (error)="onLogoErrorDark()" alt="{{ 'APP_NAME' | translate }}" />
}
</div>
</div>
<!-- Welcome -->
<div class="welcome">
<h2>{{ 'labels.heading.Welcome Back' | translate }}</h2>
<p>{{ 'labels.text.Sign in to continue' | translate }}</p>
</div>
<!-- Login Forms -->
@if (!resetPassword && !twoFactorAuthenticationRequired) {
<mifosx-login-form></mifosx-login-form>
}
@if (resetPassword) {
<mifosx-reset-password></mifosx-reset-password>
}
@if (twoFactorAuthenticationRequired) {
<mifosx-two-factor-authentication></mifosx-two-factor-authentication>
}
<!-- Version Info Section -->
<div class="login-version-info" *ngIf="displayBackendInfo"></div>
<!-- Branding Footer -->
@if (!productionMode) {
<div class="card-footer">
<span class="footer-text">
{{ 'APP_NAME' | translate }}
</span>
</div>
}
<div class="right-footer">
RBI Licensed · PCI-DSS Compliant · ISO 27001 Certified
</div>
</div>
</div>
<!-- Footer -->
<footer class="login-footer">
<span>🇮🇳</span>
<span class="login-footer__text">
Compliant with guidelines issued by &nbsp;
<strong>Institute for Development and Research in Banking Technology (IDRBT)</strong>
&nbsp;—&nbsp; Established by Reserve Bank of India
</span>
<span class="login-footer__sep">|</span>
<span class="login-footer__text">© 2025 {{ 'APP_NAME' | translate }}. All rights reserved.</span>
</footer>
</div>
<!-- Resource Menus (kept for compatibility) -->
<mat-menu #resourcesMenu="matMenu" class="modern-menu">
<mat-menu #resourcesMenu="matMenu">
<a [href]="'userManual' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="book-open" class="menu-icon"></fa-icon>
{{ 'labels.links.User Manual' | translate }}
</a>
<a [href]="'fineractFunctionalSpecs' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="file-alt" class="menu-icon"></fa-icon>
{{ 'labels.links.Functional Specifications' | translate }}
</a>
<a [href]="'fineractContributorZone' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="code" class="menu-icon"></fa-icon>
{{ 'labels.links.Developer Zone' | translate }}
</a>
</mat-menu>
<mat-menu #communityMenu="matMenu" class="modern-menu">
<a [href]="'mifosUserGroup' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="users" class="menu-icon"></fa-icon>
{{ 'labels.links.User Group' | translate }}
</a>
<a [href]="'mifosDeveloperGroup' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="laptop-code" class="menu-icon"></fa-icon>
{{ 'labels.links.Developer Group' | translate }}
</a>
<a [href]="'mifosIrc' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="comments" class="menu-icon"></fa-icon>
{{ 'labels.links.IRC' | translate }}
</a>
</mat-menu>
<mat-menu #contributeMenu="matMenu" class="modern-menu">
<a [href]="'keyDesignPrinciples' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="lightbulb" class="menu-icon"></fa-icon>
{{ 'labels.links.Key Design Principles' | translate }}
</a>
<a [href]="'sourceforgeMifos' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="code-branch" class="menu-icon"></fa-icon>
{{ 'labels.links.Working with Code' | translate }}
</a>
<a [href]="'mifosDonate' | documentationLink" target="_blank" rel="noopener noreferrer" mat-menu-item>
<fa-icon icon="hand-holding-heart" class="menu-icon"></fa-icon>
{{ 'labels.links.Donate' | translate }}
</a>
</mat-menu>