update rd,fd,saving and current product update validation end date and and this all account nominee facility code

This commit is contained in:
Nitesh Yadav
2026-05-15 12:53:47 +05:30
parent 8758b9222f
commit 52e216fbe5
62 changed files with 3069 additions and 886 deletions
@@ -9,271 +9,268 @@
<div class="nom-section">
<!-- Header -->
<div class="nom-header">
<div class="nom-header__left">
<i class="fas fa-user-shield"></i>
<span class="nom-header__title">Nomination Facility</span>
</div>
<div class="nom-mode-tabs">
<button type="button" class="nom-tab" [class.nom-tab--active]="mode === 'manual'" (click)="switchMode('manual')">
<i class="fas fa-pencil-alt"></i> Enter Manually
</button>
<button type="button" class="nom-tab" [class.nom-tab--active]="mode === 'linked'" (click)="switchMode('linked')">
<i class="fas fa-search"></i> Link Existing Client
</button>
</div>
<mat-icon class="nom-header__icon">search</mat-icon>
<span class="nom-header__title">Search &amp; Link Nominee</span>
</div>
<div class="nom-body">
<!-- ══════════════ MANUAL MODE ══════════════ -->
@if (mode === 'manual') {
<form [formGroup]="manualForm" class="nom-form">
<!-- Basic Info -->
<div class="nom-row">
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Full Name *</mat-label>
<input matInput formControlName="fullName" placeholder="Nominee full name" />
<mat-error>Full name is required</mat-error>
</mat-form-field>
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Relationship *</mat-label>
<mat-select formControlName="relationship">
@for (rel of relationships; track rel) {
<mat-option [value]="rel">{{ rel }}</mat-option>
}
</mat-select>
<mat-error>Relationship is required</mat-error>
</mat-form-field>
</div>
<div class="nom-row">
<mat-form-field appearance="outline" class="nom-field" (click)="dobPicker.open()">
<mat-label>Date of Birth</mat-label>
<input
matInput
[matDatepicker]="dobPicker"
[min]="minDate"
[max]="maxDate"
formControlName="dateOfBirth"
readonly
/>
<mat-datepicker-toggle matSuffix [for]="dobPicker"></mat-datepicker-toggle>
<mat-datepicker #dobPicker></mat-datepicker>
</mat-form-field>
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Nationality</mat-label>
<mat-select formControlName="nationality">
<mat-option value="Indian">Indian</mat-option>
<mat-option value="NRI">NRI</mat-option>
<mat-option value="Foreign National">Foreign National</mat-option>
</mat-select>
</mat-form-field>
</div>
<!-- ID Verification -->
<div class="nom-section-label"><i class="fas fa-id-card"></i> ID Verification</div>
<div class="nom-row">
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Aadhaar Number</mat-label>
<input matInput formControlName="aadhaarNumber" maxlength="12" placeholder="12-digit Aadhaar" />
</mat-form-field>
<mat-form-field appearance="outline" class="nom-field">
<mat-label>PAN Number</mat-label>
<input
matInput
formControlName="panNumber"
maxlength="10"
placeholder="ABCDE1234F"
style="text-transform: uppercase"
/>
</mat-form-field>
</div>
<div class="nom-row">
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Mobile Number</mat-label>
<input matInput formControlName="mobileNo" maxlength="10" placeholder="10-digit mobile" />
</mat-form-field>
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Nominee Share (%)</mat-label>
<input matInput type="number" formControlName="nomineeShare" readonly />
</mat-form-field>
</div>
<!-- Guardian (shown if minor / not alive) -->
<div class="nom-section-label">
<i class="fas fa-user-friends"></i> Guardian Details
<span class="nom-hint">(if nominee is a minor)</span>
</div>
<div class="nom-row">
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Guardian Name</mat-label>
<input matInput formControlName="guardianName" />
</mat-form-field>
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Guardian Relationship</mat-label>
<mat-select formControlName="guardianRelationship">
@for (rel of relationships; track rel) {
<mat-option [value]="rel">{{ rel }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<!-- Flags -->
<div class="nom-flags">
<mat-checkbox formControlName="isAlive" color="primary">Is Alive</mat-checkbox>
<mat-checkbox formControlName="isDependent" color="primary">Is Dependent</mat-checkbox>
</div>
<!-- Remarks -->
<mat-form-field appearance="outline" class="nom-field nom-field--full">
<mat-label>Remarks</mat-label>
<textarea matInput formControlName="remarks" rows="2"></textarea>
<!-- Search box -->
@if (!selectedClient) {
<div class="nom-search-wrap">
<mat-form-field appearance="outline" class="nom-field--full">
<mat-label>Search by Name, Client ID or Mobile</mat-label>
<mat-icon matPrefix class="nom-search-icon">search</mat-icon>
<input
matInput
[value]="searchText"
(input)="onSearch($any($event.target).value)"
(blur)="dismissSearch()"
placeholder="Type at least 2 characters..."
autocomplete="off"
/>
</mat-form-field>
</form>
}
<!-- ══════════════ LINK EXISTING CLIENT MODE ══════════════ -->
@if (mode === 'linked') {
@if (!selectedClient) {
<!-- Search -->
<div class="nom-search-wrap">
<mat-form-field appearance="outline" class="nom-field--full">
<mat-label>Search by Name or Client ID</mat-label>
<input matInput [value]="searchText" (input)="onSearch($any($event.target).value)" autocomplete="off" />
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
@if (searching) {
<div class="nom-results">
@if (searching || searchResults.length > 0) {
<div class="nom-results">
@if (searching) {
<div class="nom-results__loading">
<mat-progress-spinner diameter="16" mode="indeterminate"></mat-progress-spinner>
<span>Searching...</span>
</div>
</div>
}
@if (!searching && searchResults.length > 0) {
<div class="nom-results">
@for (r of searchResults; track r.id) {
<div class="nom-result-item" (click)="selectClient(r)">
<mat-icon class="nom-result-item__icon">person</mat-icon>
<div class="nom-result-item__info">
<span class="nom-result-item__name">{{ r.displayName }}</span>
<span class="nom-result-item__meta">
ID: {{ r.id }}
@if (r.officeName) {
· {{ r.officeName }}
}
@if (r.mobileNo) {
· {{ r.mobileNo }}
}
</span>
</div>
}
@for (r of searchResults; track r.id) {
<div
class="nom-result-item"
[class.nom-result-item--disabled]="isExcludedNominee(r)"
(mousedown)="selectClient(r); $event.preventDefault()"
>
<mat-icon class="nom-result-item__icon">person</mat-icon>
<div class="nom-result-item__info">
<span class="nom-result-item__name">{{ r.displayName }}</span>
<span class="nom-result-item__meta">
ID: {{ r.id }}
@if (r.officeName) {
· {{ r.officeName }}
}
@if (r.mobileNo) {
· {{ r.mobileNo }}
}
</span>
</div>
}
</div>
}
@if (isExcludedNominee(r)) {
<span class="nom-self-tag">Cannot select (self)</span>
}
</div>
}
@if (!searching && searchText.length >= 2 && searchResults.length === 0) {
<div class="nom-no-results">No clients found</div>
}
</div>
}
</div>
}
@if (!searching && searchText.length >= 2 && searchResults.length === 0) {
<div class="nom-no-results">No clients found</div>
<!-- Selected client card -->
@if (selectedClient) {
<div class="nom-client-card">
<div class="nom-client-card__avatar">
@if (linkedProfileImage) {
<img [src]="linkedProfileImage" alt="" class="nom-client-card__photo" />
} @else {
<mat-icon class="nom-client-card__avatar-icon">person</mat-icon>
}
</div>
<div class="nom-client-card__info">
<span class="nom-client-card__name">{{ selectedClient.displayName }}</span>
<span class="nom-client-card__meta">
ID: {{ selectedClient.id }}
@if (selectedClient.mobileNo) {
· {{ selectedClient.mobileNo }}
}
</span>
</div>
<button mat-icon-button type="button" class="nom-client-card__remove" (click)="removeClient()">
<mat-icon>close</mat-icon>
</button>
</div>
@if (fetchingDetails) {
<div class="nom-fetching">
<mat-progress-spinner diameter="14" mode="indeterminate"></mat-progress-spinner>
<span>Fetching details...</span>
</div>
}
@if (selectedClient) {
<!-- Selected Client Card -->
<div class="nom-client-card">
<div class="nom-client-card__avatar">
@if (linkedProfileImage) {
<img [src]="linkedProfileImage" alt="Profile" class="nom-client-card__photo" />
} @else {
<mat-icon class="nom-client-card__avatar-icon">person</mat-icon>
@if (!fetchingDetails) {
<!-- KYC row -->
@if (clientDob || clientPan || clientAadhaar) {
<div class="nom-kyc-row">
@if (clientDob) {
<span class="nom-kyc-item">
<span class="nom-kyc-label">DOB</span>
<span class="nom-kyc-value">{{ clientDob | dateFormat }}</span>
@if (isMinorByDob) {
<span class="nom-minor-badge">Minor</span>
}
</span>
}
@if (clientPan) {
<span class="nom-kyc-item">
<span class="nom-kyc-label">PAN</span>
<span class="nom-kyc-value">
{{ clientPan }}
@if (linkedKycStatus?.panVerified) {
<mat-icon class="nom-kyc-ok">check_circle</mat-icon>
}
</span>
</span>
}
@if (clientAadhaar) {
<span class="nom-kyc-item">
<span class="nom-kyc-label">AADHAAR</span>
<span class="nom-kyc-value">
{{ clientAadhaar }}
@if (linkedKycStatus?.aadhaarVerified) {
<mat-icon class="nom-kyc-ok">check_circle</mat-icon>
}
</span>
</span>
}
</div>
<div class="nom-client-card__info">
<span class="nom-client-card__name">{{ selectedClient.displayName }}</span>
<span class="nom-client-card__meta">
Client ID: {{ selectedClient.id }}
@if (selectedClient.accountNumber) {
· A/C: {{ selectedClient.accountNumber }}
}
</span>
</div>
<button
mat-icon-button
type="button"
(click)="removeLinked()"
class="nom-client-card__remove"
matTooltip="Remove"
>
<mat-icon>close</mat-icon>
</button>
</div>
@if (fetchingLinkedData) {
<div class="nom-fetching">
<mat-progress-spinner diameter="14" mode="indeterminate"></mat-progress-spinner>
<span>Fetching nominee details...</span>
</div>
}
@if (!fetchingLinkedData) {
<div class="nom-details-grid">
<div class="nom-detail">
<span class="nom-detail__label">Full Name</span>
<span class="nom-detail__value">{{ selectedClient.displayName }}</span>
</div>
<div class="nom-detail">
<span class="nom-detail__label">Date of Birth</span>
<span class="nom-detail__value">{{ clientDob || '—' }}</span>
</div>
@if (clientAadhaar) {
<div class="nom-detail">
<span class="nom-detail__label">Aadhaar</span>
<span class="nom-detail__value">
{{ clientAadhaar }}
@if (linkedKycStatus?.aadhaarVerified) {
<span class="nom-verified"><mat-icon>verified</mat-icon> Verified</span>
}
</span>
</div>
<!-- Fields row -->
<div class="nom-fields-row">
<mat-form-field appearance="outline" class="nom-field-item">
<mat-label>Nomination Type</mat-label>
<mat-select [(ngModel)]="nominationType">
@for (opt of nominationTypeOptions; track opt.value) {
<mat-option [value]="opt.value">{{ opt.label }}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="nom-field-item">
<mat-label>Relationship</mat-label>
<mat-select [(ngModel)]="relationshipId">
@for (rel of relationshipOptions; track rel.id) {
<mat-option [value]="rel.id">{{ rel.name }}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="nom-field-item nom-field-item--sm">
<mat-label>Share %</mat-label>
<input matInput type="number" [(ngModel)]="percentageShare" min="1" max="100" />
@if (percentageShare && (percentageShare < 1 || percentageShare > 100)) {
<mat-error>1–100</mat-error>
}
@if (clientPan) {
<div class="nom-detail">
<span class="nom-detail__label">PAN</span>
<span class="nom-detail__value">
{{ clientPan }}
@if (linkedKycStatus?.panVerified) {
<span class="nom-verified"><mat-icon>verified</mat-icon> Verified</span>
}
</span>
</mat-form-field>
<div class="nom-field-item nom-minor-toggle">
<mat-slide-toggle [(ngModel)]="nomineeIsMinor" [disabled]="minorToggleLocked">Minor</mat-slide-toggle>
</div>
</div>
<!-- Guardian section — shown only when minor is ON -->
@if (nomineeIsMinor) {
<div class="nom-guardian-section">
<div class="nom-guardian-header">
<mat-icon class="nom-guardian-icon">shield</mat-icon>
<span class="nom-guardian-title">Guardian</span>
<span class="nom-guardian-hint">(Required for minor nominee)</span>
</div>
@if (!selectedGuardian) {
<div class="nom-search-wrap">
<mat-form-field appearance="outline" class="nom-field--full">
<mat-label>Search Guardian by Name or Client ID</mat-label>
<mat-icon matPrefix class="nom-search-icon">search</mat-icon>
<input
matInput
[value]="guardianSearchText"
(input)="onGuardianSearch($any($event.target).value)"
(blur)="dismissGuardianSearch()"
placeholder="Type at least 2 characters..."
autocomplete="off"
/>
</mat-form-field>
@if (guardianSearching || guardianSearchResults.length > 0) {
<div class="nom-results">
@if (guardianSearching) {
<div class="nom-results__loading">
<mat-progress-spinner diameter="16" mode="indeterminate"></mat-progress-spinner>
<span>Searching...</span>
</div>
}
@for (r of guardianSearchResults; track r.id) {
<div
class="nom-result-item"
[class.nom-result-item--disabled]="selectedClient && r.id === selectedClient.id"
(mousedown)="selectGuardian(r); $event.preventDefault()"
>
<mat-icon class="nom-result-item__icon">person</mat-icon>
<div class="nom-result-item__info">
<span class="nom-result-item__name">{{ r.displayName }}</span>
<span class="nom-result-item__meta"
>ID: {{ r.id }}
@if (r.mobileNo) {
· {{ r.mobileNo }}
}
</span>
</div>
@if (selectedClient && r.id === selectedClient.id) {
<span class="nom-result-item__conflict">Same as nominee</span>
}
</div>
}
@if (!guardianSearching && guardianSearchText.length >= 2 && guardianSearchResults.length === 0) {
<div class="nom-no-results">No clients found</div>
}
</div>
}
</div>
} @else {
<!-- Selected guardian card -->
<div class="nom-guardian-card" [class.nom-guardian-card--error]="guardianSameAsNominee">
<mat-icon class="nom-guardian-card__icon">person</mat-icon>
<div class="nom-guardian-card__info">
<span class="nom-guardian-card__name">{{ selectedGuardian.displayName }}</span>
<span class="nom-guardian-card__meta"
>ID: {{ selectedGuardian.id }}
@if (selectedGuardian.mobileNo) {
· {{ selectedGuardian.mobileNo }}
}
</span>
</div>
<button mat-icon-button type="button" (click)="removeGuardian()">
<mat-icon>close</mat-icon>
</button>
</div>
@if (guardianSameAsNominee) {
<div class="nom-conflict-error">
<mat-icon>error_outline</mat-icon>
Guardian and nominee cannot be the same client (same Client ID / CIF).
</div>
}
}
</div>
}
<!-- Relationship picker for linked client -->
<div class="nom-linked-extras">
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Relationship *</mat-label>
<mat-select [(ngModel)]="linkedRelationship" (ngModelChange)="onLinkedRelationshipChange($event)">
@for (rel of relationships; track rel) {
<mat-option [value]="rel">{{ rel }}</mat-option>
}
</mat-select>
</mat-form-field>
<!-- Remarks -->
<mat-form-field appearance="outline" class="nom-field--full">
<mat-label>Remarks</mat-label>
<input matInput [(ngModel)]="remarks" placeholder="Optional" />
</mat-form-field>
<mat-form-field appearance="outline" class="nom-field">
<mat-label>Nominee Share (%)</mat-label>
<input matInput type="number" [value]="100" readonly />
</mat-form-field>
<!-- Actions -->
@if (showActions) {
<div class="nom-actions">
<button mat-stroked-button type="button" (click)="cancel()">Cancel</button>
<button mat-raised-button color="primary" type="button" [disabled]="!isValid" (click)="save()">
<mat-icon>check</mat-icon> Save
</button>
</div>
}
}