@@ -32,8 +32,14 @@ import {
3232 MapPin ,
3333 Phone ,
3434 FileText ,
35- Calendar
35+ Calendar ,
36+ HeartPulse ,
37+ Droplets ,
38+ AlertTriangle ,
39+ ClipboardList ,
40+ Pill
3641} from 'lucide-react'
42+ import { TagsInput } from '../ui/tags-input'
3743
3844export interface CreatePatientFormProps {
3945 onRecordUpdated ?: ( patient : Patient ) => void
@@ -77,6 +83,17 @@ const birthYearFromAge = (birth_year: number) => {
7783 return currentYear - birth_year
7884}
7985
86+ const BLOOD_GROUPS = [ 'A+' , 'A-' , 'B+' , 'B-' , 'AB+' , 'AB-' , 'O+' , 'O-' ] as const
87+
88+ // Helper functions to convert between arrays and comma-separated strings
89+ const tagsToString = ( tags : string [ ] ) : string | null => {
90+ return tags . length > 0 ? tags . join ( ',' ) : null
91+ }
92+
93+ const stringToTags = ( str : string | null ) : string [ ] => {
94+ return str ? str . split ( ',' ) . filter ( ( tag ) => tag . trim ( ) ) : [ ]
95+ }
96+
8097const patientSchema = z . object ( {
8198 phn : z . string ( ) . min ( 1 , {
8299 message : 'PHN is required'
@@ -94,7 +111,12 @@ const patientSchema = z.object({
94111 . regex ( AGE_PATTERN , 'Age must be in the format(year, year month or month) ie: 20y, 10y 6m, 5m' ) ,
95112 gender : z . enum ( [ 'M' , 'F' ] , {
96113 message : 'Select Gender'
97- } )
114+ } ) ,
115+ // Medical history fields
116+ blood_group : z . enum ( BLOOD_GROUPS ) . optional ( ) . nullable ( ) ,
117+ allergies : z . array ( z . string ( ) ) . optional ( ) . default ( [ ] ) ,
118+ conditions : z . array ( z . string ( ) ) . optional ( ) . default ( [ ] ) ,
119+ medications : z . array ( z . string ( ) ) . optional ( ) . default ( [ ] )
98120} )
99121
100122type FormSchema = z . infer < typeof patientSchema >
@@ -117,7 +139,12 @@ export const NewPatientForm = forwardRef<NewPatientFormRef, CreatePatientFormPro
117139 emergency_contact : values ?. emergency_contact || '' ,
118140 emergency_phone : values ?. emergency_phone || '' ,
119141 gender : values ?. gender || ( '' as any ) ,
120- age : values && values . birth_year ? `${ birthYearFromAge ( values . birth_year ) } y` : ''
142+ age : values && values . birth_year ? `${ birthYearFromAge ( values . birth_year ) } y` : '' ,
143+ // Medical history fields
144+ blood_group : values ?. blood_group as typeof BLOOD_GROUPS [ number ] | null || null ,
145+ allergies : stringToTags ( values ?. allergies || null ) ,
146+ conditions : stringToTags ( values ?. conditions || null ) ,
147+ medications : stringToTags ( values ?. medications || null )
121148 }
122149 } )
123150 const isUpdate = values && ! ! values . id
@@ -130,7 +157,11 @@ export const NewPatientForm = forwardRef<NewPatientFormRef, CreatePatientFormPro
130157 if ( isUpdate ) {
131158 form . reset ( {
132159 ...values ,
133- age : values && values . birth_year ? `${ birthYearFromAge ( values . birth_year ) } y` : ''
160+ age : values && values . birth_year ? `${ birthYearFromAge ( values . birth_year ) } y` : '' ,
161+ blood_group : values ?. blood_group as typeof BLOOD_GROUPS [ number ] | null || null ,
162+ allergies : stringToTags ( values ?. allergies || null ) ,
163+ conditions : stringToTags ( values ?. conditions || null ) ,
164+ medications : stringToTags ( values ?. medications || null )
134165 } )
135166
136167 return
@@ -145,8 +176,11 @@ export const NewPatientForm = forwardRef<NewPatientFormRef, CreatePatientFormPro
145176 emergency_contact : '' ,
146177 emergency_phone : '' ,
147178 remarks : '' ,
148-
149- gender : '' as any
179+ gender : '' as any ,
180+ blood_group : null ,
181+ allergies : [ ] ,
182+ conditions : [ ] ,
183+ medications : [ ]
150184 } )
151185 } , [ form , isUpdate , values ] )
152186
@@ -163,7 +197,11 @@ export const NewPatientForm = forwardRef<NewPatientFormRef, CreatePatientFormPro
163197 phone : data . phone ,
164198 emergency_contact : data . emergency_contact ,
165199 emergency_phone : data . emergency_phone ,
166- remarks : data . remarks
200+ remarks : data . remarks ,
201+ blood_group : data . blood_group || null ,
202+ allergies : tagsToString ( data . allergies || [ ] ) ,
203+ conditions : tagsToString ( data . conditions || [ ] ) ,
204+ medications : tagsToString ( data . medications || [ ] )
167205 } )
168206
169207 if ( error ) {
@@ -199,7 +237,11 @@ export const NewPatientForm = forwardRef<NewPatientFormRef, CreatePatientFormPro
199237 phone : data . phone ,
200238 emergency_contact : data . emergency_contact ,
201239 emergency_phone : data . emergency_phone ,
202- remarks : data . remarks
240+ remarks : data . remarks ,
241+ blood_group : data . blood_group || null ,
242+ allergies : tagsToString ( data . allergies || [ ] ) ,
243+ conditions : tagsToString ( data . conditions || [ ] ) ,
244+ medications : tagsToString ( data . medications || [ ] )
203245 } )
204246
205247 if ( error ) {
@@ -505,10 +547,134 @@ export const NewPatientForm = forwardRef<NewPatientFormRef, CreatePatientFormPro
505547 </ CardContent >
506548 </ Card >
507549
508- { /* Row 4: Notes */ }
550+ { /* Row 4: Medical History */ }
509551 < Card
510552 className = "bg-gradient-to-br from-card to-card/80 animate-fade-in-up"
511553 style = { { animationDelay : '300ms' } }
554+ >
555+ < CardHeader className = "pb-3 pt-4" >
556+ < div className = "flex items-center gap-2.5" >
557+ < div className = "h-8 w-8 rounded-lg bg-rose-500/10 flex items-center justify-center" >
558+ < HeartPulse className = "h-4 w-4 text-rose-500" />
559+ </ div >
560+ < CardTitle className = "text-xs font-medium uppercase tracking-wider text-muted-foreground" >
561+ Medical History
562+ </ CardTitle >
563+ </ div >
564+ </ CardHeader >
565+ < CardContent className = "pt-0 space-y-4" >
566+ { /* Blood Group Field */ }
567+ < FormField
568+ control = { form . control }
569+ name = "blood_group"
570+ render = { ( { field } ) => (
571+ < FormItem >
572+ < div className = "flex items-center gap-2 mb-1.5" >
573+ < div className = "h-6 w-6 rounded-md bg-red-500/10 flex items-center justify-center" >
574+ < Droplets className = "h-3.5 w-3.5 text-red-500" />
575+ </ div >
576+ < FormLabel className = "text-sm font-medium" > Blood Group</ FormLabel >
577+ </ div >
578+ < Select onValueChange = { field . onChange } value = { field . value || '' } >
579+ < FormControl >
580+ < SelectTrigger >
581+ < SelectValue placeholder = "Select blood group..." />
582+ </ SelectTrigger >
583+ </ FormControl >
584+ < SelectContent >
585+ { BLOOD_GROUPS . map ( ( group ) => (
586+ < SelectItem key = { group } value = { group } >
587+ { group }
588+ </ SelectItem >
589+ ) ) }
590+ </ SelectContent >
591+ </ Select >
592+ < FormMessage />
593+ </ FormItem >
594+ ) }
595+ />
596+
597+ { /* Allergies Field */ }
598+ < FormField
599+ control = { form . control }
600+ name = "allergies"
601+ render = { ( { field } ) => (
602+ < FormItem >
603+ < div className = "flex items-center gap-2 mb-1.5" >
604+ < div className = "h-6 w-6 rounded-md bg-amber-500/10 flex items-center justify-center" >
605+ < AlertTriangle className = "h-3.5 w-3.5 text-amber-500" />
606+ </ div >
607+ < FormLabel className = "text-sm font-medium" > Known Allergies</ FormLabel >
608+ </ div >
609+ < FormControl >
610+ < TagsInput
611+ value = { field . value || [ ] }
612+ onChange = { field . onChange }
613+ placeholder = "Add allergy..."
614+ />
615+ </ FormControl >
616+ < FormDescription className = "text-xs" >
617+ Drug allergies, food allergies, environmental triggers
618+ </ FormDescription >
619+ < FormMessage />
620+ </ FormItem >
621+ ) }
622+ />
623+
624+ { /* Pre-existing Conditions Field */ }
625+ < FormField
626+ control = { form . control }
627+ name = "conditions"
628+ render = { ( { field } ) => (
629+ < FormItem >
630+ < div className = "flex items-center gap-2 mb-1.5" >
631+ < div className = "h-6 w-6 rounded-md bg-violet-500/10 flex items-center justify-center" >
632+ < ClipboardList className = "h-3.5 w-3.5 text-violet-500" />
633+ </ div >
634+ < FormLabel className = "text-sm font-medium" > Pre-existing Conditions</ FormLabel >
635+ </ div >
636+ < FormControl >
637+ < TagsInput
638+ value = { field . value || [ ] }
639+ onChange = { field . onChange }
640+ placeholder = "Add condition..."
641+ />
642+ </ FormControl >
643+ < FormMessage />
644+ </ FormItem >
645+ ) }
646+ />
647+
648+ { /* Current Medications Field */ }
649+ < FormField
650+ control = { form . control }
651+ name = "medications"
652+ render = { ( { field } ) => (
653+ < FormItem >
654+ < div className = "flex items-center gap-2 mb-1.5" >
655+ < div className = "h-6 w-6 rounded-md bg-emerald-500/10 flex items-center justify-center" >
656+ < Pill className = "h-3.5 w-3.5 text-emerald-500" />
657+ </ div >
658+ < FormLabel className = "text-sm font-medium" > Current Medications</ FormLabel >
659+ </ div >
660+ < FormControl >
661+ < TagsInput
662+ value = { field . value || [ ] }
663+ onChange = { field . onChange }
664+ placeholder = "Add medication..."
665+ />
666+ </ FormControl >
667+ < FormMessage />
668+ </ FormItem >
669+ ) }
670+ />
671+ </ CardContent >
672+ </ Card >
673+
674+ { /* Row 5: Notes */ }
675+ < Card
676+ className = "bg-gradient-to-br from-card to-card/80 animate-fade-in-up"
677+ style = { { animationDelay : '375ms' } }
512678 >
513679 < CardHeader className = "pb-3 pt-4" >
514680 < div className = "flex items-center gap-2.5" >
0 commit comments