merging code

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nitesh Yadav
2026-04-20 14:26:25 +05:30
co-authored by Claude Sonnet 4.6
322 changed files with 28779 additions and 4976 deletions
@@ -20,15 +20,18 @@
<mat-tab-group class="addr-tabs" [(selectedIndex)]="activeTab" animationDuration="150ms">
<!-- ═══ TAB 1: PERMANENT ═══ -->
<mat-tab>
<ng-template mat-tab-label>
<span class="addr-tab-num">1</span> Permanent Address
</ng-template>
<ng-template mat-tab-label> <span class="addr-tab-num">1</span> Permanent Address </ng-template>
<div class="addr-panel" [formGroup]="permanentForm">
<div class="addr-grid addr-grid--1">
<mat-form-field appearance="outline" class="addr-ff">
<mat-label>Address Line 1</mat-label>
<span matPrefix class="addr-prefix"><mat-icon>home</mat-icon></span>
<input matInput required formControlName="addressLine1" placeholder="House / Flat No., Floor, Building Name" />
<input
matInput
required
formControlName="addressLine1"
placeholder="House / Flat No., Floor, Building Name"
/>
</mat-form-field>
</div>
<div class="addr-grid addr-grid--1">
@@ -45,9 +48,15 @@
<mat-form-field appearance="outline" class="addr-ff">
<mat-label>PIN Code</mat-label>
<span matPrefix class="addr-prefix"><mat-icon>pin_drop</mat-icon></span>
<input matInput required formControlName="pinCode" maxlength="6" placeholder="6-digit PIN"
<input
matInput
required
formControlName="pinCode"
maxlength="6"
placeholder="6-digit PIN"
(input)="onPinInput('permanent')"
(keypress)="$event.charCode >= 48 && $event.charCode <= 57 ? true : $event.preventDefault()" />
(keypress)="$event.charCode >= 48 && $event.charCode <= 57 ? true : $event.preventDefault()"
/>
@if (permanentForm.get('pinCode')?.hasError('pattern') && permanentForm.get('pinCode')?.touched) {
<mat-error>Enter a valid 6-digit PIN code</mat-error>
}
@@ -126,9 +135,7 @@
<!-- ═══ TAB 2: CURRENT / RESIDENTIAL ═══ -->
<mat-tab>
<ng-template mat-tab-label>
<span class="addr-tab-num">2</span> Current / Residential
</ng-template>
<ng-template mat-tab-label> <span class="addr-tab-num">2</span> Current / Residential </ng-template>
<div class="addr-panel" [formGroup]="currentForm">
<div class="addr-same-row">
<mat-checkbox [checked]="sameAsPermanent" (change)="toggleSameAsPermanent($event.checked)">
@@ -140,7 +147,12 @@
<div class="addr-grid addr-grid--1">
<mat-form-field appearance="outline" class="addr-ff">
<mat-label>Address Line 1</mat-label>
<input matInput required formControlName="addressLine1" placeholder="House / Flat No., Floor, Building Name" />
<input
matInput
required
formControlName="addressLine1"
placeholder="House / Flat No., Floor, Building Name"
/>
</mat-form-field>
</div>
<div class="addr-grid addr-grid--1">
@@ -155,9 +167,15 @@
<div class="addr-grid addr-grid--2">
<mat-form-field appearance="outline" class="addr-ff">
<mat-label>PIN Code</mat-label>
<input matInput required formControlName="pinCode" maxlength="6" placeholder="6-digit PIN"
<input
matInput
required
formControlName="pinCode"
maxlength="6"
placeholder="6-digit PIN"
(input)="onPinInput('current')"
(keypress)="$event.charCode >= 48 && $event.charCode <= 57 ? true : $event.preventDefault()" />
(keypress)="$event.charCode >= 48 && $event.charCode <= 57 ? true : $event.preventDefault()"
/>
@if (currentForm.get('pinCode')?.hasError('pattern') && currentForm.get('pinCode')?.touched) {
<mat-error>Enter a valid 6-digit PIN code</mat-error>
}
@@ -230,9 +248,7 @@
<!-- ═══ TAB 3: OFFICE / WORK ═══ -->
<mat-tab>
<ng-template mat-tab-label>
<span class="addr-tab-num">3</span> Office / Work
</ng-template>
<ng-template mat-tab-label> <span class="addr-tab-num">3</span> Office / Work </ng-template>
<div class="addr-panel" [formGroup]="officeForm">
<div class="addr-grid addr-grid--2">
<mat-form-field appearance="outline" class="addr-ff">
@@ -268,9 +284,14 @@
<mat-form-field appearance="outline" class="addr-ff">
<mat-label>PIN Code</mat-label>
<span matPrefix class="addr-prefix"><mat-icon>pin_drop</mat-icon></span>
<input matInput formControlName="pinCode" maxlength="6" placeholder="6-digit PIN"
<input
matInput
formControlName="pinCode"
maxlength="6"
placeholder="6-digit PIN"
(input)="onPinInput('office')"
(keypress)="$event.charCode >= 48 && $event.charCode <= 57 ? true : $event.preventDefault()" />
(keypress)="$event.charCode >= 48 && $event.charCode <= 57 ? true : $event.preventDefault()"
/>
@if (officeForm.get('pinCode')?.hasError('pattern') && officeForm.get('pinCode')?.touched) {
<mat-error>Enter a valid 6-digit PIN code</mat-error>
}
@@ -348,13 +369,13 @@
<!-- ═══ TAB 4: CORRESPONDENCE ═══ -->
<mat-tab>
<ng-template mat-tab-label>
<span class="addr-tab-num">4</span> Correspondence
</ng-template>
<ng-template mat-tab-label> <span class="addr-tab-num">4</span> Correspondence </ng-template>
<div class="addr-panel" [formGroup]="correspondenceForm">
<div class="addr-copy-row">
<span class="addr-copy-label">Copy address from:</span>
<button mat-stroked-button type="button" class="addr-copy-btn" (click)="copyFrom('permanent')">Permanent</button>
<button mat-stroked-button type="button" class="addr-copy-btn" (click)="copyFrom('permanent')">
Permanent
</button>
<button mat-stroked-button type="button" class="addr-copy-btn" (click)="copyFrom('current')">Current</button>
<button mat-stroked-button type="button" class="addr-copy-btn" (click)="copyFrom('office')">Office</button>
</div>
@@ -363,7 +384,12 @@
<mat-form-field appearance="outline" class="addr-ff">
<mat-label>Address Line 1</mat-label>
<span matPrefix class="addr-prefix"><mat-icon>home</mat-icon></span>
<input matInput required formControlName="addressLine1" placeholder="House / Flat No., Floor, Building Name" />
<input
matInput
required
formControlName="addressLine1"
placeholder="House / Flat No., Floor, Building Name"
/>
</mat-form-field>
</div>
<div class="addr-grid addr-grid--1">
@@ -380,9 +406,15 @@
<mat-form-field appearance="outline" class="addr-ff">
<mat-label>PIN Code</mat-label>
<span matPrefix class="addr-prefix"><mat-icon>pin_drop</mat-icon></span>
<input matInput required formControlName="pinCode" maxlength="6" placeholder="6-digit PIN"
<input
matInput
required
formControlName="pinCode"
maxlength="6"
placeholder="6-digit PIN"
(input)="onPinInput('correspondence')"
(keypress)="$event.charCode >= 48 && $event.charCode <= 57 ? true : $event.preventDefault()" />
(keypress)="$event.charCode >= 48 && $event.charCode <= 57 ? true : $event.preventDefault()"
/>
@if (correspondenceForm.get('pinCode')?.hasError('pattern') && correspondenceForm.get('pinCode')?.touched) {
<mat-error>Enter a valid 6-digit PIN code</mat-error>
}
@@ -1,3 +1,11 @@
/**
* Copyright since 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* Copyright since 2025 Mifos Initiative
*/
@@ -38,7 +46,7 @@ $muted: #64748b;
&__sub {
font-size: 11px;
color: rgba(255, 255, 255, 0.5);
color: rgb(255 255 255 / 50%);
margin: 2px 0 0;
}
}
@@ -76,9 +84,17 @@ $muted: #64748b;
gap: 4px 16px;
margin-bottom: 4px;
&--1 { grid-template-columns: 1fr; }
&--2 { grid-template-columns: 1fr 1fr; }
&--3 { grid-template-columns: 1fr 1fr 1fr; }
&--1 {
grid-template-columns: 1fr;
}
&--2 {
grid-template-columns: 1fr 1fr;
}
&--3 {
grid-template-columns: 1fr 1fr 1fr;
}
}
.addr-ff {
@@ -101,7 +117,8 @@ $muted: #64748b;
white-space: nowrap;
}
&::before, &::after {
&::before,
&::after {
content: '';
flex: 1;
height: 1px;
@@ -173,8 +190,9 @@ $muted: #64748b;
}
// Responsive
@media (max-width: 768px) {
.addr-grid--2, .addr-grid--3 {
@media (width <= 768px) {
.addr-grid--2,
.addr-grid--3 {
grid-template-columns: 1fr;
}
@@ -42,27 +42,60 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
sameAsPermanent = false;
permanentForm: UntypedFormGroup = this.fb.group({
addressLine1: ['', Validators.required],
addressLine1: [
'',
Validators.required
],
addressLine2: [''],
pinCode: ['', [Validators.required, Validators.pattern(/^\d{6}$/)]],
locality: ['', Validators.required],
pinCode: [
'',
[
Validators.required,
Validators.pattern(/^\d{6}$/)
]
],
locality: [
'',
Validators.required
],
city: [''],
district: [''],
state: ['', Validators.required],
state: [
'',
Validators.required
],
country: [{ value: 'India', disabled: true }],
landmark: [''],
proofType: ['', Validators.required],
proofType: [
'',
Validators.required
],
proofDocNumber: ['']
});
currentForm: UntypedFormGroup = this.fb.group({
addressLine1: ['', Validators.required],
addressLine1: [
'',
Validators.required
],
addressLine2: [''],
pinCode: ['', [Validators.required, Validators.pattern(/^\d{6}$/)]],
locality: ['', Validators.required],
pinCode: [
'',
[
Validators.required,
Validators.pattern(/^\d{6}$/)
]
],
locality: [
'',
Validators.required
],
city: [''],
district: [''],
state: ['', Validators.required],
state: [
'',
Validators.required
],
country: [{ value: 'India', disabled: true }],
landmark: [''],
residenceType: [''],
@@ -74,7 +107,10 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
department: [''],
addressLine1: [''],
addressLine2: [''],
pinCode: ['', Validators.pattern(/^\d{6}$/)],
pinCode: [
'',
Validators.pattern(/^\d{6}$/)
],
locality: [''],
city: [''],
district: [''],
@@ -87,13 +123,28 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
});
correspondenceForm: UntypedFormGroup = this.fb.group({
addressLine1: ['', Validators.required],
addressLine1: [
'',
Validators.required
],
addressLine2: [''],
pinCode: ['', [Validators.required, Validators.pattern(/^\d{6}$/)]],
locality: ['', Validators.required],
pinCode: [
'',
[
Validators.required,
Validators.pattern(/^\d{6}$/)
]
],
locality: [
'',
Validators.required
],
city: [''],
district: [''],
state: ['', Validators.required],
state: [
'',
Validators.required
],
country: [{ value: 'India', disabled: true }],
landmark: [''],
commMode: [''],
@@ -116,18 +167,36 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
};
proofTypes = [
'Aadhaar Card', 'Passport', 'Voter ID', 'Driving Licence',
'Utility Bill (not older than 3 months)', 'Bank Statement'
'Aadhaar Card',
'Passport',
'Voter ID',
'Driving Licence',
'Utility Bill (not older than 3 months)',
'Bank Statement'
];
residenceTypes = ['Owned', 'Rented', 'Leased', 'Company Provided', 'Parental / Family Owned'];
residenceTypes = [
'Owned',
'Rented',
'Leased',
'Company Provided',
'Parental / Family Owned'
];
employmentTypes = [
'Salaried (Private)', 'Salaried (Government / PSU)',
'Self-Employed Professional', 'Business Owner', 'Retired'
'Salaried (Private)',
'Salaried (Government / PSU)',
'Self-Employed Professional',
'Business Owner',
'Retired'
];
commModes = ['Post / Courier', 'Email', 'SMS', 'WhatsApp'];
commModes = [
'Post / Courier',
'Email',
'SMS',
'WhatsApp'
];
private pinTimers: Record<string, any> = {};
private pinCache: Record<string, any[]> = {};
@@ -144,7 +213,12 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges): void {
if (changes['readOnly']) {
const forms = [this.permanentForm, this.currentForm, this.officeForm, this.correspondenceForm];
const forms = [
this.permanentForm,
this.currentForm,
this.officeForm,
this.correspondenceForm
];
for (const form of forms) {
if (this.readOnly) {
form.disable({ emitEvent: false });
@@ -168,10 +242,19 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
// Build type-to-tab mapping from address type names
const tabMap: Record<string, string> = {
permanent: 'permanent', 'permanent address': 'permanent',
residential: 'current', current: 'current', 'current / residential': 'current', communication: 'current',
office: 'office', 'office / work': 'office', business: 'office', work: 'office',
correspondence: 'correspondence', mailing: 'correspondence', postal: 'correspondence'
permanent: 'permanent',
'permanent address': 'permanent',
residential: 'current',
current: 'current',
'current / residential': 'current',
communication: 'current',
office: 'office',
'office / work': 'office',
business: 'office',
work: 'office',
correspondence: 'correspondence',
mailing: 'correspondence',
postal: 'correspondence'
};
for (const addr of addresses) {
@@ -192,7 +275,9 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
});
}
},
error: () => { this.addressLoaded = true; }
error: () => {
this.addressLoaded = true;
}
});
}
@@ -235,11 +320,13 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
private applyPinData(tab: string, offices: any[]) {
const seen = new Set<string>();
this.localityOptions[tab] = offices.filter(o => {
if (seen.has(o.Name)) return false;
seen.add(o.Name);
return true;
}).map(o => o.Name);
this.localityOptions[tab] = offices
.filter((o) => {
if (seen.has(o.Name)) return false;
seen.add(o.Name);
return true;
})
.map((o) => o.Name);
const form = this.getForm(tab);
const f = offices[0];
@@ -259,11 +346,16 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
getForm(tab: string): UntypedFormGroup {
switch (tab) {
case 'permanent': return this.permanentForm;
case 'current': return this.currentForm;
case 'office': return this.officeForm;
case 'correspondence': return this.correspondenceForm;
default: return this.permanentForm;
case 'permanent':
return this.permanentForm;
case 'current':
return this.currentForm;
case 'office':
return this.officeForm;
case 'correspondence':
return this.correspondenceForm;
default:
return this.permanentForm;
}
}
@@ -307,7 +399,9 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
get addressData(): any {
return {
permanent: this.permanentForm.getRawValue(),
current: this.sameAsPermanent ? { ...this.permanentForm.getRawValue(), sameAsPermanent: true } : this.currentForm.getRawValue(),
current: this.sameAsPermanent
? { ...this.permanentForm.getRawValue(), sameAsPermanent: true }
: this.currentForm.getRawValue(),
office: this.officeForm.getRawValue(),
correspondence: this.correspondenceForm.getRawValue()
};