@openmrs/esm-fast-data-entry-app 1.0.1-pre.17 → 1.0.1-pre.176

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.
Files changed (176) hide show
  1. package/README.md +21 -2
  2. package/__mocks__/react-i18next.js +9 -14
  3. package/dist/101.js +1 -0
  4. package/dist/101.js.map +1 -0
  5. package/dist/132.js +1 -1
  6. package/dist/143.js +1 -0
  7. package/dist/143.js.map +1 -0
  8. package/dist/188.js +1 -0
  9. package/dist/188.js.map +1 -0
  10. package/dist/197.js +1 -0
  11. package/dist/219.js +1 -0
  12. package/dist/219.js.map +1 -0
  13. package/dist/221.js +1 -0
  14. package/dist/221.js.map +1 -0
  15. package/dist/259.js +1 -0
  16. package/dist/259.js.map +1 -0
  17. package/dist/29.js +2 -0
  18. package/dist/29.js.LICENSE.txt +3 -0
  19. package/dist/29.js.map +1 -0
  20. package/dist/300.js +1 -0
  21. package/dist/31.js +2 -0
  22. package/dist/{569.js.LICENSE.txt → 31.js.LICENSE.txt} +9 -6
  23. package/dist/31.js.map +1 -0
  24. package/dist/326.js +1 -0
  25. package/dist/326.js.map +1 -0
  26. package/dist/335.js +1 -0
  27. package/dist/367.js +1 -0
  28. package/dist/367.js.map +1 -0
  29. package/dist/480.js +1 -0
  30. package/dist/491.js +1 -0
  31. package/dist/491.js.map +1 -0
  32. package/dist/540.js +2 -0
  33. package/dist/540.js.map +1 -0
  34. package/dist/55.js +1 -0
  35. package/dist/564.js +1 -0
  36. package/dist/564.js.map +1 -0
  37. package/dist/602.js +1 -0
  38. package/dist/602.js.map +1 -0
  39. package/dist/626.js +2 -0
  40. package/dist/626.js.LICENSE.txt +9 -0
  41. package/dist/626.js.map +1 -0
  42. package/dist/652.js +1 -0
  43. package/dist/685.js +1 -0
  44. package/dist/685.js.map +1 -0
  45. package/dist/773.js +2 -0
  46. package/dist/{68.js.LICENSE.txt → 773.js.LICENSE.txt} +13 -2
  47. package/dist/773.js.map +1 -0
  48. package/dist/91.js +1 -0
  49. package/dist/91.js.map +1 -0
  50. package/dist/961.js +2 -0
  51. package/dist/961.js.map +1 -0
  52. package/dist/99.js +1 -0
  53. package/dist/99.js.map +1 -0
  54. package/dist/main.js +1 -1
  55. package/dist/main.js.map +1 -0
  56. package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
  57. package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +403 -136
  58. package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -0
  59. package/dist/routes.json +1 -0
  60. package/jest.config.json +2 -1
  61. package/package.json +41 -38
  62. package/prettier.config.js +8 -0
  63. package/src/CancelModal.tsx +42 -0
  64. package/src/CompleteModal.tsx +35 -0
  65. package/src/FormBootstrap.tsx +39 -11
  66. package/src/Root.tsx +7 -12
  67. package/src/add-group-modal/AddGroupModal.tsx +107 -120
  68. package/src/add-group-modal/styles.scss +7 -3
  69. package/src/config-schema.ts +77 -16
  70. package/src/constant.ts +1 -1
  71. package/src/context/FormWorkflowContext.tsx +31 -32
  72. package/src/context/FormWorkflowReducer.ts +53 -67
  73. package/src/context/GroupFormWorkflowContext.tsx +56 -44
  74. package/src/context/GroupFormWorkflowReducer.ts +177 -68
  75. package/src/declarations.d.ts +4 -0
  76. package/src/empty-state/EmptyDataIllustration.tsx +4 -16
  77. package/src/empty-state/EmptyState.tsx +8 -13
  78. package/src/empty-state/styles.scss +14 -14
  79. package/src/form-entry-workflow/FormEntryWorkflow.tsx +78 -124
  80. package/src/form-entry-workflow/form-review-card/FormReviewCard.tsx +7 -7
  81. package/src/form-entry-workflow/form-review-card/index.ts +1 -1
  82. package/src/form-entry-workflow/form-review-card/styles.scss +9 -11
  83. package/src/form-entry-workflow/index.ts +1 -1
  84. package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +5 -5
  85. package/src/form-entry-workflow/patient-banner/PatientBanner.tsx +14 -27
  86. package/src/form-entry-workflow/patient-banner/index.ts +1 -1
  87. package/src/form-entry-workflow/patient-banner/styles.scss +11 -12
  88. package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +19 -28
  89. package/src/form-entry-workflow/patient-search-header/index.ts +1 -1
  90. package/src/form-entry-workflow/patient-search-header/styles.scss +13 -10
  91. package/src/form-entry-workflow/styles.scss +13 -14
  92. package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +13 -11
  93. package/src/form-entry-workflow/workflow-review/index.ts +1 -1
  94. package/src/form-entry-workflow/workflow-review/styles.scss +0 -4
  95. package/src/forms-app-menu-link.tsx +4 -6
  96. package/src/forms-page/FormsPage.tsx +24 -47
  97. package/src/forms-page/forms-table/FormsTable.tsx +33 -47
  98. package/src/forms-page/forms-table/index.ts +1 -1
  99. package/src/forms-page/forms-table/styles.scss +4 -5
  100. package/src/forms-page/index.ts +1 -1
  101. package/src/forms-page/styles.scss +3 -5
  102. package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +15 -402
  103. package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +207 -0
  104. package/src/group-form-entry-workflow/SessionDetailsForm.tsx +154 -0
  105. package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +99 -0
  106. package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +130 -0
  107. package/src/group-form-entry-workflow/attendance-table/index.ts +1 -0
  108. package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +41 -0
  109. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.test.tsx +5 -5
  110. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +14 -30
  111. package/src/group-form-entry-workflow/group-display-header/index.ts +1 -1
  112. package/src/group-form-entry-workflow/group-display-header/styles.scss +20 -20
  113. package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +24 -35
  114. package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +13 -15
  115. package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +22 -38
  116. package/src/group-form-entry-workflow/group-search/compact-group-result.scss +16 -17
  117. package/src/group-form-entry-workflow/group-search/compact-group-search.scss +7 -8
  118. package/src/group-form-entry-workflow/group-search/group-search.scss +20 -23
  119. package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +41 -18
  120. package/src/group-form-entry-workflow/group-search-header/index.ts +1 -1
  121. package/src/group-form-entry-workflow/group-search-header/styles.scss +8 -8
  122. package/src/group-form-entry-workflow/index.ts +1 -1
  123. package/src/group-form-entry-workflow/styles.scss +15 -17
  124. package/src/hooks/index.ts +7 -6
  125. package/src/hooks/useForm.ts +56 -0
  126. package/src/hooks/useFormState.ts +3 -3
  127. package/src/hooks/useGetAllForms.ts +7 -15
  128. package/src/hooks/useGetEncounter.ts +3 -3
  129. package/src/hooks/useGetPatient.ts +3 -3
  130. package/src/hooks/useGetPatients.ts +32 -0
  131. package/src/hooks/useGetSystemSetting.ts +36 -0
  132. package/src/hooks/useKeyPress.ts +5 -5
  133. package/src/hooks/usePostEndpoint.ts +16 -10
  134. package/src/hooks/useSearchEndpoint.ts +23 -40
  135. package/src/hooks/useStartVisit.ts +82 -0
  136. package/src/index.ts +12 -76
  137. package/src/patient-card/PatientCard.tsx +8 -20
  138. package/src/patient-card/index.ts +1 -1
  139. package/src/patient-card/styles.scss +3 -4
  140. package/src/routes.json +24 -0
  141. package/src/setup-tests.ts +1 -1
  142. package/src/types.ts +20 -0
  143. package/tools/i18next-parser.config.js +93 -0
  144. package/translations/am.json +75 -0
  145. package/translations/ar.json +75 -0
  146. package/translations/en.json +32 -11
  147. package/translations/es.json +75 -0
  148. package/translations/fr.json +75 -0
  149. package/translations/he.json +75 -0
  150. package/translations/km.json +75 -0
  151. package/turbo.json +18 -0
  152. package/webpack.config.js +1 -1
  153. package/dist/247.js +0 -1
  154. package/dist/255.js +0 -1
  155. package/dist/294.js +0 -2
  156. package/dist/32.js +0 -1
  157. package/dist/327.js +0 -1
  158. package/dist/403.js +0 -2
  159. package/dist/403.js.LICENSE.txt +0 -14
  160. package/dist/553.js +0 -2
  161. package/dist/553.js.LICENSE.txt +0 -14
  162. package/dist/569.js +0 -2
  163. package/dist/574.js +0 -1
  164. package/dist/595.js +0 -2
  165. package/dist/595.js.LICENSE.txt +0 -1
  166. package/dist/617.js +0 -1
  167. package/dist/68.js +0 -2
  168. package/dist/776.js +0 -1
  169. package/dist/804.js +0 -1
  170. package/dist/820.js +0 -1
  171. package/dist/906.js +0 -1
  172. package/dist/935.js +0 -2
  173. package/dist/openmrs-esm-fast-data-entry-app.old +0 -1
  174. package/src/declarations.d.tsx +0 -2
  175. /package/dist/{294.js.LICENSE.txt → 540.js.LICENSE.txt} +0 -0
  176. /package/dist/{935.js.LICENSE.txt → 961.js.LICENSE.txt} +0 -0
