@openmrs/esm-fast-data-entry-app 1.0.0-pre.59 → 1.0.0

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 (193) 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/188.js +1 -0
  7. package/dist/188.js.map +1 -0
  8. package/dist/197.js +1 -0
  9. package/dist/219.js +1 -0
  10. package/dist/219.js.map +1 -0
  11. package/dist/221.js +1 -0
  12. package/dist/221.js.map +1 -0
  13. package/dist/259.js +1 -0
  14. package/dist/259.js.map +1 -0
  15. package/dist/29.js +2 -0
  16. package/dist/29.js.LICENSE.txt +3 -0
  17. package/dist/29.js.map +1 -0
  18. package/dist/300.js +1 -0
  19. package/dist/326.js +1 -0
  20. package/dist/326.js.map +1 -0
  21. package/dist/335.js +1 -0
  22. package/dist/367.js +1 -0
  23. package/dist/367.js.map +1 -0
  24. package/dist/480.js +1 -0
  25. package/dist/540.js +2 -0
  26. package/dist/{536.js.LICENSE.txt → 540.js.LICENSE.txt} +3 -2
  27. package/dist/540.js.map +1 -0
  28. package/dist/55.js +1 -0
  29. package/dist/564.js +1 -0
  30. package/dist/564.js.map +1 -0
  31. package/dist/602.js +1 -0
  32. package/dist/602.js.map +1 -0
  33. package/dist/626.js +2 -0
  34. package/dist/{294.js.LICENSE.txt → 626.js.LICENSE.txt} +3 -8
  35. package/dist/626.js.map +1 -0
  36. package/dist/652.js +1 -0
  37. package/dist/685.js +1 -0
  38. package/dist/685.js.map +1 -0
  39. package/dist/773.js +2 -0
  40. package/dist/773.js.LICENSE.txt +32 -0
  41. package/dist/773.js.map +1 -0
  42. package/dist/893.js +1 -0
  43. package/dist/893.js.map +1 -0
  44. package/dist/91.js +1 -0
  45. package/dist/91.js.map +1 -0
  46. package/dist/941.js +2 -0
  47. package/dist/941.js.LICENSE.txt +30 -0
  48. package/dist/941.js.map +1 -0
  49. package/dist/961.js +2 -0
  50. package/dist/{935.js.LICENSE.txt → 961.js.LICENSE.txt} +6 -10
  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/991.js +1 -0
  55. package/dist/991.js.map +1 -0
  56. package/dist/main.js +1 -0
  57. package/dist/main.js.map +1 -0
  58. package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
  59. package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +500 -122
  60. package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -0
  61. package/dist/routes.json +1 -0
  62. package/jest.config.json +21 -18
  63. package/package.json +59 -62
  64. package/prettier.config.js +8 -0
  65. package/src/CancelModal.tsx +42 -0
  66. package/src/CompleteModal.tsx +35 -0
  67. package/src/FormBootstrap.tsx +45 -10
  68. package/src/Root.tsx +11 -9
  69. package/src/add-group-modal/AddGroupModal.tsx +249 -0
  70. package/src/add-group-modal/styles.scss +49 -0
  71. package/src/config-schema.ts +77 -16
  72. package/src/constant.ts +1 -1
  73. package/src/context/FormWorkflowContext.tsx +32 -33
  74. package/src/context/FormWorkflowReducer.ts +53 -67
  75. package/src/context/GroupFormWorkflowContext.tsx +155 -0
  76. package/src/context/GroupFormWorkflowReducer.ts +405 -0
  77. package/src/declarations.d.ts +4 -0
  78. package/src/empty-state/EmptyDataIllustration.tsx +4 -16
  79. package/src/empty-state/EmptyState.tsx +16 -17
  80. package/src/empty-state/styles.scss +14 -14
  81. package/src/form-entry-workflow/FormEntryWorkflow.tsx +89 -125
  82. package/src/{form-review-card → form-entry-workflow/form-review-card}/FormReviewCard.tsx +7 -7
  83. package/src/form-entry-workflow/form-review-card/index.ts +3 -0
  84. package/src/form-entry-workflow/form-review-card/styles.scss +37 -0
  85. package/src/form-entry-workflow/index.ts +1 -1
  86. package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +9 -0
  87. package/src/{patient-banner → form-entry-workflow/patient-banner}/PatientBanner.tsx +14 -27
  88. package/src/form-entry-workflow/patient-banner/index.ts +3 -0
  89. package/src/form-entry-workflow/patient-banner/styles.scss +44 -0
  90. package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +54 -0
  91. package/src/form-entry-workflow/patient-search-header/index.ts +3 -0
  92. package/src/form-entry-workflow/patient-search-header/styles.scss +25 -0
  93. package/src/form-entry-workflow/styles.scss +16 -16
  94. package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +37 -0
  95. package/src/form-entry-workflow/workflow-review/index.ts +3 -0
  96. package/src/{workflow-review → form-entry-workflow/workflow-review}/styles.scss +0 -4
  97. package/src/forms-app-menu-link.tsx +5 -7
  98. package/src/forms-page/FormsPage.tsx +48 -37
  99. package/src/forms-page/forms-table/FormsTable.tsx +117 -0
  100. package/src/forms-page/forms-table/index.ts +3 -0
  101. package/src/forms-page/forms-table/styles.scss +19 -0
  102. package/src/forms-page/index.ts +1 -1
  103. package/src/forms-page/styles.scss +3 -5
  104. package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +26 -0
  105. package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +207 -0
  106. package/src/group-form-entry-workflow/SessionDetailsForm.tsx +154 -0
  107. package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +99 -0
  108. package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +130 -0
  109. package/src/group-form-entry-workflow/attendance-table/index.ts +1 -0
  110. package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +41 -0
  111. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.test.tsx +9 -0
  112. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +55 -0
  113. package/src/group-form-entry-workflow/group-display-header/index.ts +3 -0
  114. package/src/group-form-entry-workflow/group-display-header/styles.scss +60 -0
  115. package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +128 -0
  116. package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +66 -0
  117. package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +134 -0
  118. package/src/group-form-entry-workflow/group-search/compact-group-result.scss +63 -0
  119. package/src/group-form-entry-workflow/group-search/compact-group-search.scss +34 -0
  120. package/src/group-form-entry-workflow/group-search/group-search.scss +93 -0
  121. package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +72 -0
  122. package/src/group-form-entry-workflow/group-search-header/index.ts +3 -0
  123. package/src/group-form-entry-workflow/group-search-header/styles.scss +20 -0
  124. package/src/group-form-entry-workflow/index.ts +3 -0
  125. package/src/group-form-entry-workflow/styles.scss +94 -0
  126. package/src/hooks/index.ts +7 -5
  127. package/src/hooks/useForm.ts +56 -0
  128. package/src/hooks/useFormState.ts +3 -3
  129. package/src/hooks/useGetAllForms.ts +7 -15
  130. package/src/hooks/useGetEncounter.ts +3 -3
  131. package/src/hooks/useGetPatient.ts +3 -3
  132. package/src/hooks/useGetPatients.ts +32 -0
  133. package/src/hooks/useGetSystemSetting.ts +36 -0
  134. package/src/hooks/useKeyPress.ts +31 -0
  135. package/src/hooks/usePostEndpoint.ts +76 -0
  136. package/src/hooks/useSearchEndpoint.ts +103 -0
  137. package/src/hooks/useStartVisit.ts +82 -0
  138. package/src/index.ts +12 -72
  139. package/src/patient-card/PatientCard.tsx +10 -20
  140. package/src/patient-card/index.ts +1 -1
  141. package/src/patient-card/styles.scss +8 -8
  142. package/src/routes.json +24 -0
  143. package/src/setup-tests.ts +1 -1
  144. package/src/types.ts +20 -0
  145. package/tools/i18next-parser.config.js +93 -0
  146. package/translations/am.json +75 -0
  147. package/translations/ar.json +75 -0
  148. package/translations/en.json +57 -2
  149. package/translations/es.json +75 -0
  150. package/translations/fr.json +75 -0
  151. package/translations/he.json +75 -0
  152. package/translations/km.json +75 -0
  153. package/turbo.json +18 -0
  154. package/webpack.config.js +1 -1
  155. package/.editorconfig +0 -12
  156. package/.eslintignore +0 -2
  157. package/.eslintrc.js +0 -10
  158. package/.github/pull_request_template.md +0 -18
  159. package/.github/workflows/node.js.yml +0 -121
  160. package/.husky/pre-push +0 -1
  161. package/.prettierignore +0 -14
  162. package/dist/187.js +0 -1
  163. package/dist/247.js +0 -1
  164. package/dist/294.js +0 -2
  165. package/dist/312.js +0 -1
  166. package/dist/412.js +0 -1
  167. package/dist/536.js +0 -2
  168. package/dist/574.js +0 -1
  169. package/dist/592.js +0 -1
  170. package/dist/595.js +0 -2
  171. package/dist/595.js.LICENSE.txt +0 -1
  172. package/dist/776.js +0 -1
  173. package/dist/804.js +0 -1
  174. package/dist/880.js +0 -2
  175. package/dist/880.js.LICENSE.txt +0 -20
  176. package/dist/906.js +0 -1
  177. package/dist/935.js +0 -2
  178. package/dist/990.js +0 -1
  179. package/dist/openmrs-esm-fast-data-entry-app.old +0 -1
  180. package/src/declarations.d.tsx +0 -2
  181. package/src/form-review-card/index.ts +0 -3
  182. package/src/form-review-card/styles.scss +0 -38
  183. package/src/forms-table/FormsTable.tsx +0 -123
  184. package/src/forms-table/index.ts +0 -3
  185. package/src/forms-table/styles.scss +0 -20
  186. package/src/patient-banner/PatientBanner.test.tsx +0 -9
  187. package/src/patient-banner/index.ts +0 -3
  188. package/src/patient-banner/styles.scss +0 -44
  189. package/src/patient-search-header/PatientSearchHeader.tsx +0 -61
  190. package/src/patient-search-header/index.ts +0 -3
  191. package/src/patient-search-header/styles.scss +0 -21
  192. package/src/workflow-review/WorkflowReview.tsx +0 -35
  193. package/src/workflow-review/index.ts +0 -3
