@@ -54,7 +54,7 @@ const bookAppointmentQuestionnaire: {
5454 version : string | undefined ;
5555 templateQuestionnaire : Questionnaire | undefined ;
5656} = ( ( ) => {
57- const templateResource = Object . values ( bookAppointmentQuestionnaireJson . fhirResources ) [ 0 ] ?. resource ;
57+ const templateResource = _ . cloneDeep ( BookingQuestionnaire ) ;
5858 return {
5959 url : templateResource ?. url ,
6060 version : templateResource ?. version ,
@@ -97,100 +97,6 @@ interface BookingFormPrePopulationInput {
9797 context : BookingContext ;
9898 patient ?: Patient ;
9999}
100- const prepopulateBookingForm = ( input : BookingFormPrePopulationInput ) : QuestionnaireResponseItem [ ] => {
101- const {
102- patient,
103- questionnaire,
104- context : { serviceMode, serviceCategoryCode } ,
105- } = input ;
106- console . log (
107- 'making prepopulated items for booking form with serviceMode, serviceCategoryCode' ,
108- serviceMode ,
109- serviceCategoryCode
110- ) ;
111-
112- let patientSex : string | undefined ;
113- if ( patient ?. gender === 'male' ) {
114- patientSex = 'Male' ;
115- } else if ( patient ?. gender === 'female' ) {
116- patientSex = 'Female' ;
117- } else if ( patient ?. gender !== undefined ) {
118- patientSex = 'Intersex' ;
119- }
120- const patientPreferredName = patient ?. name ?. find ( ( name ) => name . use === 'nickname' ) ?. given ?. [ 0 ] ;
121- const patientEmail = patient ?. telecom ?. find ( ( c ) => c . system === 'email' && c . period ?. end === undefined ) ?. value ;
122-
123- const authorizedNLG = patient ?. extension ?. find (
124- ( e ) => e . url === FHIR_EXTENSION . Patient . authorizedNonLegalGuardians . url
125- ) ?. valueString ;
126-
127- const ssn = patient ?. identifier ?. find (
128- ( id ) =>
129- id . type ?. coding ?. some ( ( c ) => c . system === 'http://terminology.hl7.org/CodeSystem/v2-0203' && c . code === 'SS' ) &&
130- id . period ?. end === undefined
131- ) ?. value ;
132-
133- // assuming here we never need to collect this when we already have it
134- const shouldShownSSNField = ! ssn ;
135- const ssnRequired = serviceCategoryCode === 'workmans_comp' && shouldShownSSNField ;
136-
137- const item : QuestionnaireResponseItem [ ] = ( questionnaire . item ?? [ ] ) . map ( ( item ) => {
138- const populatedItem : QuestionnaireResponseItem [ ] = ( ( ) => {
139- const itemItems = ( item . item ?? [ ] )
140- . filter ( ( i : QuestionnaireItem ) => i . type !== 'display' )
141- . map ( ( subItem ) => {
142- const { linkId } = subItem ;
143- let answer : QuestionnaireResponseItemAnswer [ ] | undefined ;
144- if ( linkId === 'existing-patient-id' && patient ?. id ) {
145- answer = makeAnswer ( patient . id ) ;
146- }
147- if ( linkId === 'should-display-ssn-field' ) {
148- answer = makeAnswer ( shouldShownSSNField , 'Boolean' ) ;
149- }
150- if ( linkId === 'ssn-field-required' ) {
151- answer = makeAnswer ( ssnRequired , 'Boolean' ) ;
152- }
153- if ( linkId === 'patient-first-name' && patient ) {
154- answer = makeAnswer ( getFirstName ( patient ) ?? '' ) ;
155- }
156- if ( linkId === 'patient-last-name' && patient ) {
157- answer = makeAnswer ( getLastName ( patient ) ?? '' ) ;
158- }
159-
160- if ( linkId === 'patient-middle-name' && patient ) {
161- answer = makeAnswer ( getMiddleName ( patient ) ?? '' ) ;
162- }
163- if ( linkId === 'patient-preferred-name' && patientPreferredName ) {
164- answer = makeAnswer ( patientPreferredName ) ;
165- }
166- if ( linkId === 'patient-birthdate' && patient ?. birthDate ) {
167- answer = makeAnswer ( patient . birthDate ) ;
168- }
169- if ( linkId === 'patient-birth-sex' && patientSex ) {
170- answer = makeAnswer ( patientSex ) ;
171- }
172- if ( linkId === 'patient-email' && patientEmail ) {
173- answer = makeAnswer ( patientEmail ) ;
174- }
175- if ( linkId === 'authorized-non-legal-guardian' && authorizedNLG ) {
176- answer = makeAnswer ( authorizedNLG ) ;
177- }
178-
179- return {
180- linkId,
181- answer,
182- } ;
183- } ) ;
184- return itemItems ;
185- } ) ( ) ;
186- return {
187- linkId : item . linkId ,
188- item : populatedItem ,
189- } ;
190- } ) ;
191-
192- return item ;
193- } ;
194100
195101const mapBookingQRItemToPatientInfo = ( qrItem : QuestionnaireResponseItem [ ] ) : PatientInfo => {
196102 const items = flattenQuestionnaireAnswers ( qrItem ) ;
@@ -243,13 +149,20 @@ const mapBookingQRItemToPatientInfo = (qrItem: QuestionnaireResponseItem[]): Pat
243149 return patientInfo ;
244150} ;
245151
152+ type BookingQuestionnaireLinkId = NonNullable <
153+ NonNullable < typeof BookingQuestionnaire . item > [ number ] [ 'item' ]
154+ > [ number ] [ 'linkId' ] ;
155+
156+ const hiddenBookingFields : BookingQuestionnaireLinkId [ ] = [ ] ;
157+
246158const BOOKING_DEFAULTS = {
247159 reasonForVisitOptions : REASON_FOR_VISIT_OPTIONS ,
248160 cancelReasonOptions : CANCEL_REASON_OPTIONS ,
249161 serviceCategoriesEnabled : {
250162 serviceModes : [ 'in-person' , 'virtual' ] ,
251163 visitType : [ 'prebook' ] ,
252164 } ,
165+ hiddenBookingFields,
253166 serviceCategories : SERVICE_CATEGORIES_AVAILABLE ,
254167 intakeQuestionnaires,
255168 selectBookingQuestionnaire : (
@@ -266,10 +179,10 @@ const BOOKING_DEFAULTS = {
266179 }
267180 throw new Error ( 'No booking questionnaire configured' ) ;
268181 } ,
269- prepopulateBookingForm,
270182 mapBookingQRItemToPatientInfo,
271183} ;
272184
185+ // todo: it would be nice to use zod to validate the merged booking config shape here
273186export const BOOKING_CONFIG = mergeAndFreezeConfigObjects ( BOOKING_DEFAULTS , BOOKING_OVERRIDES ) ;
274187
275188export const shouldShowServiceCategorySelectionPage = ( params : { serviceMode : string ; visitType : string } ) : boolean => {
@@ -285,3 +198,98 @@ export const ServiceCategoryCodeSchema = z.enum(
285198) ;
286199
287200export type ServiceCategoryCode = z . infer < typeof ServiceCategoryCodeSchema > ;
201+
202+ export const prepopulateBookingForm = ( input : BookingFormPrePopulationInput ) : QuestionnaireResponseItem [ ] => {
203+ const {
204+ patient,
205+ questionnaire,
206+ context : { serviceMode, serviceCategoryCode } ,
207+ } = input ;
208+ console . log (
209+ 'making prepopulated items for booking form with serviceMode, serviceCategoryCode' ,
210+ serviceMode ,
211+ serviceCategoryCode
212+ ) ;
213+
214+ let patientSex : string | undefined ;
215+ if ( patient ?. gender === 'male' ) {
216+ patientSex = 'Male' ;
217+ } else if ( patient ?. gender === 'female' ) {
218+ patientSex = 'Female' ;
219+ } else if ( patient ?. gender !== undefined ) {
220+ patientSex = 'Intersex' ;
221+ }
222+ const patientPreferredName = patient ?. name ?. find ( ( name ) => name . use === 'nickname' ) ?. given ?. [ 0 ] ;
223+ const patientEmail = patient ?. telecom ?. find ( ( c ) => c . system === 'email' && c . period ?. end === undefined ) ?. value ;
224+
225+ const authorizedNLG = patient ?. extension ?. find (
226+ ( e ) => e . url === FHIR_EXTENSION . Patient . authorizedNonLegalGuardians . url
227+ ) ?. valueString ;
228+
229+ const ssn = patient ?. identifier ?. find (
230+ ( id ) =>
231+ id . type ?. coding ?. some ( ( c ) => c . system === 'http://terminology.hl7.org/CodeSystem/v2-0203' && c . code === 'SS' ) &&
232+ id . period ?. end === undefined
233+ ) ?. value ;
234+
235+ // assuming here we never need to collect this when we already have it
236+ const shouldShownSSNField = ! ssn && ! BOOKING_CONFIG . hiddenBookingFields . includes ( 'patient-ssn' ) ;
237+ const ssnRequired = serviceCategoryCode === 'workmans_comp' && shouldShownSSNField ;
238+
239+ const item : QuestionnaireResponseItem [ ] = ( questionnaire . item ?? [ ] ) . map ( ( item ) => {
240+ const populatedItem : QuestionnaireResponseItem [ ] = ( ( ) => {
241+ const itemItems = ( item . item ?? [ ] )
242+ . filter ( ( i : QuestionnaireItem ) => i . type !== 'display' )
243+ . map ( ( subItem ) => {
244+ const { linkId } = subItem ;
245+ let answer : QuestionnaireResponseItemAnswer [ ] | undefined ;
246+ if ( linkId === 'existing-patient-id' && patient ?. id ) {
247+ answer = makeAnswer ( patient . id ) ;
248+ }
249+ if ( linkId === 'should-display-ssn-field' ) {
250+ answer = makeAnswer ( shouldShownSSNField , 'Boolean' ) ;
251+ }
252+ if ( linkId === 'ssn-field-required' ) {
253+ answer = makeAnswer ( ssnRequired , 'Boolean' ) ;
254+ }
255+ if ( linkId === 'patient-first-name' && patient ) {
256+ answer = makeAnswer ( getFirstName ( patient ) ?? '' ) ;
257+ }
258+ if ( linkId === 'patient-last-name' && patient ) {
259+ answer = makeAnswer ( getLastName ( patient ) ?? '' ) ;
260+ }
261+
262+ if ( linkId === 'patient-middle-name' && patient ) {
263+ answer = makeAnswer ( getMiddleName ( patient ) ?? '' ) ;
264+ }
265+ if ( linkId === 'patient-preferred-name' && patientPreferredName ) {
266+ answer = makeAnswer ( patientPreferredName ) ;
267+ }
268+ if ( linkId === 'patient-birthdate' && patient ?. birthDate ) {
269+ answer = makeAnswer ( patient . birthDate ) ;
270+ }
271+ if ( linkId === 'patient-birth-sex' && patientSex ) {
272+ answer = makeAnswer ( patientSex ) ;
273+ }
274+ if ( linkId === 'patient-email' && patientEmail ) {
275+ answer = makeAnswer ( patientEmail ) ;
276+ }
277+ if ( linkId === 'authorized-non-legal-guardian' && authorizedNLG ) {
278+ answer = makeAnswer ( authorizedNLG ) ;
279+ }
280+
281+ return {
282+ linkId,
283+ answer,
284+ } ;
285+ } ) ;
286+ return itemItems ;
287+ } ) ( ) ;
288+ return {
289+ linkId : item . linkId ,
290+ item : populatedItem ,
291+ } ;
292+ } ) ;
293+
294+ return item ;
295+ } ;
0 commit comments