@@ -1,105 +1,93 @@
1
- import React, { useCallback, useContext, useEffect, useState } from "react";
2
- import {
3
- ComposedModal,
4
- Button,
5
- ModalHeader,
6
- ModalFooter,
7
- ModalBody,
8
- TextInput,
9
- FormLabel,
10
- Loading,
11
- } from "@carbon/react";
12
- import { Add, TrashCan } from "@carbon/react/icons";
13
- import { useTranslation } from "react-i18next";
14
- import { ExtensionSlot, showToast } from "@openmrs/esm-framework";
15
- import styles from "./styles.scss";
16
- import GroupFormWorkflowContext from "../context/GroupFormWorkflowContext";
17
- import { usePostCohort } from "../hooks";
1
+ import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
2
+ import { ComposedModal, Button, ModalHeader, ModalFooter, ModalBody, TextInput, FormLabel } from '@carbon/react';
3
+ import { TrashCan } from '@carbon/react/icons';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { ExtensionSlot, fetchCurrentPatient, showToast, useConfig, usePatient } from '@openmrs/esm-framework';
6
+ import styles from './styles.scss';
7
+ import GroupFormWorkflowContext from '../context/GroupFormWorkflowContext';
8
+ import { usePostCohort } from '../hooks';
18
9
 
