Skip to content

Commit 6a1a8a6

Browse files
authored
Merge pull request #2652 from JaySoni1/WEB-223-make-date-of-birth-handling-for-client-creation-consistent
WEB-223 Make Date of Birth handling for Client Creation consistent
2 parents 293486e + 60d47ba commit 6a1a8a6

File tree

10 files changed

+253
-69
lines changed

10 files changed

+253
-69
lines changed

src/app/clients/client-stepper/client-family-members-step/client-family-member-dialog/client-family-member-dialog.component.html

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,7 @@ <h1 mat-dialog-title>{{ data.context }} {{ 'labels.heading.Family Member' | tran
3232

3333
<mat-form-field class="flex-48">
3434
<mat-label>{{ 'labels.inputs.Age' | translate }}</mat-label>
35-
<input type="number" formControlName="age" matInput [min]="0" />
36-
<mat-error *ngIf="familyMemberForm.controls.age.hasError('required')">
37-
{{ 'labels.inputs.Age' | translate }} {{ 'labels.commons.is' | translate }}
38-
<strong>{{ 'labels.commons.required and cannot be negative' | translate }}</strong>
39-
</mat-error>
35+
<input type="number" formControlName="age" matInput [min]="0" disabled />
4036
</mat-form-field>
4137

4238
<mat-checkbox formControlName="isDependent" labelPosition="before" class="flex-48"
@@ -89,19 +85,22 @@ <h1 mat-dialog-title>{{ data.context }} {{ 'labels.heading.Family Member' | tran
8985

9086
<mat-form-field class="flex-98" (click)="dueDatePicker.open()">
9187
<mat-label>{{ 'labels.inputs.Date Of Birth' | translate }}</mat-label>
92-
<input formControlName="dateOfBirth" matInput [max]="maxDate" [matDatepicker]="dueDatePicker" required />
88+
<input
89+
formControlName="dateOfBirth"
90+
matInput
91+
[max]="maxDate"
92+
[matDatepicker]="dueDatePicker"
93+
placeholder="Optional"
94+
/>
9395
<mat-datepicker-toggle matSuffix [for]="dueDatePicker"></mat-datepicker-toggle>
9496
<mat-datepicker #dueDatePicker></mat-datepicker>
95-
<mat-error *ngIf="familyMemberForm.controls.dateOfBirth.hasError('required')">
96-
{{ 'labels.inputs.Date Of Birth' | translate }} {{ 'labels.commons.is' | translate }}
97-
<strong>{{ 'labels.commons.required' | translate }}</strong>
98-
</mat-error>
9997
</mat-form-field>
10098
</div>
10199

102100
<mat-dialog-actions align="center">
103-
<button mat-raised-button mat-dialog-close>{{ 'labels.buttons.Cancel' | translate }}</button>
101+
<button type="button" mat-raised-button mat-dialog-close>{{ 'labels.buttons.Cancel' | translate }}</button>
104102
<button
103+
type="button"
105104
mat-raised-button
106105
color="primary"
107106
[disabled]="!familyMemberForm.valid"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.mat-form-field-hint {
2+
font-size: 75%;
3+
color: rgb(0 0 0 / 60%);
4+
margin-top: 4px;
5+
margin-bottom: 8px;
6+
}

src/app/clients/client-stepper/client-family-members-step/client-family-member-dialog/client-family-member-dialog.component.ts

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,41 @@ export class ClientFamilyMemberDialogComponent implements OnInit {
7070
dateOfBirth: this.data.member.dateOfBirth && new Date(this.data.member.dateOfBirth)
7171
});
7272
}
73+
74+
// Add subscription to date of birth changes to update age
75+
this.familyMemberForm.get('dateOfBirth').valueChanges.subscribe((dateOfBirth: any) => {
76+
if (dateOfBirth) {
77+
const age = this.calculateAge(dateOfBirth);
78+
this.familyMemberForm.get('age').setValue(age);
79+
} else {
80+
this.familyMemberForm.get('age').setValue('');
81+
}
82+
});
83+
84+
// If a date of birth is already set, calculate the age
85+
const currentDob = this.familyMemberForm.get('dateOfBirth').value;
86+
if (currentDob) {
87+
const age = this.calculateAge(currentDob);
88+
this.familyMemberForm.get('age').setValue(age);
89+
}
90+
}
91+
92+
/**
93+
* Calculates age from date of birth
94+
* @param {Date} dateOfBirth Date of Birth
95+
* @returns {number} Age
96+
*/
97+
calculateAge(dateOfBirth: Date): number {
98+
const today = new Date(this.settingsService.businessDate);
99+
const birthDate = new Date(dateOfBirth);
100+
let age = today.getFullYear() - birthDate.getFullYear();
101+
const monthDiff = today.getMonth() - birthDate.getMonth();
102+
103+
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
104+
age--;
105+
}
106+
107+
return age;
73108
}
74109

