@openmrs/esm-form-engine-lib 2.1.0-pre.1404 → 2.1.0-pre.1412

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.1404",
3
+ "version": "2.1.0-pre.1412",
4
4
  "description": "React Form Engine for O3",
5
5
  "browser": "dist/openmrs-esm-form-engine-lib.js",
6
6
  "main": "src/index.ts",
@@ -8,8 +8,13 @@ import {
8
8
  type Attachment,
9
9
  type ValueAndDisplay,
10
10
  } from '../types';
11
- import { hasRendering, gracefullySetSubmission, clearSubmission, flattenObsList } from '../utils/common-utils';
12
- import { parseToLocalDateTime } from '../utils/form-helper';
11
+ import {
12
+ hasRendering,
13
+ gracefullySetSubmission,
14
+ clearSubmission,
15
+ flattenObsList,
16
+ parseToLocalDateTime,
17
+ } from '../utils/common-utils';
13
18
  import { type FormContextProps } from '../provider/form-provider';
14
19
  import { type FormFieldValueAdapter } from '../types';
15
20
  import { isEmpty } from '../validators/form-validator';
@@ -16,11 +16,10 @@ import { hasRendering } from '../../../utils/common-utils';
16
16
  import { useFormProviderContext } from '../../../provider/form-provider';
17
17
  import { isEmpty } from '../../../validators/form-validator';
18
18
  import PreviousValueReview from '../../previous-value-review/previous-value-review.component';
19
- import { getRegisteredControl } from '../../../registry/registry';
19
+ import { getFieldControlWithFallback, getRegisteredControl } from '../../../registry/registry';
20
20
  import styles from './form-field-renderer.scss';
21
21
  import { isTrue } from '../../../utils/boolean-utils';
22
22
  import UnspecifiedField from '../../inputs/unspecified/unspecified.component';
23
- import { getFieldControlWithFallback } from '../../../utils/form-helper';
24
23
  import { handleFieldLogic } from './fieldLogic';
25
24
 
26
25
  export interface FormFieldRendererProps {
@@ -1,4 +1,5 @@
1
1
  import {
2
+ type FormField,
2
3
  type DataSource,
3
4
  type FormFieldValidator,
4
5
  type FormSchemaTransformer,
@@ -121,7 +122,7 @@ export async function getRegisteredControl(renderType: string) {
121
122
  let component = inbuiltControls.find(
122
123
  (control) => control.name === renderType || control?.alias === renderType,
123
124
  )?.component;
124
- // if undefined, try serching through the registered custom controls
125
+ // if undefined, try searching through the registered custom controls
125
126
  if (!component) {
126
127
  const importedControl = await getFormsStore()
127
128
  .controls.find((control) => control.name === renderType || control?.alias === renderType)
@@ -132,6 +133,26 @@ export async function getRegisteredControl(renderType: string) {
132
133
  return component;
133
134
  }
134
135
 
136
+ /**
137
+ * Retrieves the appropriate field control for a question, considering missing concepts.
138
+ * If the question is of type 'obs' and has a missing concept, it falls back to a disabled text input.
139
+ * Otherwise, it retrieves the registered control based on the rendering specified in the question.
140
+ * @param question - The FormField representing the question.
141
+ * @returns The field control to be used for rendering the question.
142
+ */
143
+ export function getFieldControlWithFallback(question: FormField) {
144
+ // Check if the question has a missing concept
145
+ if (hasMissingConcept(question)) {
146
+ // If so, render a disabled text input
147
+ question.disabled = true;
148
+ question.isDisabled = true;
149
+ return getRegisteredControl('text');
150
+ }
151
+
152
+ // Retrieve the registered control based on the specified rendering
153
+ return getRegisteredControl(question.questionOptions.rendering);
154
+ }
155
+
135
156
  export async function getRegisteredFieldValueAdapter(type: string): Promise<FormFieldValueAdapter> {
136
157
  if (registryCache.fieldValueAdapters[type]) {
137
158
  return registryCache.fieldValueAdapters[type];
@@ -259,3 +280,9 @@ function getFormsStore(): FormsRegistryStoreState {
259
280
  formSchemaTransformers: [],
260
281
  }).getState();
261
282
  }
283
+
284
+ function hasMissingConcept(question: FormField) {
285
+ return (
286
+ question.type == 'obs' && !question.questionOptions.concept && question.questionOptions.rendering !== 'fixed-value'
287
+ );
288
+ }
@@ -110,6 +110,19 @@ export interface PostSubmissionAction {
110
110
  ): void;
111
111
  }
112
112
 
113
+ export interface FormFieldInputProps {
114
+ value: any;
115
+ field: FormField;
116
+ errors: ValidationResult[];
117
+ warnings: ValidationResult[];
118
+ /**
119
+ * Callback function to handle changes to the field value in the React Hook Form context.
120
+ *
121
+ * @param value - The new value of the field.
122
+ */
123
+ setFieldValue: (value: any) => void;
124
+ }
125
+
113
126
  /**
114
127
  * Field validator
115
128
  */
@@ -1,6 +1,5 @@
1
1
  import { type OpenmrsResource } from '@openmrs/esm-framework';
2
2
  import { type OpenmrsEncounter } from './domain';
3
- import { type ValidationResult } from '..';
4
3
 
5
4
  export interface FormSchema {
6
5
  name: string;
@@ -88,19 +87,6 @@ export interface FormField {
88
87
  meta?: QuestionMetaProps;
89
88
  }
90
89
 
91
- export interface FormFieldInputProps {
92
- value: any;
93
- field: FormField;
94
- errors: ValidationResult[];
95
- warnings: ValidationResult[];
96
- /**
97
- * Callback function to handle changes to the field value in the React Hook Form context.
98
- *
99
- * @param value - The new value of the field.
100
- */
101
- setFieldValue: (value: any) => void;
102
- }
103
-
104
90
  export interface HideProps {
105
91
  hideWhenExpression: string;
106
92
  }
@@ -1,4 +1,11 @@
1
- import { flattenObsList, hasRendering, clearSubmission, gracefullySetSubmission, hasSubmission } from './common-utils';
1
+ import {
2
+ flattenObsList,
3
+ hasRendering,
4
+ clearSubmission,
5
+ gracefullySetSubmission,
6
+ hasSubmission,
7
+ parseToLocalDateTime,
8
+ } from './common-utils';
2
9
  import { isEmpty } from '../validators/form-validator';
3
10
  import { type FormField, type OpenmrsObs } from '../types';
4
11
  import { obsList } from '__mocks__/forms/rfe-forms/obs-list-data';
@@ -134,3 +141,32 @@ describe('utils functions', () => {
134
141
  });
135
142
  });
136
143
  });