19
10
  const MemExtension = React.memo(ExtensionSlot);
20
11
 
21
12
  const PatientRow = ({ patient, removePatient }) => {
22
13
  const { t } = useTranslation();
14
+ const { patient: patientInfo, error, isLoading } = usePatient(patient?.uuid);
15
+ const onClickHandler = useCallback(() => removePatient(patient?.uuid), [patient, removePatient]);
16
+
17
+ const patientDisplay = useMemo(() => {
18
+ if (isLoading || error || !patientInfo) return '';
19
+
20
+ const { identifier, name } = patientInfo;
21
+ const displayIdentifier = identifier?.[0]?.value || '';
22
+ const givenNames = `${(name?.[0]?.given || []).join(' ')} ${name?.[0]?.family || ''}`;
23
+
24
+ return `${displayIdentifier ? `${displayIdentifier} -` : ''}${givenNames ? ` ${givenNames}` : ''}`.trim();
25
+ }, [isLoading, error, patientInfo]);
26
+
23
27
  return (
24
- <li key={patient.uuid} className={styles.patientRow}>
28
+ <li className={styles.patientRow}>
25
29
  <span>
26
30
  <Button
27
31
  kind="tertiary"
28
32
  size="sm"
29
33
  hasIconOnly
30
- onClick={() => removePatient(patient.uuid)}
34
+ onClick={onClickHandler}
31
35
  renderIcon={TrashCan}
32
36
  tooltipAlignment="start"
33
37
  tooltipPosition="top"
34
- iconDescription={t("remove", "Remove")}
38
+ iconDescription={t('remove', 'Remove')}
35
39
  />
36
40
  </span>
37
- <span className={styles.patientName}>{patient?.display}</span>
41
+ <span className={styles.patientName}>{patientDisplay}</span>
38
42
  </li>
39
43
  );
40
44
  };
41
45
 