75110
/**
@@ -88,9 +123,7 @@ export class ClientFamilyMemberDialogComponent implements OnInit {
88123
],
89124
qualification: [''],
90125
age: [
91-
'',
92-
Validators.required
93-
],
126+
{ value: '', disabled: true }],
94127
isDependent: [''],
95128
relationshipId: [
96129
'',
@@ -102,33 +135,51 @@ export class ClientFamilyMemberDialogComponent implements OnInit {
102135
],
103136
professionId: [''],
104137
maritalStatusId: [''],
105-
dateOfBirth: [
106-
'',
107-
Validators.required
108-
]
138+
dateOfBirth: ['']
109139
});
110140
}
111141

112142
/**
113143
* Returns Formatted Family Member
114144
*/
115145
get familyMember() {
116-
const familyMemberFormData = this.familyMemberForm.value;
146+
// Get form values including disabled controls like age
147+
const formValue = {
148+
...this.familyMemberForm.getRawValue()
149+
};
150+
117151
const locale = this.settingsService.language.code;
118152
const dateFormat = this.settingsService.dateFormat;
119-
if (familyMemberFormData.dateOfBirth instanceof Date) {
120-
familyMemberFormData.dateOfBirth = this.dateUtils.formatDate(familyMemberFormData.dateOfBirth, dateFormat);
153+
const prevDateOfBirth: Date = formValue.dateOfBirth;
154+
155+
// Calculate age from dateOfBirth if present
156+
if (prevDateOfBirth) {
157+
if (formValue.dateOfBirth instanceof Date) {
158+
formValue.dateOfBirth = this.dateUtils.formatDate(prevDateOfBirth, dateFormat);
159+
}
160+
// Ensure age is calculated even if it wasn't already
161+
if (!formValue.age && prevDateOfBirth) {
162+
formValue.age = this.calculateAge(prevDateOfBirth);
163+
}
164+
} else {
165+
// If no date of birth, remove age and dateOfBirth from submission
166+
delete formValue.age;
167+
delete formValue.dateOfBirth;
121168
}
169+
122170
const familyMember = {
123-
...familyMemberFormData,
171+
...formValue,
124172
dateFormat,
125173
locale
126174
};
175+
176+
// Remove empty fields
127177
for (const key in familyMember) {
128178
if (familyMember[key] === '' || familyMember[key] === undefined) {
129179
delete familyMember[key];
130180
}
131181
}
182+
132183
return familyMember;
133184
}
134185
}

src/app/clients/clients-view/family-members-tab/add-family-member/add-family-member.component.html

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
<div class="layout-row-wrap responsive-column align-start-center">
44
<mat-form-field class="flex-50-minus-25px">
55
<mat-label>{{ 'labels.inputs.First Name' | translate }}</mat-label>
6-
<input formControlName="firstName" required matInput />
6+
<input
7+
formControlName="firstName"
8+
required
9+
matInput
10+
aria-label="First Name"
11+
placeholder="First Name"
12+
title="First Name"
13+
/>
714
<mat-error *ngIf="addFamilyMemberForm.controls.firstName.hasError('required')">
815
{{ 'labels.inputs.First Name' | translate }} {{ 'labels.commons.is' | translate }}
916
<strong>{{ 'labels.commons.required' | translate }}</strong>
@@ -12,12 +19,25 @@
1219

