@openmrs/esm-form-engine-lib 2.1.0-pre.1398 → 2.1.0-pre.1402

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.1398",
3
+ "version": "2.1.0-pre.1402",
4
4
  "description": "React Form Engine for O3",
5
5
  "browser": "dist/openmrs-esm-form-engine-lib.js",
6
6
  "main": "src/index.ts",
@@ -6,29 +6,43 @@ import { isTrue } from '../../../utils/boolean-utils';
6
6
  import { type FormFieldInputProps } from '../../../types';
7
7
  import FieldValueView from '../../value/view/field-value-view.component';
8
8
  import FieldLabel from '../../field-label/field-label.component';
9
-
10
- import styles from './dropdown.scss';
11
9
  import { useFormProviderContext } from '../../../provider/form-provider';
10
+ import { NullSelectOption } from '../../../constants';
11
+ import { isEmpty } from '../../../validators/form-validator';
12
+ import styles from './dropdown.scss';
12
13
 
13
14
  const Dropdown: React.FC<FormFieldInputProps> = ({ field, value, errors, warnings, setFieldValue }) => {
14
15
  const { t } = useTranslation();
15
16
  const { layoutType, sessionMode, workspaceLayout, formFieldAdapters } = useFormProviderContext();
16
17
 
17
18
  const handleChange = useCallback(
18
- (value) => {
19
- setFieldValue(value);
19
+ ({ selectedItem }) => {
20
+ setFieldValue(selectedItem === NullSelectOption ? null : selectedItem);
20
21
  },
21
22
  [setFieldValue],
22
23
  );
23
24
 
24
25
  const itemToString = useCallback(
25
26
  (item) => {
26
- const answer = field.questionOptions.answers.find((opt) => (opt.value ? opt.value == item : opt.concept == item));
27
+ let answer = field.questionOptions.answers.find((opt) => {
28
+ return opt.value ? opt.value == item : opt.concept == item;
29
+ });
27
30
  return answer?.label;
28
31
  },
29
32
  [field.questionOptions.answers],
30
33
  );
31
34
 
35
+ const items = useMemo(() => {
36
+ const options = field.questionOptions.answers;
37
+ if (!options.some((option) => option.value === NullSelectOption)) {
38
+ options.unshift({
39
+ value: NullSelectOption,
40
+ label: t('chooseAnOption', 'Choose an option'),
41
+ });
42
+ }
43
+ return options.filter((option) => !option.isHidden).map((item) => item.value || item.concept);
44
+ }, [field.questionOptions.answers]);
45
+
32
46
  const isInline = useMemo(() => {
33
47
  if (['view', 'embedded-view'].includes(sessionMode) || isTrue(field.readonly)) {
34
48
  return shouldUseInlineLayout(field.inlineRendering, layoutType, workspaceLayout, sessionMode);
@@ -50,13 +64,10 @@ const Dropdown: React.FC<FormFieldInputProps> = ({ field, value, errors, warning
50
64
  <DropdownInput
51
65
  id={field.id}
52
66
  titleText={<FieldLabel field={field} />}
53
- label={t('chooseAnOption', 'Choose an option')}
54
- items={field.questionOptions.answers
55
- .filter((answer) => !answer.isHidden)
56
- .map((item) => item.value || item.concept)}
67
+ items={items}
57
68
  itemToString={itemToString}
58
- selectedItem={value}
59
- onChange={({ selectedItem }) => handleChange(selectedItem)}
69
+ selectedItem={isEmpty(value) ? NullSelectOption : value}
70
+ onChange={handleChange}
60
71
  disabled={field.isDisabled}
61
72
  readOnly={field.readonly}
62
73
  invalid={errors.length > 0}
@@ -117,4 +117,41 @@ describe.skip('dropdown input field', () => {
117
117
  });
118
118
  });
119
119
  });
120
- });
120
+
121
+ it('should clear selection when empty option is selected', async () => {
122
+ // setup
123
+ question.meta.previousValue = {
124
+ uuid: '305ed1fc-c1fd-11eb-8529-0242ac130003',
125
+ person: '833db896-c1f0-11eb-8529-0242ac130003',
126
+ obsDatetime: encounterContext.encounterDate,
127
+ concept: '1c43b05b-b6d8-4eb5-8f37-0b14f5347568',
128
+ location: { uuid: '41e6e516-c1f0-11eb-8529-0242ac130003' },
129
+ order: null,
130
+ groupMembers: [],
131
+ voided: false,
132
+ value: '6ddd933a-e65c-4f35-8884-c555b50c55e1',
133
+ };
134
+ await renderForm({ 'patient-past-program': question.meta.previousValue.value });
135
+ const dropdownWidget = screen.getByRole('combobox', { name: /Patient past program./ });
136
+
137
+ // select an option first
138
+ fireEvent.click(dropdownWidget);
139
+ const oncologyScreeningOption = screen.getByText('Oncology Screening and Diagnosis Program');
140
+ fireEvent.click(oncologyScreeningOption);
141
+
142
+ // clear the selection
143
+ fireEvent.click(dropdownWidget);
144
+ const clearOption = screen.getByText('Select an option');
145
+ fireEvent.click(clearOption);
146
+
147
+ // verify
148
+ await act(async () => {
149
+ expect(question.meta.submission.newValue).toEqual({
150
+ uuid: '305ed1fc-c1fd-11eb-8529-0242ac130003',
151
+ value: null,
152
+ formFieldNamespace: 'rfe-forms',
153
+ formFieldPath: 'rfe-forms-patient-past-program',
154
+ });
155
+ });
156
+ });
157
+ });
@@ -23,12 +23,14 @@ const WorkspaceLauncher: React.FC<FormFieldInputProps> = ({ field }) => {
23
23
  };
24
24
 
25
25
  return (
26
- <div>
27
- <div className={styles.label}>{t(field.label)}</div>
28
- <div className={styles.workspaceButton}>
29
- <Button onClick={handleLaunchWorkspace}>{field.questionOptions?.buttonLabel ?? t('launchWorkspace')}</Button>
26
+ !field.isHidden && (
27
+ <div>
28
+ <div className={styles.label}>{t(field.label)}</div>
29
+ <div className={styles.workspaceButton}>
30
+ <Button onClick={handleLaunchWorkspace}>{field.questionOptions?.buttonLabel ?? t('launchWorkspace')}</Button>
31
+ </div>
30
32
  </div>
31
- </div>
33
+ )
32
34
  );
33
35
  };
34
36
 
package/src/constants.ts CHANGED
@@ -10,3 +10,4 @@ export const encounterRepresentation =
10
10
  export const FormsStore = 'forms-engine-store';
11
11
  export const PatientChartWorkspaceHeaderSlot = 'patient-chart-workspace-header-slot';
12
12
  export const codedTypes = ['radio', 'checkbox', 'select', 'content-switcher'];
13
+ export const NullSelectOption = 'OPTION_NULL';