144
+
145
+ describe('parseToLocalDateTime', () => {
146
+ it('should parse valid date string with time correctly', () => {
147
+ const dateString = '2023-06-27T14:30:00';
148
+ const expectedDate = new Date(2023, 5, 27, 14, 30, 0);
149
+ const parsedDate = parseToLocalDateTime(dateString);
150
+
151
+ expect(parsedDate).toEqual(expectedDate);
152
+ });
153
+
154
+ it('should parse valid date string without time correctly', () => {
155
+ const dateString = '2023-06-27';
156
+ const expectedDate = new Date(2023, 5, 27);
157
+ const parsedDate = parseToLocalDateTime(dateString);
158
+
159
+ // Set hours, minutes, and seconds to 0 since the input doesn't contain time
160
+ expectedDate.setHours(0, 0, 0, 0);
161
+
162
+ expect(parsedDate).toEqual(expectedDate);
163
+ });
164
+
165
+ it('should handle invalid date string format gracefully', () => {
166
+ const dateString = 'invalid-date-string';
167
+ const parsedDate = parseToLocalDateTime(dateString);
168
+
169
+ // Check if the parsedDate is an Invalid Date
170
+ expect(isNaN(parsedDate.getTime())).toBe(true);
171
+ });
172
+ });
@@ -1,3 +1,4 @@
1
+ import dayjs from 'dayjs';
1
2
  import { type FormField, type OpenmrsObs, type RenderType } from '../types';
2
3
  import { isEmpty } from '../validators/form-validator';
3
4
 
@@ -53,3 +54,14 @@ export function hasSubmission(field: FormField) {
53
54
  export function isViewMode(sessionMode: string) {
54
55
  return sessionMode === 'view' || sessionMode === 'embedded-view';
55
56
  }
57
+
58
+ export function parseToLocalDateTime(dateString: string): Date {
59
+ const dateObj = dayjs(dateString).toDate();
60
+ try {
61
+ const localTimeTokens = dateString.split('T')[1].split(':');
62
+ dateObj.setHours(parseInt(localTimeTokens[0]), parseInt(localTimeTokens[1]), 0);
63
+ } catch (e) {
64
+ console.error(e);
65
+ }
66
+ return dateObj;
67
+ }
@@ -2,7 +2,6 @@ import {
2
2
  findConceptByReference,
3
3
  evaluateConditionalAnswered,
4
4
  evaluateFieldReadonlyProp,
5
- parseToLocalDateTime,
6
5
  evaluateDisabled,
7
6
  } from './form-helper';
8
7
  import { DefaultValueValidator } from '../validators/default-value-validator';
@@ -384,35 +383,6 @@ describe('Form Engine Helper', () => {
384
383
  });
385
384
  });