@@ -0,0 +1,249 @@
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';
9
+
10
+ const MemExtension = React.memo(ExtensionSlot);
11
+
12
+ const PatientRow = ({ patient, removePatient }) => {
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
+
27
+ return (
28
+ <li className={styles.patientRow}>
29
+ <span>
30
+ <Button
31
+ kind="tertiary"
32
+ size="sm"
33
+ hasIconOnly
34
+ onClick={onClickHandler}
35
+ renderIcon={TrashCan}
36
+ tooltipAlignment="start"
37
+ tooltipPosition="top"
38
+ iconDescription={t('remove', 'Remove')}
39
+ />
40
+ </span>
41
+ <span className={styles.patientName}>{patientDisplay}</span>
42
+ </li>
43
+ );
44
+ };
45
+
46
+ const NewGroupForm = (props) => {
47
+ const { name, setName, patientList, updatePatientList, errors, validate, removePatient } = props;
48
+ const { t } = useTranslation();
49
+
50
+ return (
51
+ <div
52
+ style={{
53
+ display: 'flex',
54
+ flexDirection: 'column',
55
+ rowGap: '1rem',
56
+ }}
57
+ >
58
+ <TextInput
59
+ labelText={t('newGroupName', 'New Group Name')}
60
+ value={name}
61
+ onChange={(e) => setName(e.target.value)}
62
+ onBlur={() => validate('name')}
63
+ />
64
+ {errors?.name && (
65
+ <p className={styles.formError}>
66
+ {errors.name === 'required' ? t('groupNameError', 'Please enter a group name.') : errors.name}
67
+ </p>
68
+ )}
69
+ <FormLabel>
70
+ {patientList.length} {t('patientsInGroup', 'Patients in group')}
71
+ </FormLabel>
72
+ {errors?.patientList && (
73
+ <p className={styles.formError}>{t('noPatientError', 'Please enter at least one patient.')}</p>
74
+ )}
75
+ {!errors?.patientList && (
76
+ <ul className={styles.patientList}>
77
+ {patientList?.map((patient, index) => (
78
+ <PatientRow patient={patient} removePatient={removePatient} key={patient.uuid} />
79
+ ))}
80
+ </ul>
81
+ )}
82
+
83
+ <FormLabel>{t('searchForPatientsToAddToGroup', 'Search for patients to add to group')}</FormLabel>
84
+ <div className={styles.searchBar}>
85
+ <MemExtension
86
+ extensionSlotName="patient-search-bar-slot"
87
+ state={{
88
+ selectPatientAction: updatePatientList,
89
+ buttonProps: {
90
+ kind: 'secondary',
91
+ },
92
+ }}
93
+ />
94
+ </div>
95
+ </div>
96
+ );
97
+ };
98
+
99
+ const AddGroupModal = ({
100
+ patients = undefined,
101
+ isCreate = undefined,
102
+ groupName = '',
103
+ cohortUuid = undefined,
104
+ isOpen,
105
+ onPostCancel,
106
+ onPostSubmit,
107
+ }) => {
108
+ const { setGroup } = useContext(GroupFormWorkflowContext);
109
+ const { t } = useTranslation();
110
+ const [errors, setErrors] = useState({});
111
+ const [name, setName] = useState(groupName);
112
+ const [patientList, setPatientList] = useState(patients || []);
113
+ const { post, result, error } = usePostCohort();
114
+ const config = useConfig();
115
+
116
+ const removePatient = useCallback(
117
+ (patientUuid: string) =>
118
+ setPatientList((patientList) => patientList.filter((patient) => patient.uuid !== patientUuid)),
119
+ [setPatientList],
120
+ );
121
+
122
+ const validate = useCallback(
123
+ (field?: string | undefined) => {
124
+ let valid = true;
125
+ if (field) {
126
+ valid = field === 'name' ? !!name : !!patientList.length;
127
+ setErrors((errors) => ({
128
+ ...errors,
129
+ [field]: valid ? null : 'required',
130
+ }));
131
+ } else {
132
+ if (!name) {
133
+ setErrors((errors) => ({ ...errors, name: 'required' }));
134
+ valid = false;
135
+ } else {
136
+ setErrors((errors) => ({ ...errors, name: null }));
137
+ }
138
+ if (!patientList.length) {
139
+ setErrors((errors) => ({ ...errors, patientList: 'required' }));
140
+ valid = false;
141
+ } else {
142
+ setErrors((errors) => ({ ...errors, patientList: null }));
143
+ }
144
+ }
145
+ return valid;
146
+ },
147
+ [name, patientList.length],
148
+ );
149
+
150
+ const updatePatientList = useCallback(
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
+ }
167
+ setErrors((errors) => ({ ...errors, patientList: null }));
168
+ },
169
+ [patientList, setPatientList],
170
+ );
171
+
172
+ const handleSubmit = () => {
173
+ if (validate()) {
174
+ post({
175
+ uuid: cohortUuid,
176
+ name: name,
177
+ cohortType: config?.groupSessionConcepts?.cohortTypeId,
178
+ cohortMembers: patientList.map((p) => ({ patient: p.uuid })),
179
+ });
180
+ if (onPostSubmit) {
181
+ onPostSubmit();
182
+ }
183
+ }
184
+ };
185
+
186
+ const handleCancel = () => {
187
+ setPatientList(patients || []);
188
+ if (onPostCancel) {
189
+ onPostCancel();
190
+ }
191
+ };
192
+
193
+ useEffect(() => {
194
+ if (result) {
195
+ setGroup({
196
+ ...result,
197
+ // the result doesn't come with cohortMembers.
198
+ // need to add it in based on our local state
199
+ cohortMembers: patientList.map((p) => ({ patient: { uuid: p.uuid } })),
200
+ });
201
+ }
202
+ }, [result, setGroup, patientList]);
203
+
204
+ useEffect(() => {
205
+ if (error) {
206
+ showToast({
207
+ kind: 'error',
208
+ title: t('postError', 'POST Error'),
209
+ description: error.message ?? t('unknownPostError', 'An unknown error occurred while saving data'),
210
+ });
211
+ if (error.fieldErrors) {
212
+ setErrors(
213
+ Object.fromEntries(Object.entries(error.fieldErrors).map(([key, value]) => [key, value?.[0]?.message])),
214
+ );
215
+ }
216
+ }
217
+ }, [error, t]);
218
+
219
+ return (
220
+ <div className={styles.modal}>
221
+ <ComposedModal open={isOpen} onClose={handleCancel}>
222
+ <ModalHeader>{isCreate ? t('createNewGroup', 'Create New Group') : t('editGroup', 'Edit Group')}</ModalHeader>
223
+ <ModalBody>
224
+ <NewGroupForm
225
+ {...{
226
+ name,
227
+ setName,
228
+ patientList,
229
+ updatePatientList,
230
+ errors,
231
+ validate,
232
+ removePatient,
233
+ }}
234
+ />
235
+ </ModalBody>
236
+ <ModalFooter>
237
+ <Button kind="secondary" onClick={handleCancel}>
238
+ {t('cancel', 'Cancel')}
239
+ </Button>
240
+ <Button kind="primary" onClick={handleSubmit}>
241
+ {isCreate ? t('createGroup', 'Create Group') : t('save', 'Save')}
242
+ </Button>
243
+ </ModalFooter>
244
+ </ComposedModal>
245
+ </div>
246
+ );
247
+ };
248
+
249
+ export default AddGroupModal;
@@ -0,0 +1,49 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+
4
+ .modal {
5
+ :global(.cds--modal) {
6
+ z-index: 90;
7
+ }
8
+ :global(.cds--modal-container) {
9
+ height: 600px;
10
+ }
11
+ :global(.cds--modal-content) {
12
+ height: 100%;
13
+ }
14
+ }
15
+
16
+ .searchBar > div > div > div {
17
+ width: 100%
18
+ }
19
+
20
+ .searchBar > div button {
21
+ height: auto;
22
+ }
23
+
24
+ .formError {
25
+ color: red;
26
+ }
27
+
28
+ .patientRow {
29
+ display: flex;
30
+ align-items: center;
31
+ width: "100%";
32
+ &:nth-child(odd) {
33
+ background-color: colors.$gray-20;
34
+ }
35
+ }
36
+
37
+ .patientName {
38
+ flex-grow: 1;
39
+ padding-left: layout.$spacing-05;
40
+ }
41
+
42
+ .loading {
43
+ display: flex;
44
+ height: 100%;
45
+ flex-direction: column;
46
+ justify-content: center;
47
+ align-items: center;
48
+ row-gap: layout.$spacing-05;
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,8 +1,10 @@
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
- formUuid: string;
7
+ formUuid?: string;
6
8
  }
7
9
 
8
10
  const initialActions = {
@@ -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}