1320
<mat-form-field class="flex-50-minus-25px">
1421
<mat-label>{{ 'labels.inputs.Middle Name' | translate }}</mat-label>
15-
<input formControlName="middleName" matInput />
22+
<input
23+
formControlName="middleName"
24+
matInput
25+
aria-label="Middle Name"
26+
placeholder="Middle Name"
27+
title="Middle Name"
28+
/>
1629
</mat-form-field>
1730

1831
<mat-form-field class="flex-50-minus-25px">
1932
<mat-label>{{ 'labels.inputs.Last Name' | translate }}</mat-label>
20-
<input formControlName="lastName" required matInput />
33+
<input
34+
formControlName="lastName"
35+
required
36+
matInput
37+
aria-label="Last Name"
38+
placeholder="Last Name"
39+
title="Last Name"
40+
/>
2141
<mat-error *ngIf="addFamilyMemberForm.controls.lastName.hasError('required')">
2242
{{ 'labels.inputs.Last Name' | translate }} {{ 'labels.commons.is' | translate }}
2343
<strong>{{ 'labels.commons.required' | translate }}</strong>
@@ -26,16 +46,27 @@
2646

2747
<mat-form-field class="flex-50-minus-25px">
2848
<mat-label>{{ 'labels.inputs.Qualification' | translate }}</mat-label>
29-
<input formControlName="qualification" matInput />
49+
<input
50+
formControlName="qualification"
51+
matInput
52+
aria-label="Qualification"
53+
placeholder="Qualification"
54+
title="Qualification"
55+
/>
3056
</mat-form-field>
3157

3258
<mat-form-field class="flex-50-minus-25px">
3359
<mat-label>{{ 'labels.inputs.Age' | translate }}</mat-label>
34-
<input type="number" formControlName="age" required matInput [min]="minAge" />
35-
<mat-error *ngIf="addFamilyMemberForm.controls.age.hasError('required')">
36-
{{ 'labels.inputs.Age' | translate }} {{ 'labels.commons.is' | translate }}
37-
<strong>{{ 'labels.commons.required and cannot be negative' | translate }}</strong>
38-
</mat-error>
60+
<input
61+
type="number"
62+
formControlName="age"
63+
matInput
64+
[min]="minAge"
65+
disabled
66+
aria-label="Age"
67+
placeholder="Age"
68+
title="Age"
69+
/>
3970
</mat-form-field>
4071

4172
<mat-checkbox formControlName="isDependent" labelPosition="before" class="flex-50-minus-25px">
@@ -91,13 +122,17 @@
91122

92123
<mat-form-field class="flex-fill" (click)="dueDatePicker.open()">
93124
<mat-label>{{ 'labels.inputs.Date Of Birth' | translate }}</mat-label>
94-
<input formControlName="dateOfBirth" matInput [max]="maxDate" [matDatepicker]="dueDatePicker" required />
125+
<input
126+
formControlName="dateOfBirth"
127+
matInput
128+
[max]="maxDate"
129+
[matDatepicker]="dueDatePicker"
130+
placeholder="Optional"
131+
aria-label="Date Of Birth"
132+
title="Date Of Birth"
133+
/>
95134
<mat-datepicker-toggle matSuffix [for]="dueDatePicker"></mat-datepicker-toggle>
96135
<mat-datepicker #dueDatePicker></mat-datepicker>
97-
<mat-error *ngIf="addFamilyMemberForm.controls.dateOfBirth.hasError('required')">
98-
{{ 'labels.inputs.Date Of Birth' | translate }} {{ 'labels.commons.is' | translate }}
99-
<strong>{{ 'labels.commons.required' | translate }}</strong>
100-
</mat-error>
101136
</mat-form-field>
102137
</div>
103138

