@openmrs/esm-form-engine-lib 2.1.0-pre.1594 → 2.1.0-pre.1604

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-form-engine-lib",
3
- "version": "2.1.0-pre.1594",
3
+ "version": "2.1.0-pre.1604",
4
4
  "description": "React Form Engine for O3",
5
5
  "browser": "dist/openmrs-esm-form-engine-lib.js",
6
6
  "main": "src/index.ts",
@@ -64,30 +64,40 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
64
64
  mode: sessionMode,
65
65
  patient,
66
66
  },
67
- ).then((result) => {
68
- setValue(dependent.id, result);
69
- // validate calculated value
70
- const { errors, warnings } = validateFieldValue(dependent, result, context.formFieldValidators, {
71
- formFields,
72
- values,
73
- expressionContext: { patient, mode: sessionMode },
67
+ )
68
+ .then((result) => {
69
+ setValue(dependent.id, result);
70
+ // validate calculated value
71
+ const { errors, warnings } = validateFieldValue(dependent, result, context.formFieldValidators, {
72
+ formFields,
73
+ values,
74
+ expressionContext: { patient, mode: sessionMode },
75
+ });
76
+ if (!dependent.meta.submission) {
77
+ dependent.meta.submission = {};
78
+ }
79
+ dependent.meta.submission.errors = errors;
80
+ dependent.meta.submission.warnings = warnings;
81
+ if (!errors.length) {
82
+ context.formFieldAdapters[dependent.type].transformFieldValue(dependent, result, context);
83
+ }
84
+ updateFormField(dependent);
85
+ })
86
+ .catch((error) => {
87
+ reportError(error, 'Error evaluating calculate expression');
74
88
  });
75
- if (!dependent.meta.submission) {
76
- dependent.meta.submission = {};
77
- }
78
- dependent.meta.submission.errors = errors;
79
- dependent.meta.submission.warnings = warnings;
80
- if (!errors.length) {
81
- context.formFieldAdapters[dependent.type].transformFieldValue(dependent, result, context);
82
- }
83
- updateFormField(dependent);
84
- }).catch((error) => {
85
- reportError(error, 'Error evaluating calculate expression');
86
- });
87
89
  }
88
90
  // evaluate hide
89
91
  if (dependent.hide) {
90
- evaluateHide({ value: dependent, type: 'field' }, formFields, values, sessionMode, patient, evaluateExpression);
92
+ evaluateHide(
93
+ { value: dependent, type: 'field' },
94
+ formFields,
95
+ values,
96
+ sessionMode,
97
+ patient,
98
+ evaluateExpression,
99
+ updateFormField,
100
+ );
91
101
  }
92
102
  // evaluate disabled
93
103
  if (typeof dependent.disabled === 'object' && dependent.disabled.disableWhenExpression) {
@@ -197,12 +207,8 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
197
207
  sessionMode,
198
208
  patient,
199
209
  evaluateExpression,
210
+ updateFormField,
200
211
  );
201
- if (isTrue(section.isHidden)) {
202
- section.questions.forEach((field) => {
203
- field.isParentHidden = true;
204
- });
205
- }
206
212
  shouldUpdateForm = true;
207
213
  break;
208
214
  }
@@ -214,14 +220,15 @@ function evaluateFieldDependents(field: FormField, values: any, context: FormCon
214
220
  if (field.pageDependents) {
215
221
  field.pageDependents?.forEach((dep) => {
216
222
  const dependent = formJson.pages.find((f) => f.label == dep);
217
- evaluateHide({ value: dependent, type: 'page' }, formFields, values, sessionMode, patient, evaluateExpression);
218
- if (isTrue(dependent.isHidden)) {
219
- dependent.sections.forEach((section) => {
220
- section.questions.forEach((field) => {
221
- field.isParentHidden = true;
222
- });
223
- });
224
- }
223
+ evaluateHide(
224
+ { value: dependent, type: 'page' },
225
+ formFields,
226
+ values,
227
+ sessionMode,
228
+ patient,
229
+ evaluateExpression,
230
+ updateFormField,
231
+ );
225
232
  shouldUpdateForm = true;
226
233
  });
227
234
  }
@@ -46,6 +46,7 @@ export const FormFieldRenderer = ({ fieldId, valueAdapter, repeatOptions }: Form
46
46
  formFieldValidators,
47
47
  addInvalidField,
48
48
  removeInvalidField,
49
+ updateFormField,
49
50
  } = context;
50
51
 
51
52
  const fieldValue = useWatch({ control, name: fieldId, exact: true });
@@ -132,6 +133,18 @@ export const FormFieldRenderer = ({ fieldId, valueAdapter, repeatOptions }: Form
132
133
  }
133
134
  setWarnings(validationWarnings);
134
135
  handleFieldLogic(field, context);
136
+ if (field.meta.groupId) {
137
+ const group = formFields.find((f) => f.id === field.meta.groupId);
138
+ if (group) {
139
+ group.questions = group.questions.map((child) => {
140
+ if (child.id === field.id) {
141
+ return field;
142
+ }
143
+ return child;
144
+ });
145
+ updateFormField(group);
146
+ }
147
+ }
135
148
  };
