fix(clients): address-proof date fields use calendar picker, Pension Payment Order gets one too
Both the address-proof upload dialog and the permanent-address step used a native `type="date"` input for the issue/statement date, so no calendar popup was available. Switched both to Angular Material's datepicker, kept the client-india-address-step round-trip (payload -> saved description -> re-parsed on edit) working with the Dates util now that the control holds a Date object instead of a raw string. Pension Payment Orders was also the only "Financial & Other" address-proof type missing requiresDate, so selecting it never showed a date field at all — added the flag and moved Monthly/Yearly Turnover under the "Other Income" heading alongside Agriculture/Non-Agriculture Income.
This commit is contained in:
+32
-32
@@ -1232,38 +1232,6 @@
|
|||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field appearance="outline" class="form-field">
|
|
||||||
<mat-label>Monthly Turnover</mat-label>
|
|
||||||
<span matPrefix class="rupee-prefix">₹</span>
|
|
||||||
<input matInput type="number" formControlName="monthlyTurnover" min="0" />
|
|
||||||
@if (
|
|
||||||
createClientForm.get('monthlyTurnover')?.hasError('pattern') &&
|
|
||||||
createClientForm.get('monthlyTurnover')?.touched
|
|
||||||
) {
|
|
||||||
<mat-error>Enter a valid amount</mat-error>
|
|
||||||
} @else if (
|
|
||||||
createClientForm.get('monthlyTurnover')?.hasError('min') && createClientForm.get('monthlyTurnover')?.touched
|
|
||||||
) {
|
|
||||||
<mat-error>Amount cannot be negative</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<mat-form-field appearance="outline" class="form-field">
|
|
||||||
<mat-label>Yearly Turnover</mat-label>
|
|
||||||
<span matPrefix class="rupee-prefix">₹</span>
|
|
||||||
<input matInput type="number" formControlName="annualTurnover" min="0" />
|
|
||||||
@if (
|
|
||||||
createClientForm.get('annualTurnover')?.hasError('pattern') &&
|
|
||||||
createClientForm.get('annualTurnover')?.touched
|
|
||||||
) {
|
|
||||||
<mat-error>Enter a valid amount</mat-error>
|
|
||||||
} @else if (
|
|
||||||
createClientForm.get('annualTurnover')?.hasError('min') && createClientForm.get('annualTurnover')?.touched
|
|
||||||
) {
|
|
||||||
<mat-error>Amount cannot be negative</mat-error>
|
|
||||||
}
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<div class="full-width subsection-title">
|
<div class="full-width subsection-title">
|
||||||
<fa-icon icon="coins" class="subsection-icon"></fa-icon>
|
<fa-icon icon="coins" class="subsection-icon"></fa-icon>
|
||||||
Other Income
|
Other Income
|
||||||
@@ -1303,6 +1271,38 @@
|
|||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>Monthly Turnover</mat-label>
|
||||||
|
<span matPrefix class="rupee-prefix">₹</span>
|
||||||
|
<input matInput type="number" formControlName="monthlyTurnover" min="0" />
|
||||||
|
@if (
|
||||||
|
createClientForm.get('monthlyTurnover')?.hasError('pattern') &&
|
||||||
|
createClientForm.get('monthlyTurnover')?.touched
|
||||||
|
) {
|
||||||
|
<mat-error>Enter a valid amount</mat-error>
|
||||||
|
} @else if (
|
||||||
|
createClientForm.get('monthlyTurnover')?.hasError('min') && createClientForm.get('monthlyTurnover')?.touched
|
||||||
|
) {
|
||||||
|
<mat-error>Amount cannot be negative</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="outline" class="form-field">
|
||||||
|
<mat-label>Yearly Turnover</mat-label>
|
||||||
|
<span matPrefix class="rupee-prefix">₹</span>
|
||||||
|
<input matInput type="number" formControlName="annualTurnover" min="0" />
|
||||||
|
@if (
|
||||||
|
createClientForm.get('annualTurnover')?.hasError('pattern') &&
|
||||||
|
createClientForm.get('annualTurnover')?.touched
|
||||||
|
) {
|
||||||
|
<mat-error>Enter a valid amount</mat-error>
|
||||||
|
} @else if (
|
||||||
|
createClientForm.get('annualTurnover')?.hasError('min') && createClientForm.get('annualTurnover')?.touched
|
||||||
|
) {
|
||||||
|
<mat-error>Amount cannot be negative</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<div class="full-width subsection-title">
|
<div class="full-width subsection-title">
|
||||||
<fa-icon icon="user-shield" class="subsection-icon"></fa-icon>
|
<fa-icon icon="user-shield" class="subsection-icon"></fa-icon>
|
||||||
Senior Citizen / Person with Disability
|
Senior Citizen / Person with Disability
|
||||||
|
|||||||
+3
-2
@@ -173,8 +173,9 @@
|
|||||||
@if (selectedAddrProof.requiresDate) {
|
@if (selectedAddrProof.requiresDate) {
|
||||||
<mat-form-field appearance="outline" class="addr-ff">
|
<mat-form-field appearance="outline" class="addr-ff">
|
||||||
<mat-label>Issue / bill date</mat-label>
|
<mat-label>Issue / bill date</mat-label>
|
||||||
<span matPrefix class="addr-prefix"><mat-icon>event</mat-icon></span>
|
<input matInput [matDatepicker]="addrIssueDatePicker" formControlName="issueDate" />
|
||||||
<input matInput type="date" formControlName="issueDate" />
|
<mat-datepicker-toggle matSuffix [for]="addrIssueDatePicker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #addrIssueDatePicker></mat-datepicker>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+6
-3
@@ -20,6 +20,7 @@ import { ClientsService } from '../../clients.service';
|
|||||||
import { ProofType, normalizeProofType, groupProofsByCategory } from '../../shared/kyc-proof-types';
|
import { ProofType, normalizeProofType, groupProofsByCategory } from '../../shared/kyc-proof-types';
|
||||||
import { KycUploadHelperService } from '../../shared/kyc-upload-helper.service';
|
import { KycUploadHelperService } from '../../shared/kyc-upload-helper.service';
|
||||||
import { DocumentPreviewDialogComponent } from '../../shared/document-preview-dialog/document-preview-dialog.component';
|
import { DocumentPreviewDialogComponent } from '../../shared/document-preview-dialog/document-preview-dialog.component';
|
||||||
|
import { Dates } from 'app/core/utils/dates';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'mifosx-client-india-address-step',
|
selector: 'mifosx-client-india-address-step',
|
||||||
@@ -41,6 +42,7 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
|
|||||||
private clientsService = inject(ClientsService);
|
private clientsService = inject(ClientsService);
|
||||||
private kycUpload = inject(KycUploadHelperService);
|
private kycUpload = inject(KycUploadHelperService);
|
||||||
private dialog = inject(MatDialog);
|
private dialog = inject(MatDialog);
|
||||||
|
private dates = inject(Dates);
|
||||||
|
|
||||||
/** Client ID — when set, loads existing addresses for edit mode */
|
/** Client ID — when set, loads existing addresses for edit mode */
|
||||||
@Input() clientId: string = '';
|
@Input() clientId: string = '';
|
||||||
@@ -413,11 +415,12 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
|
|||||||
files.push({ slot: 'Back', file: this.addrFiles.back });
|
files.push({ slot: 'Back', file: this.addrFiles.back });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const rawIssueDate = this.permanentForm.get('issueDate')?.value;
|
||||||
return {
|
return {
|
||||||
proof: this.selectedAddrProof,
|
proof: this.selectedAddrProof,
|
||||||
proofId: this.permanentForm.get('proofId')?.value || '',
|
proofId: this.permanentForm.get('proofId')?.value || '',
|
||||||
documentKey: this.permanentForm.get('documentKey')?.value || '',
|
documentKey: this.permanentForm.get('documentKey')?.value || '',
|
||||||
issueDate: this.permanentForm.get('issueDate')?.value || '',
|
issueDate: rawIssueDate ? this.dates.getDate(rawIssueDate) : '',
|
||||||
files
|
files
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -560,13 +563,13 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
|
|||||||
proofId: matchedProof.id,
|
proofId: matchedProof.id,
|
||||||
documentKey: identifier.documentKey || ''
|
documentKey: identifier.documentKey || ''
|
||||||
});
|
});
|
||||||
// The description carries `Issue date: dd/mm/yyyy` when set on create (see
|
// The description carries `Issue date: yyyy-MM-dd` when set on create (see
|
||||||
// create-client.saveAddressProof) — pull it out so the form's issueDate field
|
// create-client.saveAddressProof) — pull it out so the form's issueDate field
|
||||||
// shows what was previously entered.
|
// shows what was previously entered.
|
||||||
const desc: string = identifier.description || '';
|
const desc: string = identifier.description || '';
|
||||||
const issueMatch = desc.match(/Issue date:\s*(.+)$/i);
|
const issueMatch = desc.match(/Issue date:\s*(.+)$/i);
|
||||||
if (issueMatch) {
|
if (issueMatch) {
|
||||||
this.permanentForm.patchValue({ issueDate: issueMatch[1].trim() });
|
this.permanentForm.patchValue({ issueDate: this.dates.parseDate(issueMatch[1].trim()) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-3
@@ -347,9 +347,18 @@
|
|||||||
<i class="fa fa-calendar"></i> Issue / statement date
|
<i class="fa fa-calendar"></i> Issue / statement date
|
||||||
<span class="kyc-opt">(not older than 3 months)</span>
|
<span class="kyc-opt">(not older than 3 months)</span>
|
||||||
</label>
|
</label>
|
||||||
<div class="kyc-input-wrap kyc-input-wrap--date">
|
<div class="kyc-input-wrap kyc-input-wrap--date" (click)="uploadIssueDatePicker.open()">
|
||||||
<i class="fa fa-calendar-o kyc-input-wrap__icon"></i>
|
<input
|
||||||
<input type="date" class="kyc-input kyc-input--date" formControlName="issueDate" />
|
class="kyc-input kyc-input--date"
|
||||||
|
[matDatepicker]="uploadIssueDatePicker"
|
||||||
|
formControlName="issueDate"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
<mat-datepicker-toggle
|
||||||
|
class="kyc-input-wrap__calendar-toggle"
|
||||||
|
[for]="uploadIssueDatePicker"
|
||||||
|
></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #uploadIssueDatePicker></mat-datepicker>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-28
@@ -388,42 +388,32 @@ $red-900: #993c1d;
|
|||||||
padding-left: 38px;
|
padding-left: 38px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Date input — match styling of other kyc inputs */
|
/* Date input — opens the Material calendar picker; styled to match other kyc inputs */
|
||||||
.kyc-input--date {
|
.kyc-input--date {
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
color: $gray-900;
|
color: $gray-900;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
padding-right: 14px !important;
|
padding-left: 12px !important;
|
||||||
|
padding-right: 40px !important;
|
||||||
|
}
|
||||||
|
|
||||||
&::-webkit-calendar-picker-indicator {
|
.kyc-input-wrap--date .kyc-input-wrap__calendar-toggle {
|
||||||
opacity: 0.55;
|
position: absolute;
|
||||||
cursor: pointer;
|
right: 2px;
|
||||||
filter: grayscale(1);
|
top: 50%;
|
||||||
transition: opacity 0.15s;
|
transform: translateY(-50%);
|
||||||
|
color: $gray-500;
|
||||||
|
|
||||||
|
::ng-deep .mat-mdc-icon-button {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover::-webkit-calendar-picker-indicator {
|
::ng-deep .mat-mdc-icon-button svg {
|
||||||
opacity: 0.9;
|
width: 18px;
|
||||||
}
|
height: 18px;
|
||||||
|
|
||||||
&::-webkit-datetime-edit {
|
|
||||||
color: $gray-900;
|
|
||||||
padding-top: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-datetime-edit-fields-wrapper {
|
|
||||||
color: $gray-900;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-datetime-edit-text {
|
|
||||||
color: $gray-500;
|
|
||||||
padding: 0 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:invalid::-webkit-datetime-edit,
|
|
||||||
&:not(:focus):placeholder-shown::-webkit-datetime-edit {
|
|
||||||
color: $gray-500;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ export const PROOF_META: Record<string, Partial<ProofType>> = {
|
|||||||
PENSION_PAYMENT_ORDER: {
|
PENSION_PAYMENT_ORDER: {
|
||||||
sides: 1,
|
sides: 1,
|
||||||
category: 'Financial & other',
|
category: 'Financial & other',
|
||||||
|
requiresDate: true,
|
||||||
info: 'Pension payment order — upload full document issued by pension authority.'
|
info: 'Pension payment order — upload full document issued by pension authority.'
|
||||||
},
|
},
|
||||||
CERT_INCORPORATION: {
|
CERT_INCORPORATION: {
|
||||||
|
|||||||
Reference in New Issue
Block a user