src/app/clients/clients-view/family-members-tab/add-family-member/add-family-member.component.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@
1515
}
1616
}
1717
}
18+
19+
.mat-form-field-hint {
20+
font-size: 75%;
21+
color: rgb(0 0 0 / 60%);
22+
margin-top: 4px;
23+
margin-bottom: 8px;
24+
}

src/app/clients/clients-view/family-members-tab/add-family-member/add-family-member.component.ts

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,32 @@ export class AddFamilyMemberComponent implements OnInit {
5959
ngOnInit() {
6060
this.maxDate = this.settingsService.businessDate;
6161
this.createAddFamilyMemberForm();
62+
this.addFamilyMemberForm.get('dateOfBirth').valueChanges.subscribe((dateOfBirth: any) => {
63+
if (dateOfBirth) {
64+
const age = this.calculateAge(dateOfBirth);
65+
this.addFamilyMemberForm.get('age').setValue(age);
66+
} else {
67+
this.addFamilyMemberForm.get('age').setValue('');
68+
}
69+
});
70+
}
71+
72+
/**
73+
* Calculates age from date of birth
74+
* @param {Date} dateOfBirth Date of Birth
75+
* @returns {number} Age
76+
*/
77+
calculateAge(dateOfBirth: Date): number {
78+
const today = new Date(this.settingsService.businessDate);
79+
const birthDate = new Date(dateOfBirth);
80+
let age = today.getFullYear() - birthDate.getFullYear();
81+
const monthDiff = today.getMonth() - birthDate.getMonth();
82+
83+
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
84+
age--;
85+
}
86+
87+
return age;
6288
}
6389

6490
/**
@@ -77,9 +103,7 @@ export class AddFamilyMemberComponent implements OnInit {
77103
],
78104
qualification: [''],
79105
age: [
80-
'',
81-
Validators.required
82-
],
106+
{ value: '', disabled: true }],
83107
isDependent: [''],
84108
relationshipId: [
85109
'',
@@ -91,29 +115,44 @@ export class AddFamilyMemberComponent implements OnInit {
91115
],
92116
professionId: [''],
93117
maritalStatusId: [''],
94-
dateOfBirth: [
95-
'',
96-
Validators.required
97-
]
118+
dateOfBirth: ['']
98119
});
99120
}
100121

101122
/**
102123
* Submits the form and adds the family member
103124
*/
104125
submit() {
105-
const addFamilyMemberFormData = this.addFamilyMemberForm.value;
126+
// Get form values including disabled controls like age
127+
const formValue = {
128+
...this.addFamilyMemberForm.getRawValue()
129+
};
130+
106131
const locale = this.settingsService.language.code;
107132
const dateFormat = this.settingsService.dateFormat;
108-
const prevDateOfBirth: Date = this.addFamilyMemberForm.value.dateOfBirth;
109-
if (addFamilyMemberFormData.dateOfBirth instanceof Date) {
110-
addFamilyMemberFormData.dateOfBirth = this.dateUtils.formatDate(prevDateOfBirth, dateFormat);
133+
const prevDateOfBirth: Date = formValue.dateOfBirth;
134+
135+
// Calculate age from dateOfBirth if present
136+
if (prevDateOfBirth) {
137+
if (formValue.dateOfBirth instanceof Date) {
138+
formValue.dateOfBirth = this.dateUtils.formatDate(prevDateOfBirth, dateFormat);
139+
}
140+
// Ensure age is calculated even if it wasn't already
141+
if (!formValue.age && prevDateOfBirth) {
142+
formValue.age = this.calculateAge(prevDateOfBirth);
143+
}
144+
} else {
145+
// If no date of birth, remove age and dateOfBirth from submission
146+
delete formValue.age;
147+
delete formValue.dateOfBirth;
111148
}
149+
112150
const data = {
113-
...addFamilyMemberFormData,
151+
...formValue,
114152
dateFormat,
115153
locale
116154
};
155+
117156
this.clientsService.addFamilyMember(this.clientId, data).subscribe((res) => {
118157
this.router.navigate(['../'], { relativeTo: this.route });
119158
});

0 commit comments

Comments
 (0)