136
149
 
137
150
  if (!inputComponentWrapper) {
@@ -877,6 +877,49 @@ describe('Form engine component', () => {
877
877
  });
878
878
 
879
879
  describe('Obs group', () => {
880
+ it('should save obs group on form submission', async () => {
881
+ const saveEncounterMock = jest.spyOn(api, 'saveEncounter');
882
+ await act(async () => {
883
+ renderForm(null, obsGroupTestForm);
884
+ });
885
+
886
+ // Fill out the obs group fields
887
+ const dateOfBirth = screen.getByRole('textbox', { name: /date of birth/i });
888
+ const maleRadio = screen.getByRole('radio', { name: /^male$/i });
889
+
890
+ await user.click(dateOfBirth);
891
+ await user.paste('2020-09-09T00:00:00.000Z');
892
+ await user.click(maleRadio);
893
+
894
+ // Submit the form
895
+ await user.click(screen.getByRole('button', { name: /save/i }));
896
+
897
+ // Verify the encounter was saved with the correct structure
898
+ expect(saveEncounterMock).toHaveBeenCalledTimes(1);
899
+
900
+ const [_, encounter] = saveEncounterMock.mock.calls[0];
901
+ expect(encounter.obs.length).toBe(1);
902
+ expect(encounter.obs[0]).toEqual({
903
+ groupMembers: [
904
+ {
905
+ value: '1534AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
906
+ concept: '1587AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
907
+ formFieldNamespace: 'rfe-forms',
908
+ formFieldPath: 'rfe-forms-childSex',
909
+ },
910
+ {
911
+ value: '2020-09-09',
912
+ concept: '164802AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
913
+ formFieldNamespace: 'rfe-forms',
914
+ formFieldPath: 'rfe-forms-birthDate',
915
+ },
916
+ ],
917
+ concept: '1c70c490-cafa-4c95-9fdd-a30b62bb78b8',
918
+ formFieldNamespace: 'rfe-forms',
919
+ formFieldPath: 'rfe-forms-myGroup',
920
+ });
921
+ });
922
+
880
923
  it('should test addition of a repeating group', async () => {
881
924
  await act(async () => {
882
925
  renderForm(null, obsGroupTestForm);
@@ -109,7 +109,15 @@ export const useEvaluateFormFieldExpressions = (
109
109
  useEffect(() => {
110
110
  factoryContext.formJson?.pages?.forEach((page) => {
111
111
  if (page.hide) {
112
- evaluateHide({ value: page, type: 'page' }, formFields, formValues, sessionMode, patient, evaluateExpression);
112
+ evaluateHide(
113
+ { value: page, type: 'page' },
114
+ formFields,
115
+ formValues,
116
+ sessionMode,
117
+ patient,
118
+ evaluateExpression,
119
+ null,
120
+ );
113
121
  } else {
114
122
  page.isHidden = false;
115
123
  }
@@ -122,6 +130,7 @@ export const useEvaluateFormFieldExpressions = (
122
130
  sessionMode,
123
131
  patient,
124
132
  evaluateExpression,
133
+ null,
125
134
  );
126
135
  } else {
127
136
  section.isHidden = false;
@@ -95,6 +95,7 @@ export function evaluateHide(
95
95
  sessionMode: SessionMode,
96
96
  patient: fhir.Patient,
97
97
  expressionRunnerFn,
98
+ updateFormFieldFn: (field: FormField) => void | null,
98
99
  ) {
99
100
  const { value, type } = node;
100
101
  const isHidden = expressionRunnerFn(value['hide']?.hideWhenExpression, node, allFields, allValues, {
@@ -111,15 +112,20 @@ export function evaluateHide(
111
112
  if (type == 'page') {
112
113
  value['sections'].forEach((section) => {
113
114
  section.isParentHidden = isHidden;
114
- cascadeVisibilityToChildFields(isHidden, section, allFields);
115
+ cascadeVisibilityToChildFields(isHidden, section, allFields, updateFormFieldFn);
115
116
  });
116
117
  }
117
118
  if (type == 'section') {
118
- cascadeVisibilityToChildFields(isHidden, value, allFields);
119
+ cascadeVisibilityToChildFields(isHidden, value, allFields, updateFormFieldFn);
119
120
  }
120
121
  }
121
122
 
122
- function cascadeVisibilityToChildFields(visibility: boolean, section: FormSection, allFields: Array<FormField>) {
123
+ function cascadeVisibilityToChildFields(
124
+ visibility: boolean,
125
+ section: FormSection,
126
+ allFields: Array<FormField>,
127
+ updateFormFieldFn: (field: FormField) => void,
128
+ ) {
123
129
  const candidateIds = section.questions.map((q) => q.id);
124
130
  allFields
125
131
  .filter((field) => candidateIds.includes(field.id))
@@ -130,6 +136,7 @@ function cascadeVisibilityToChildFields(visibility: boolean, section: FormSectio
130
136
  member.isParentHidden = visibility;
131
137
  });
132
138
  }
139
+ updateFormFieldFn?.(field);
133
140
  });
134
141
  }
135
142