Skip to content

Commit db0e8d0

Browse files
committed
add hidden fields facility for booking form
1 parent d1f0dd9 commit db0e8d0

File tree

2 files changed

+106
-97
lines changed
  • packages
    • utils/lib/configuration/booking
    • zambdas/src/patient/paperwork/get-booking-questionnaire

2 files changed

+106
-97
lines changed

packages/utils/lib/configuration/booking/index.ts

Lines changed: 104 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -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

195101
const 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+
246158
const 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
273186
export const BOOKING_CONFIG = mergeAndFreezeConfigObjects(BOOKING_DEFAULTS, BOOKING_OVERRIDES);
274187

275188
export const shouldShowServiceCategorySelectionPage = (params: { serviceMode: string; visitType: string }): boolean => {
@@ -285,3 +198,98 @@ export const ServiceCategoryCodeSchema = z.enum(
285198
);
286199

287200
export 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+
};

packages/zambdas/src/patient/paperwork/get-booking-questionnaire/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
INVALID_INPUT_ERROR,
1414
mapQuestionnaireAndValueSetsToItemsList,
1515
MISSING_REQUEST_BODY,
16+
prepopulateBookingForm,
1617
Secrets,
1718
SecretsKeys,
1819
ServiceCategoryCode,
@@ -87,7 +88,7 @@ const performEffect = async (input: EffectInput, oystehr: Oystehr): Promise<GetQ
8788
const valueSets: ValueSet[] = [];
8889
const allItems = mapQuestionnaireAndValueSetsToItemsList(items, valueSets);
8990

90-
const prepopulatedItem = BOOKING_CONFIG.prepopulateBookingForm({
91+
const prepopulatedItem = prepopulateBookingForm({
9192
questionnaire,
9293
context: {
9394
serviceMode,

0 commit comments

Comments
 (0)