11import { Component , OnInit , HostListener } from '@angular/core' ;
22import { ActivatedRoute , Router , ParamMap } from '@angular/router' ;
3- import { UntypedFormBuilder , UntypedFormGroup , Validators } from '@angular/forms' ;
3+ import { FormBuilder , FormControl , FormGroup , Validators } from '@angular/forms' ;
44import { HealthService } from './health.service' ;
55import { conditions , conditionAndTreatmentFields } from './health.constants' ;
66import { UserService } from '../shared/user.service' ;
@@ -16,21 +16,47 @@ import { CanComponentDeactivate } from '../shared/unsaved-changes.guard';
1616import { warningMsg } from '../shared/unsaved-changes.component' ;
1717import { debounce } from 'rxjs/operators' ;
1818
19+ interface HealthEventFormModel {
20+ temperature : FormControl < number | null > ;
21+ pulse : FormControl < number | null > ;
22+ bp : FormControl < string | null > ;
23+ height : FormControl < number | null > ;
24+ weight : FormControl < number | null > ;
25+ vision : FormControl < string | null > ;
26+ hearing : FormControl < string | null > ;
27+ notes : FormControl < string | null > ;
28+ diagnosis : FormControl < string | null > ;
29+ treatments : FormControl < string | null > ;
30+ medications : FormControl < string | null > ;
31+ immunizations : FormControl < string | null > ;
32+ allergies : FormControl < string | null > ;
33+ xrays : FormControl < string | null > ;
34+ tests : FormControl < string | null > ;
35+ referrals : FormControl < string | null > ;
36+ conditions : FormControl < Record < string , boolean > > ;
37+ }
38+
39+ type HealthEventFormValue = {
40+ [ Key in keyof HealthEventFormModel ] : HealthEventFormModel [ Key ] extends FormControl < infer Value >
41+ ? Value
42+ : never ;
43+ } ;
44+
1945@Component ( {
2046 templateUrl : './health-event.component.html' ,
2147 styleUrls : [ './health-update.scss' ]
2248} )
2349export class HealthEventComponent implements OnInit , CanComponentDeactivate {
2450
25- healthForm : UntypedFormGroup ;
51+ healthForm : FormGroup < HealthEventFormModel > ;
2652 conditions = conditions ;
2753 dialogPrompt : MatDialogRef < DialogsPromptComponent > ;
2854 event : any = { } ;
2955 initialFormValues : any ;
3056 hasUnsavedChanges = false ;
3157
3258 constructor (
33- private fb : UntypedFormBuilder ,
59+ private fb : FormBuilder ,
3460 private healthService : HealthService ,
3561 private router : Router ,
3662 private route : ActivatedRoute ,
@@ -40,24 +66,24 @@ export class HealthEventComponent implements OnInit, CanComponentDeactivate {
4066 private dialog : MatDialog ,
4167 private planetMessageService : PlanetMessageService
4268 ) {
43- this . healthForm = this . fb . group ( {
44- temperature : [ '' , Validators . min ( 1 ) ] ,
45- pulse : [ '' , Validators . min ( 1 ) ] ,
46- bp : [ '' , CustomValidators . bpValidator ] ,
47- height : [ '' , Validators . min ( 1 ) ] ,
48- weight : [ '' , Validators . min ( 1 ) ] ,
49- vision : [ '' ] ,
50- hearing : [ '' ] ,
51- notes : '' ,
52- diagnosis : '' ,
53- treatments : '' ,
54- medications : '' ,
55- immunizations : '' ,
56- allergies : '' ,
57- xrays : '' ,
58- tests : '' ,
59- referrals : '' ,
60- conditions : { }
69+ this . healthForm = this . fb . group < HealthEventFormModel > ( {
70+ temperature : this . fb . control < number | null > ( null , { validators : Validators . min ( 1 ) } ) ,
71+ pulse : this . fb . control < number | null > ( null , { validators : Validators . min ( 1 ) } ) ,
72+ bp : this . fb . control < string | null > ( '' , { validators : CustomValidators . bpValidator } ) ,
73+ height : this . fb . control < number | null > ( null , { validators : Validators . min ( 1 ) } ) ,
74+ weight : this . fb . control < number | null > ( null , { validators : Validators . min ( 1 ) } ) ,
75+ vision : this . fb . control < string | null > ( '' ) ,
76+ hearing : this . fb . control < string | null > ( '' ) ,
77+ notes : this . fb . control < string | null > ( '' ) ,
78+ diagnosis : this . fb . control < string | null > ( '' ) ,
79+ treatments : this . fb . control < string | null > ( '' ) ,
80+ medications : this . fb . control < string | null > ( '' ) ,
81+ immunizations : this . fb . control < string | null > ( '' ) ,
82+ allergies : this . fb . control < string | null > ( '' ) ,
83+ xrays : this . fb . control < string | null > ( '' ) ,
84+ tests : this . fb . control < string | null > ( '' ) ,
85+ referrals : this . fb . control < string | null > ( '' ) ,
86+ conditions : this . fb . control < Record < string , boolean > > ( { } )
6187 } ) ;
6288 }
6389
@@ -85,25 +111,15 @@ export class HealthEventComponent implements OnInit, CanComponentDeactivate {
85111 }
86112
87113 private captureInitialState ( ) {
88- const formValue = this . healthForm . value ;
89- const numericFields = [ 'temperature' , 'pulse' , 'height' , 'weight' ] ;
90- const processedForm = Object . keys ( formValue ) . reduce ( ( acc , key ) => {
91- if ( numericFields . includes ( key ) ) {
92- acc [ key ] = formValue [ key ] === '' || formValue [ key ] === null ? undefined : Number ( formValue [ key ] ) ;
93- } else if ( key === 'conditions' ) {
94- acc [ key ] = this . processConditions ( formValue [ key ] || { } ) ;
95- } else {
96- acc [ key ] = formValue [ key ] ;
97- }
98- return acc ;
99- } , { } ) ;
114+ const formValue = this . healthForm . getRawValue ( ) ;
115+ const processedForm = this . transformFormValue ( formValue ) ;
100116
101117 this . initialFormValues = JSON . stringify ( processedForm ) ;
102118 }
103119
104- private processConditions ( inputConditions : any ) {
105- const processedConditions = Object . keys ( inputConditions || { } ) . reduce ( ( acc , key ) => {
106- if ( inputConditions [ key ] ) {
120+ private processConditions ( inputConditions : Record < string , boolean > | null | undefined ) : Record < string , boolean > {
121+ const processedConditions = Object . keys ( inputConditions || { } ) . reduce < Record < string , boolean > > ( ( acc , key ) => {
122+ if ( inputConditions && inputConditions [ key ] ) {
107123 acc [ key ] = true ;
108124 }
109125 return acc ;
@@ -116,18 +132,8 @@ export class HealthEventComponent implements OnInit, CanComponentDeactivate {
116132 . pipe (
117133 debounce ( ( ) => race ( interval ( 200 ) , of ( true ) ) )
118134 )
119- . subscribe ( formValue => {
120- const numericFields = [ 'temperature' , 'pulse' , 'height' , 'weight' ] ;
121- const processedForm = Object . keys ( formValue ) . reduce ( ( acc , key ) => {
122- if ( numericFields . includes ( key ) ) {
123- acc [ key ] = formValue [ key ] === '' || formValue [ key ] === null ? undefined : Number ( formValue [ key ] ) ;
124- } else if ( key === 'conditions' ) {
125- acc [ key ] = this . processConditions ( formValue [ key ] || { } ) ;
126- } else {
127- acc [ key ] = formValue [ key ] ;
128- }
129- return acc ;
130- } , { } ) ;
135+ . subscribe ( ( formValue : HealthEventFormValue ) => {
136+ const processedForm = this . transformFormValue ( formValue ) ;
131137
132138 const currentState = JSON . stringify ( processedForm ) ;
133139 this . hasUnsavedChanges = currentState !== this . initialFormValues ;
@@ -138,7 +144,7 @@ export class HealthEventComponent implements OnInit, CanComponentDeactivate {
138144 if ( ! this . healthForm . valid ) {
139145 return ;
140146 }
141- const checkFields = [ 'temperature' , 'pulse' , 'bp' , 'height' , 'weight' ] ;
147+ const checkFields : Array < keyof HealthEventFormModel > = [ 'temperature' , 'pulse' , 'bp' , 'height' , 'weight' ] ;
142148 const promptFields = checkFields . filter ( ( field ) => ! this . isFieldValueExpected ( field ) )
143149 . map ( field => ( { field, value : this . healthForm . controls [ field ] . value } ) ) ;
144150 if ( promptFields . length ) {
@@ -151,20 +157,37 @@ export class HealthEventComponent implements OnInit, CanComponentDeactivate {
151157 }
152158 }
153159
154- isEmptyForm ( ) {
155- const isConditionsEmpty = ( values ) => typeof values === 'object' && Object . values ( values ) . every ( value => ! value ) ;
160+ isEmptyForm ( ) {
161+ const isConditionsEmpty = ( values : Record < string , boolean > ) =>
162+ typeof values === 'object' && Object . values ( values ) . every ( value => ! value ) ;
163+
156164 return Object . values ( this . healthForm . controls )
157- . every ( ( { value } ) => value === null || / ^ \s * $ / . test ( value ) || isConditionsEmpty ( value ) ) ;
165+ . every ( ( control ) => {
166+ const value = control . value ;
167+ if ( value === null || value === undefined ) {
168+ return true ;
169+ }
170+ if ( typeof value === 'string' ) {
171+ return / ^ \s * $ / . test ( value ) ;
172+ }
173+ if ( typeof value === 'number' ) {
174+ return false ;
175+ }
176+ return isConditionsEmpty ( value as Record < string , boolean > ) ;
177+ } ) ;
158178 }
159179
160180 goBack ( ) {
161181 // Let the router guard handle the unsaved changes prompt
162182 this . router . navigate ( [ '..' ] , { relativeTo : this . route } ) ;
163183 }
164184
165- conditionChange ( condition ) {
166- const currentConditions = this . healthForm . controls . conditions . value ;
167- this . healthForm . controls . conditions . setValue ( { ...currentConditions , [ condition ] : currentConditions [ condition ] !== true } ) ;
185+ conditionChange ( condition : string ) {
186+ const currentConditions = this . healthForm . controls . conditions . value || { } ;
187+ this . healthForm . controls . conditions . setValue ( {
188+ ...currentConditions ,
189+ [ condition ] : currentConditions [ condition ] !== true
190+ } ) ;
168191 }
169192
170193 showWarning ( invalidFields ) {
@@ -190,7 +213,7 @@ export class HealthEventComponent implements OnInit, CanComponentDeactivate {
190213 } ) ;
191214 }
192215
193- isFieldValueExpected ( field ) {
216+ isFieldValueExpected ( field : keyof HealthEventFormModel ) {
194217 const value = this . healthForm . controls [ field ] . value ;
195218 const limits = {
196219 'temperature' : { min : 30 , max : 45 } ,
@@ -209,20 +232,42 @@ export class HealthEventComponent implements OnInit, CanComponentDeactivate {
209232 }
210233
211234 saveEvent ( ) {
235+ const formValue = this . healthForm . getRawValue ( ) ;
236+
212237 return this . healthService . addEvent (
213238 this . route . snapshot . params . id ,
214239 this . userService . get ( ) . _id ,
215240 this . event ,
216241 {
217- ...this . healthForm . value ,
242+ ...formValue ,
218243 selfExamination : this . route . snapshot . params . id === this . userService . get ( ) . _id ,
219244 createdBy : this . userService . get ( ) . _id ,
220245 planetCode : this . stateService . configuration . code ,
221- hasInfo : conditionAndTreatmentFields . some ( key => this . healthForm . value [ key ] !== '' )
246+ hasInfo : conditionAndTreatmentFields . some ( key => {
247+ const value = formValue [ key as keyof HealthEventFormValue ] ;
248+ return typeof value === 'string' ? value !== null && value !== '' : value !== null ;
249+ } )
222250 }
223251 ) ;
224252 }
225253
254+ private transformFormValue ( formValue : HealthEventFormValue ) {
255+ const numericFields : Array < keyof Pick < HealthEventFormValue , 'temperature' | 'pulse' | 'height' | 'weight' > > =
256+ [ 'temperature' , 'pulse' , 'height' , 'weight' ] ;
257+
258+ return ( Object . keys ( formValue ) as Array < keyof HealthEventFormValue > ) . reduce ( ( acc , key ) => {
259+ const value = formValue [ key ] ;
260+ if ( numericFields . includes ( key ) ) {
261+ acc [ key ] = value === null ? undefined : Number ( value ) ;
262+ } else if ( key === 'conditions' ) {
263+ acc [ key ] = this . processConditions ( value ) ;
264+ } else {
265+ acc [ key ] = value ;
266+ }
267+ return acc ;
268+ } , { } as Record < keyof HealthEventFormValue , unknown > ) ;
269+ }
270+
226271 canDeactivate ( ) : boolean {
227272 return ! this . hasUnsavedChanges ;
228273 }
0 commit comments