42
46
  const NewGroupForm = (props) => {
43
- const {
44
- name,
45
- setName,
46
- patientList,
47
- updatePatientList,
48
- errors,
49
- validate,
50
- removePatient,
51
- } = props;
47
+ const { name, setName, patientList, updatePatientList, errors, validate, removePatient } = props;
52
48
  const { t } = useTranslation();
53
49
 
54
50
  return (
55
51
  <div
56
52
  style={{
57
- display: "flex",
58
- flexDirection: "column",
59
- rowGap: "1rem",
53
+ display: 'flex',
54
+ flexDirection: 'column',
55
+ rowGap: '1rem',
60
56
  }}
61
57
  >
62
58
  <TextInput
63
- labelText={t("newGroupName", "New Group Name")}
59
+ labelText={t('newGroupName', 'New Group Name')}
64
60
  value={name}
65
61
  onChange={(e) => setName(e.target.value)}
66
- onBlur={() => validate("name")}
62
+ onBlur={() => validate('name')}
67
63
  />
68
64
  {errors?.name && (
69
65
  <p className={styles.formError}>
70
- {errors.name === "required"
71
- ? t("groupNameError", "Please enter a group name.")
72
- : errors.name}
66
+ {errors.name === 'required' ? t('groupNameError', 'Please enter a group name.') : errors.name}
73
67
  </p>
74
68
  )}
75
69
  <FormLabel>
76
- {patientList.length} {t("patientsInGroup", "Patients in group")}
70
+ {patientList.length} {t('patientsInGroup', 'Patients in group')}
77
71
  </FormLabel>
78
72
  {errors?.patientList && (
79
- <p className={styles.formError}>
80
- {t("noPatientError", "Please enter at least one patient.")}
81
- </p>
73
+ <p className={styles.formError}>{t('noPatientError', 'Please enter at least one patient.')}</p>
82
74
  )}
83
75
  {!errors?.patientList && (
84
76
  <ul className={styles.patientList}>
85
77
  {patientList?.map((patient, index) => (
86
- <PatientRow
87
- patient={patient}
88
- removePatient={removePatient}
89
- key={index}
90
- />
78
+ <PatientRow patient={patient} removePatient={removePatient} key={patient.uuid} />
91
79
  ))}
92
80
  </ul>
93
81
  )}
94
82
 
95
- <FormLabel>Search for patients to add to group</FormLabel>
83
+ <FormLabel>{t('searchForPatientsToAddToGroup', 'Search for patients to add to group')}</FormLabel>
96
84
  <div className={styles.searchBar}>
97
85
  <MemExtension
98
86
  extensionSlotName="patient-search-bar-slot"
99
87
  state={{
100
88
  selectPatientAction: updatePatientList,
101
89
  buttonProps: {
102
- kind: "secondary",
90
+ kind: 'secondary',
103
91
  },
104
92
  }}
105
93
  />
@@ -108,45 +96,47 @@ const NewGroupForm = (props) => {
108
96
  );
109
97
  };
110
98
 
111
- const AddGroupModal = () => {
99
+ const AddGroupModal = ({
100
+ patients = undefined,
101
+ isCreate = undefined,
102
+ groupName = '',
103
+ cohortUuid = undefined,
104
+ isOpen,
105
+ onPostCancel,
106
+ onPostSubmit,
107
+ }) => {
112
108
  const { setGroup } = useContext(GroupFormWorkflowContext);
113
109
  const { t } = useTranslation();
114
- const [open, setOpen] = useState(false);
115
110
  const [errors, setErrors] = useState({});
116
- const [name, setName] = useState("");
117
- const [patientList, setPatientList] = useState([]);
118
- const { post, result, isPosting, error } = usePostCohort();
119
-
120
- const handleCancel = () => {
121
- setOpen(false);
122
- };
111
+ const [name, setName] = useState(groupName);
112
+ const [patientList, setPatientList] = useState(patients || []);
113
+ const { post, result, error } = usePostCohort();
114
+ const config = useConfig();
123
115
 
124
116
  const removePatient = useCallback(
125
117
  (patientUuid: string) =>
126
- setPatientList((patientList) =>
127
- patientList.filter((patient) => patient.uuid !== patientUuid)
128
- ),
129
- [setPatientList]
118
+ setPatientList((patientList) => patientList.filter((patient) => patient.uuid !== patientUuid)),
119
+ [setPatientList],
130
120
  );
131
121
 
132
122
  const validate = useCallback(
133
123
  (field?: string | undefined) => {
134
124
  let valid = true;
135
125
  if (field) {
136
- valid = field === "name" ? !!name : !!patientList.length;
126
+ valid = field === 'name' ? !!name : !!patientList.length;
137
127
  setErrors((errors) => ({
138
128
  ...errors,
139
- [field]: valid ? null : "required",
129
+ [field]: valid ? null : 'required',
140
130
  }));
141
131
  } else {
142
132
  if (!name) {
143
- setErrors((errors) => ({ ...errors, name: "required" }));
133
+ setErrors((errors) => ({ ...errors, name: 'required' }));
144
134
  valid = false;
145
135
  } else {
146
136
  setErrors((errors) => ({ ...errors, name: null }));
147
137
  }
148
138
  if (!patientList.length) {
149
- setErrors((errors) => ({ ...errors, patientList: "required" }));
139
+ setErrors((errors) => ({ ...errors, patientList: 'required' }));
150
140
  valid = false;
151
141
  } else {
152
142
  setErrors((errors) => ({ ...errors, patientList: null }));
@@ -154,29 +144,49 @@ const AddGroupModal = () => {
154
144
  }
155
145
  return valid;
156
146
  },
157
- [name, patientList.length]
147
+ [name, patientList.length],
158
148
  );
159
149
 
160
150
  const updatePatientList = useCallback(
161
- (patient) => {
162
- setPatientList((patientList) => {
163
- if (!patientList.find((p) => p.uuid === patient.uuid)) {
164
- return [...patientList, patient];
165
- } else {
166
- return patientList;
167
- }
168
- });
151
+ (patientUuid) => {
152
+ function getPatientName(patient) {
153
+ return [patient?.name?.[0]?.given, patient?.name?.[0]?.family].join(' ');
154
+ }
155
+ if (!patientList.find((p) => p.uuid === patientUuid)) {
156
+ fetchCurrentPatient(patientUuid).then((result) => {
157
+ const newPatient = { uuid: patientUuid, ...result };
158
+ setPatientList(
159
+ [...patientList, newPatient].sort((a, b) =>
160
+ getPatientName(a).localeCompare(getPatientName(b), undefined, {
161
+ sensitivity: 'base',
162
+ }),
163
+ ),
164
+ );
165
+ });
166
+ }
169
167
  setErrors((errors) => ({ ...errors, patientList: null }));
170
168
  },
171
- [setPatientList]
169
+ [patientList, setPatientList],
172
170
  );
173
171
 
174
172
  const handleSubmit = () => {
175
173
  if (validate()) {
176
174
  post({
175
+ uuid: cohortUuid,
177
176
  name: name,
177
+ cohortType: config?.groupSessionConcepts?.cohortTypeId,
178
178
  cohortMembers: patientList.map((p) => ({ patient: p.uuid })),
179
179
  });
180
+ if (onPostSubmit) {
181
+ onPostSubmit();
182
+ }
183
+ }
184
+ };
185
+
186
+ const handleCancel = () => {
187
+ setPatientList(patients || []);
188
+ if (onPostCancel) {
189
+ onPostCancel();
180
190
  }
181
191
  };
182
192
 
@@ -194,20 +204,13 @@ const AddGroupModal = () => {
194
204
  useEffect(() => {
195
205
  if (error) {
196
206
  showToast({
197
- kind: "error",
198
- title: t("postError", "POST Error"),
199
- description:
200
- error.message ??
201
- t("unknownPostError", "An unknown error occured while saving data"),
207
+ kind: 'error',
208
+ title: t('postError', 'POST Error'),
209
+ description: error.message ?? t('unknownPostError', 'An unknown error occurred while saving data'),
202
210
  });
203
211
  if (error.fieldErrors) {
204
212
  setErrors(
205
- Object.fromEntries(
206
- Object.entries(error.fieldErrors).map(([key, value]) => [
207
- key,
208
- value?.[0]?.message,
209
- ])
210
- )
213
+ Object.fromEntries(Object.entries(error.fieldErrors).map(([key, value]) => [key, value?.[0]?.message])),
211
214
  );
212
215
  }
213
216
  }
@@ -215,43 +218,27 @@ const AddGroupModal = () => {
215
218
 
216
219
  return (
217
220
  <div className={styles.modal}>
218
- <Button
219
- onClick={() => setOpen(true)}
220
- renderIcon={Add}
221
- iconDescription="Add"
222
- >
223
- {t("createNewGroup", "Create New Group")}
224
- </Button>
225
- <ComposedModal open={open} onClose={() => setOpen(false)}>
226
- <ModalHeader>{t("createNewGroup", "Create New Group")}</ModalHeader>
221
+ <ComposedModal open={isOpen} onClose={handleCancel}>
222
+ <ModalHeader>{isCreate ? t('createNewGroup', 'Create New Group') : t('editGroup', 'Edit Group')}</ModalHeader>
227
223
  <ModalBody>
228
- {result ? (
229
- <p>Group saved succesfully</p>
230
- ) : isPosting ? (
231
- <div className={styles.loading}>
232
- <Loading withOverlay={false} />
233
- <span>Saving new group...</span>
234
- </div>
235
- ) : (
236
- <NewGroupForm
237
- {...{
238
- name,
239
- setName,
240
- patientList,
241
- updatePatientList,
242
- errors,
243
- validate,
244
- removePatient,
245
- }}
246
- />
247
- )}
224
+ <NewGroupForm
225
+ {...{
226
+ name,
227
+ setName,
228
+ patientList,
229
+ updatePatientList,
230
+ errors,
231
+ validate,
232
+ removePatient,
233
+ }}
234
+ />
248
235
  </ModalBody>
249
236
  <ModalFooter>
250
- <Button kind="secondary" onClick={handleCancel} disabled={isPosting}>
251
- {t("cancel", "Cancel")}
237
+ <Button kind="secondary" onClick={handleCancel}>
238
+ {t('cancel', 'Cancel')}
252
239
  </Button>
253
- <Button kind="primary" onClick={handleSubmit} disabled={isPosting}>
254
- {t("createGroup", "Create Group")}
240
+ <Button kind="primary" onClick={handleSubmit}>
241
+ {isCreate ? t('createGroup', 'Create Group') : t('save', 'Save')}
255
242
  </Button>
256
243
  </ModalFooter>
257
244
  </ComposedModal>
@@ -1,5 +1,5 @@
1
- @use '@carbon/styles/scss/spacing';
2
1
  @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
3
 
4
4
  .modal {
5
5
  :global(.cds--modal) {
@@ -17,6 +17,10 @@
17
17
  width: 100%
18
18
  }
19
19
 
20
+ .searchBar > div button {
21
+ height: auto;
22
+ }
23
+
20
24
  .formError {
21
25
  color: red;
22
26
  }
@@ -32,7 +36,7 @@
32
36
 
33
37
  .patientName {
34
38
  flex-grow: 1;
35
- padding-left: spacing.$spacing-05;
39
+ padding-left: layout.$spacing-05;
36
40
  }
37
41
 
38
42
  .loading {
@@ -41,5 +45,5 @@
41
45
  flex-direction: column;
42
46
  justify-content: center;
43
47
  align-items: center;
44
- row-gap: spacing.$spacing-05;
48
+ row-gap: layout.$spacing-05;
45
49
  }
@@ -1,4 +1,4 @@
1
- import { Type } from "@openmrs/esm-framework";
1
+ import { Type } from '@openmrs/esm-framework';
2
2
 
3
3
  /**
4
4
  * This is the config schema.
@@ -8,44 +8,43 @@ import { Type } from "@openmrs/esm-framework";
8
8
  export const configSchema = {
9
9
  formCategories: {
10
10
  _type: Type.Array,
11
- _description:
12
- "Organize forms into categories. A form can belong to multiple categories.",
11
+ _description: 'Organize forms into categories. A form can belong to multiple categories.',
13
12
  _elements: {
14
13
  name: {
15
14
  _type: Type.String,
16
- _description: "Category name",
15
+ _description: 'Category name',
17
16
  },
18
17
  forms: {
19
18
  _type: Type.Array,
20
- _description: "List of forms for this category.",
19
+ _description: 'List of forms for this category.',
21
20
  _elements: {
22
21
  formUUID: {
23
22
  _type: Type.UUID,
24
- _description: "UUID of form",
23
+ _description: 'UUID of form',
25
24
  },
26
25
  name: {
27
26
  _type: Type.String,
28
- _description: "Name of form",
27
+ _description: 'Name of form',
29
28
  },
30
29
  },
31
30
  },
32
31
  },
33
32
  _default: [
34
33
  {
35
- name: "ICRC Forms",
34
+ name: 'ICRC Forms',
36
35
  forms: [
37
36
  {
38
- formUUID: "0cefb866-110c-4f16-af58-560932a1db1f",
39
- name: "Adult Triage",
37
+ formUUID: '0cefb866-110c-4f16-af58-560932a1db1f',
38
+ name: 'Adult Triage',
40
39
  },
41
40
  ],
42
41
  },
43
42
  {
44
- name: "Distress Scales",
43
+ name: 'Distress Scales',
45
44
  forms: [
46
45
  {
47
- formUUID: "9f26aad4-244a-46ca-be49-1196df1a8c9a",
48
- name: "POC Sample Form 1",
46
+ formUUID: '9f26aad4-244a-46ca-be49-1196df1a8c9a',
47
+ name: 'POC Sample Form 1',
49
48
  },
50
49
  ],
51
50
  },
@@ -53,12 +52,74 @@ export const configSchema = {
53
52
  },
54
53
  formCategoriesToShow: {
55
54
  _type: Type.Array,
56
- _description: "Forms to show by default on the forms app home page.",
55
+ _description: 'Forms to show by default on the forms app home page.',
57
56
  _elements: {
58
57
  _type: Type.String,
59
- _description: "Name of category",
58
+ _description: 'Name of category',
60
59
  },
61
- _default: ["ICRC Forms", "Distress Scales"],
60
+ _default: ['ICRC Forms', 'Distress Scales'],
61
+ },
62
+ groupSessionConcepts: {
63
+ sessionName: {
64
+ _type: Type.UUID,
65
+ _description: 'UUID of concept for Session Name',
66
+ _default: 'e2559620-900b-4f66-ae41-0b9c4adfb654',
67
+ },
68
+ sessionDate: {
69
+ _type: Type.UUID,
70
+ _description: 'UUID of concept for Session Date',
71
+ _default: 'ceaca505-6dff-4940-8a43-8c060a0924d7',
72
+ },
73
+ practitionerName: {
74
+ _type: Type.UUID,
75
+ _description: 'UUID of concept for Practitioner Name',
76
+ _default: 'f1a2d58c-1a0e-4148-931a-aac224649fdc',
77
+ },
78
+ sessionNotes: {
79
+ _type: Type.UUID,
80
+ _description: 'UUID of concept for Session Notes',
81
+ _default: 'fa8fedc0-c066-4da3-8dc1-2ad8621fc480',
82
+ },
83
+ cohortTypeId: {
84
+ _type: Type.UUID,
85
+ _description: 'UUID of cohort type',
86
+ _default: 'eee9970e-7ca0-4e8c-a280-c33e9d5f6a04',
87
+ },
88
+ cohortId: {
89
+ _type: Type.UUID,
90
+ _description: 'UUID of concept for cohort identifier',
91
+ _default: '5461f231-7e59-4be8-93a4-6d49fd13c00a',
92
+ },
93
+ cohortName: {
94
+ _type: Type.UUID,
95
+ _description: 'UUID of concept for cohort name',
96
+ _default: '6029f289-92a6-4a68-80f1-3078d0152449',
97
+ },
98
+ sessionUuid: {
99
+ _type: Type.UUID,
100
+ _description: 'UUID of concept for session identifier',
101
+ _default: '6a803908-8a5b-4598-adea-19358c83529a',
102
+ },
103
+ },
104
+ specificQuestions: {
105
+ _type: Type.Array,
106
+ _description: 'List of specific questions to populate forms.',
107
+ _elements: {
108
+ forms: {
109
+ _type: Type.Array,
110
+ _description: 'List of form UUIDs for which the question applies.',
111
+ _elements: {
112
+ _type: Type.UUID,
113
+ },
114
+ _default: [],
115
+ },
116
+ questionId: {
117
+ _type: Type.String,
118
+ _description: 'ID of the question.',
119
+ _default: '',
120
+ },
121
+ },
122
+ _default: [],
62
123
  },
63
124
  };
64
125
 
package/src/constant.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export const routes = {
2
- allForms: "all-forms",
2
+ allForms: 'all-forms',
3
3
  };
4
4
 
5
5
  export const spaBase = window.spaBase;
@@ -1,6 +1,8 @@
1
- import React, { useEffect, useMemo, useReducer } from "react";
2
- import reducer from "./FormWorkflowReducer";
3
- import { useParams, useLocation } from "react-router-dom";
1
+ import React, { useEffect, useMemo, useReducer } from 'react';
2
+ import reducer from './FormWorkflowReducer';
3
+ import { useParams, useLocation } from 'react-router-dom';
4
+ import useGetSystemSetting from '../hooks/useGetSystemSetting';
5
+ import { useSession } from '@openmrs/esm-framework';
4
6
  interface ParamTypes {
5
7
  formUuid?: string;
6
8
  }
@@ -30,6 +32,8 @@ export const initialWorkflowState = {
30
32
  activeEncounterUuid: null, // pseudo field from state[activeFormUuid].encounterUuid
31
33
  patientUuids: [], // pseudo field from state[activeFormUuid].patientUuids
32
34
  encounters: {}, // pseudo field from state[activeFormUuid].encounters
35
+ singleSessionVisitTypeUuid: null,
36
+ userUuid: null, // UUID of the user to which this workflow state belongs to
33
37
  };
34
38
 
35
39
  const FormWorkflowContext = React.createContext({
@@ -38,41 +42,43 @@ const FormWorkflowContext = React.createContext({
38
42
  });
39
43
 
40
44
  const FormWorkflowProvider = ({ children }) => {
45
+ const { user } = useSession();
41
46
  const { formUuid } = useParams() as ParamTypes;
42
- const activeFormUuid = formUuid.split("&")[0];
47
+ const activeFormUuid = formUuid.split('&')[0];
43
48
  const { search } = useLocation();
44
- const newPatientUuid = new URLSearchParams(search).get("patientUuid");
49
+ const newPatientUuid = new URLSearchParams(search).get('patientUuid');
45
50
  const [state, dispatch] = useReducer(reducer, {
46
51
  ...initialWorkflowState,
47
52
  ...initialActions,
48
53
  });
54
+ const systemSetting = useGetSystemSetting('@openmrs/esm-fast-data-entry-app.groupSessionVisitTypeUuid');
55
+ const singleSessionVisitTypeUuid = systemSetting?.result?.data?.results?.[0]?.value;
49
56
 
50
57
  const actions = useMemo(
51
58
  () => ({
52
59
  initializeWorkflowState: ({ activeFormUuid, newPatientUuid }) =>
53
60
  dispatch({
54
- type: "INITIALIZE_WORKFLOW_STATE",
61
+ type: 'INITIALIZE_WORKFLOW_STATE',
55
62
  activeFormUuid,
56
63
  newPatientUuid,
64
+ userUuid: user.uuid,
57
65
  }),
58
- addPatient: (patientUuid) =>
59
- dispatch({ type: "ADD_PATIENT", patientUuid }),
60
- openPatientSearch: () => dispatch({ type: "OPEN_PATIENT_SEARCH" }),
66
+ addPatient: (patientUuid) => dispatch({ type: 'ADD_PATIENT', patientUuid }),
67
+ openPatientSearch: () => dispatch({ type: 'OPEN_PATIENT_SEARCH' }),
61
68
  saveEncounter: (encounterUuid) =>
62
69
  dispatch({
63
- type: "SAVE_ENCOUNTER",
70
+ type: 'SAVE_ENCOUNTER',
64
71
  encounterUuid,
65
72
  }),
66
- submitForNext: () => dispatch({ type: "SUBMIT_FOR_NEXT" }),
67
- submitForReview: () => dispatch({ type: "SUBMIT_FOR_REVIEW" }),
68
- submitForComplete: () => dispatch({ type: "SUBMIT_FOR_COMPLETE" }),
69
- editEncounter: (patientUuid) =>
70
- dispatch({ type: "EDIT_ENCOUNTER", patientUuid }),
71
- goToReview: () => dispatch({ type: "GO_TO_REVIEW" }),
72
- destroySession: () => dispatch({ type: "DESTROY_SESSION" }),
73
- closeSession: () => dispatch({ type: "CLOSE_SESSION" }),
73
+ submitForNext: () => dispatch({ type: 'SUBMIT_FOR_NEXT' }),
74
+ submitForReview: () => dispatch({ type: 'SUBMIT_FOR_REVIEW' }),
75
+ submitForComplete: () => dispatch({ type: 'SUBMIT_FOR_COMPLETE' }),
76
+ editEncounter: (patientUuid) => dispatch({ type: 'EDIT_ENCOUNTER', patientUuid }),
77
+ goToReview: () => dispatch({ type: 'GO_TO_REVIEW' }),
78
+ destroySession: () => dispatch({ type: 'DESTROY_SESSION' }),
79
+ closeSession: () => dispatch({ type: 'CLOSE_SESSION' }),
74
80
  }),
75
- []
81
+ [user],
76
82
  );
77
83
 
78
84
  // if formUuid isn't a part of state yet, grab it from the url params
@@ -88,21 +94,14 @@ const FormWorkflowProvider = ({ children }) => {
88
94
  value={{
89
95
  ...state,
90
96
  ...actions,
91
- workflowState:
92
- state.forms?.[state.activeFormUuid]?.workflowState ??
93
- initialWorkflowState.workflowState,
97
+ workflowState: state.forms?.[state.activeFormUuid]?.workflowState ?? initialWorkflowState.workflowState,
94
98
  activePatientUuid:
95
- state.forms?.[state.activeFormUuid]?.activePatientUuid ??
96
- initialWorkflowState.activePatientUuid,
99
+ state.forms?.[state.activeFormUuid]?.activePatientUuid ?? initialWorkflowState.activePatientUuid,
97
100
  activeEncounterUuid:
98
- state.forms?.[state.activeFormUuid]?.activeEncounterUuid ??
99
- initialWorkflowState.activeEncounterUuid,
100
- patientUuids:
101
- state.forms?.[state.activeFormUuid]?.patientUuids ??
102
- initialWorkflowState.patientUuids,
103
- encounters:
104
- state.forms?.[state.activeFormUuid]?.encounters ??
105
- initialWorkflowState.encounters,
101
+ state.forms?.[state.activeFormUuid]?.activeEncounterUuid ?? initialWorkflowState.activeEncounterUuid,
102
+ patientUuids: state.forms?.[state.activeFormUuid]?.patientUuids ?? initialWorkflowState.patientUuids,
103
+ encounters: state.forms?.[state.activeFormUuid]?.encounters ?? initialWorkflowState.encounters,
104
+ singleSessionVisitTypeUuid,
106
105
  }}
107
106
  >
108
107
  {children}