+56
-24
@@ -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>
|
||||
}
|
||||
|
||||
+25
-7
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+131
-37
@@ -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()
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user