386
385
 
387
- describe('parseToLocalDateTime', () => {
388
- it('should parse valid date string with time correctly', () => {
389
- const dateString = '2023-06-27T14:30:00';
390
- const expectedDate = new Date(2023, 5, 27, 14, 30, 0);
391
- const parsedDate = parseToLocalDateTime(dateString);
392
-
393
- expect(parsedDate).toEqual(expectedDate);
394
- });
395
-
396
- it('should parse valid date string without time correctly', () => {
397
- const dateString = '2023-06-27';
398
- const expectedDate = new Date(2023, 5, 27);
399
- const parsedDate = parseToLocalDateTime(dateString);
400
-
401
- // Set hours, minutes, and seconds to 0 since the input doesn't contain time
402
- expectedDate.setHours(0, 0, 0, 0);
403
-
404
- expect(parsedDate).toEqual(expectedDate);
405
- });
406
-
407
- it('should handle invalid date string format gracefully', () => {
408
- const dateString = 'invalid-date-string';
409
- const parsedDate = parseToLocalDateTime(dateString);
410
-
411
- // Check if the parsedDate is an Invalid Date
412
- expect(isNaN(parsedDate.getTime())).toBe(true);
413
- });
414
- });
415
-
416
386
  describe('evaluateDisabled', () => {
417
387
  let mockExpressionRunnerFn;
418
388
  let node;
@@ -1,4 +1,3 @@
1
- import dayjs from 'dayjs';
2
1
  import { type LayoutType } from '@openmrs/esm-framework';
3
2
  import { type FormField, type FormPage, type FormSection, type SessionMode } from '../types';
4
3
  import { isEmpty } from '../validators/form-validator';
@@ -58,17 +57,6 @@ export function findPagesWithErrors(pages: Set<FormPage>, errorFields: FormField
58
57
  return pagesWithErrors;
59
58
  }
60
59
 
61
- export function parseToLocalDateTime(dateString: string): Date {
62
- const dateObj = dayjs(dateString).toDate();
63
- try {
64
- const localTimeTokens = dateString.split('T')[1].split(':');
65
- dateObj.setHours(parseInt(localTimeTokens[0]), parseInt(localTimeTokens[1]), 0);
66
- } catch (e) {
67
- console.error(e);
68
- }
69
- return dateObj;
70
- }
71
-
72
60
  export function evalConditionalRequired(field: FormField, allFields: FormField[], formValues: Record<string, any>) {
73
61
  if (typeof field.required !== 'object') {
74
62
  return false;
@@ -170,32 +158,6 @@ export function findConceptByReference(reference: string, concepts) {
170
158
  }
171
159
  }
172
160
 
173
- /**
174
- * Retrieves the appropriate field control for a question, considering missing concepts.
175
- * If the question is of type 'obs' and has a missing concept, it falls back to a disabled text input.
176
- * Otherwise, it retrieves the registered control based on the rendering specified in the question.
177
- * @param question - The FormField representing the question.
178
- * @returns The field control to be used for rendering the question.
179
- */
180
- export function getFieldControlWithFallback(question: FormField) {
181
- // Check if the question has a missing concept
182
- if (hasMissingConcept(question)) {
183
- // If so, render a disabled text input
184
- question.disabled = true;
185
- question.isDisabled = true;
186
- return getRegisteredControl('text');
187
- }
188
-
189
- // Retrieve the registered control based on the specified rendering
190
- return getRegisteredControl(question.questionOptions.rendering);
191
- }
192
-
193
- export function hasMissingConcept(question: FormField) {
194
- return (
195
- question.type == 'obs' && !question.questionOptions.concept && question.questionOptions.rendering !== 'fixed-value'
196
- );
197
- }
198
-
199
161
  export function scrollIntoView(viewId: string, shouldFocus: boolean = false) {
200
162
  const currentElement = document.getElementById(viewId);
201
163
  currentElement?.scrollIntoView({