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

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 (148) hide show
  1. package/README.md +21 -2
  2. package/dist/101.js +1 -0
  3. package/dist/101.js.map +1 -0
  4. package/dist/132.js +1 -1
  5. package/dist/143.js +1 -0
  6. package/dist/143.js.map +1 -0
  7. package/dist/188.js +1 -0
  8. package/dist/188.js.map +1 -0
  9. package/dist/197.js +1 -0
  10. package/dist/219.js +1 -0
  11. package/dist/219.js.map +1 -0
  12. package/dist/221.js +1 -0
  13. package/dist/221.js.map +1 -0
  14. package/dist/259.js +1 -0
  15. package/dist/259.js.map +1 -0
  16. package/dist/29.js +2 -0
  17. package/dist/29.js.LICENSE.txt +3 -0
  18. package/dist/29.js.map +1 -0
  19. package/dist/300.js +1 -0
  20. package/dist/31.js +2 -0
  21. package/dist/{569.js.LICENSE.txt → 31.js.LICENSE.txt} +9 -6
  22. package/dist/31.js.map +1 -0
  23. package/dist/326.js +1 -0
  24. package/dist/326.js.map +1 -0
  25. package/dist/335.js +1 -0
  26. package/dist/367.js +1 -0
  27. package/dist/367.js.map +1 -0
  28. package/dist/480.js +1 -0
  29. package/dist/491.js +1 -0
  30. package/dist/491.js.map +1 -0
  31. package/dist/540.js +2 -0
  32. package/dist/540.js.map +1 -0
  33. package/dist/55.js +1 -0
  34. package/dist/564.js +1 -0
  35. package/dist/564.js.map +1 -0
  36. package/dist/602.js +1 -0
  37. package/dist/602.js.map +1 -0
  38. package/dist/626.js +2 -0
  39. package/dist/626.js.LICENSE.txt +9 -0
  40. package/dist/626.js.map +1 -0
  41. package/dist/652.js +1 -0
  42. package/dist/685.js +1 -0
  43. package/dist/685.js.map +1 -0
  44. package/dist/773.js +2 -0
  45. package/dist/{68.js.LICENSE.txt → 773.js.LICENSE.txt} +13 -2
  46. package/dist/773.js.map +1 -0
  47. package/dist/91.js +1 -0
  48. package/dist/91.js.map +1 -0
  49. package/dist/961.js +2 -0
  50. package/dist/961.js.map +1 -0
  51. package/dist/99.js +1 -0
  52. package/dist/99.js.map +1 -0
  53. package/dist/main.js +1 -1
  54. package/dist/main.js.map +1 -0
  55. package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
  56. package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +403 -136
  57. package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -0
  58. package/dist/routes.json +1 -0
  59. package/jest.config.json +2 -1
  60. package/package.json +42 -37
  61. package/src/CancelModal.tsx +48 -0
  62. package/src/CompleteModal.tsx +46 -0
  63. package/src/FormBootstrap.tsx +32 -4
  64. package/src/add-group-modal/AddGroupModal.tsx +110 -60
  65. package/src/add-group-modal/styles.scss +7 -3
  66. package/src/config-schema.ts +62 -0
  67. package/src/context/FormWorkflowContext.tsx +13 -1
  68. package/src/context/FormWorkflowReducer.ts +13 -3
  69. package/src/context/GroupFormWorkflowContext.tsx +43 -6
  70. package/src/context/GroupFormWorkflowReducer.ts +160 -15
  71. package/src/declarations.d.ts +4 -0
  72. package/src/empty-state/styles.scss +14 -14
  73. package/src/form-entry-workflow/FormEntryWorkflow.tsx +74 -102
  74. package/src/form-entry-workflow/form-review-card/styles.scss +9 -11
  75. package/src/form-entry-workflow/patient-banner/styles.scss +11 -12
  76. package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +2 -2
  77. package/src/form-entry-workflow/patient-search-header/styles.scss +13 -10
  78. package/src/form-entry-workflow/styles.scss +13 -14
  79. package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +5 -3
  80. package/src/form-entry-workflow/workflow-review/styles.scss +0 -4
  81. package/src/forms-page/FormsPage.tsx +10 -5
  82. package/src/forms-page/forms-table/FormsTable.tsx +11 -5
  83. package/src/forms-page/forms-table/styles.scss +4 -5
  84. package/src/forms-page/styles.scss +3 -5
  85. package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +12 -399
  86. package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +238 -0
  87. package/src/group-form-entry-workflow/SessionDetailsForm.tsx +177 -0
  88. package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +107 -0
  89. package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +144 -0
  90. package/src/group-form-entry-workflow/attendance-table/index.ts +1 -0
  91. package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +47 -0
  92. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +1 -9
  93. package/src/group-form-entry-workflow/group-display-header/styles.scss +20 -20
  94. package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +1 -1
  95. package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +1 -1
  96. package/src/group-form-entry-workflow/group-search/compact-group-result.scss +16 -17
  97. package/src/group-form-entry-workflow/group-search/compact-group-search.scss +7 -8
  98. package/src/group-form-entry-workflow/group-search/group-search.scss +20 -23
  99. package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +36 -6
  100. package/src/group-form-entry-workflow/group-search-header/styles.scss +8 -8
  101. package/src/group-form-entry-workflow/styles.scss +15 -17
  102. package/src/hooks/index.ts +8 -1
  103. package/src/hooks/useForm.ts +73 -0
  104. package/src/hooks/useGetAllForms.ts +3 -2
  105. package/src/hooks/useGetEncounter.ts +2 -2
  106. package/src/hooks/useGetPatient.ts +1 -1
  107. package/src/hooks/useGetPatients.ts +34 -0
  108. package/src/hooks/useGetSystemSetting.ts +38 -0
  109. package/src/hooks/usePostEndpoint.ts +10 -4
  110. package/src/hooks/useSearchEndpoint.ts +14 -8
  111. package/src/hooks/useStartVisit.ts +93 -0
  112. package/src/index.ts +13 -65
  113. package/src/patient-card/styles.scss +3 -4
  114. package/src/routes.json +24 -0
  115. package/src/types.ts +20 -0
  116. package/tools/i18next-parser.config.js +93 -0
  117. package/translations/am.json +75 -0
  118. package/translations/ar.json +75 -0
  119. package/translations/en.json +32 -11
  120. package/translations/es.json +75 -0
  121. package/translations/fr.json +75 -0
  122. package/translations/he.json +75 -0
  123. package/translations/km.json +75 -0
  124. package/turbo.json +18 -0
  125. package/dist/247.js +0 -1
  126. package/dist/255.js +0 -1
  127. package/dist/294.js +0 -2
  128. package/dist/32.js +0 -1
  129. package/dist/327.js +0 -1
  130. package/dist/403.js +0 -2
  131. package/dist/403.js.LICENSE.txt +0 -14
  132. package/dist/553.js +0 -2
  133. package/dist/553.js.LICENSE.txt +0 -14
  134. package/dist/569.js +0 -2
  135. package/dist/574.js +0 -1
  136. package/dist/595.js +0 -2
  137. package/dist/595.js.LICENSE.txt +0 -1
  138. package/dist/617.js +0 -1
  139. package/dist/68.js +0 -2
  140. package/dist/776.js +0 -1
  141. package/dist/804.js +0 -1
  142. package/dist/820.js +0 -1
  143. package/dist/906.js +0 -1
  144. package/dist/935.js +0 -2
  145. package/dist/openmrs-esm-fast-data-entry-app.old +0 -1
  146. package/src/declarations.d.tsx +0 -2
  147. /package/dist/{294.js.LICENSE.txt → 540.js.LICENSE.txt} +0 -0
  148. /package/dist/{935.js.LICENSE.txt → 961.js.LICENSE.txt} +0 -0
@@ -60,6 +60,68 @@ export const configSchema = {
60
60
  },
61
61
  _default: ["ICRC Forms", "Distress Scales"],
62
62
  },
63
+ groupSessionConcepts: {
64
+ sessionName: {
65
+ _type: Type.UUID,
66
+ _description: "UUID of concept for Session Name",
67
+ _default: "e2559620-900b-4f66-ae41-0b9c4adfb654",
68
+ },
69
+ sessionDate: {
70
+ _type: Type.UUID,
71
+ _description: "UUID of concept for Session Date",
72
+ _default: "ceaca505-6dff-4940-8a43-8c060a0924d7",
73
+ },
74
+ practitionerName: {
75
+ _type: Type.UUID,
76
+ _description: "UUID of concept for Practitioner Name",
77
+ _default: "f1a2d58c-1a0e-4148-931a-aac224649fdc",
78
+ },
79
+ sessionNotes: {
80
+ _type: Type.UUID,
81
+ _description: "UUID of concept for Session Notes",
82
+ _default: "fa8fedc0-c066-4da3-8dc1-2ad8621fc480",
83
+ },
84
+ cohortTypeId: {
85
+ _type: Type.UUID,
86
+ _description: "UUID of cohort type",
87
+ _default: "eee9970e-7ca0-4e8c-a280-c33e9d5f6a04",
88
+ },
89
+ cohortId: {
90
+ _type: Type.UUID,
91
+ _description: "UUID of concept for cohort identifier",
92
+ _default: "5461f231-7e59-4be8-93a4-6d49fd13c00a",
93
+ },
94
+ cohortName: {
95
+ _type: Type.UUID,
96
+ _description: "UUID of concept for cohort name",
97
+ _default: "6029f289-92a6-4a68-80f1-3078d0152449",
98
+ },
99
+ sessionUuid: {
100
+ _type: Type.UUID,
101
+ _description: "UUID of concept for session identifier",
102
+ _default: "6a803908-8a5b-4598-adea-19358c83529a",
103
+ },
104
+ },
105
+ specificQuestions: {
106
+ _type: Type.Array,
107
+ _description: "List of specific questions to populate forms.",
108
+ _elements: {
109
+ forms: {
110
+ _type: Type.Array,
111
+ _description: "List of form UUIDs for which the question applies.",
112
+ _elements: {
113
+ _type: Type.UUID,
114
+ },
115
+ _default: [],
116
+ },
117
+ questionId: {
118
+ _type: Type.String,
119
+ _description: "ID of the question.",
120
+ _default: "",
121
+ },
122
+ },
123
+ _default: [],
124
+ },
63
125
  };
64
126
 
65
127
  export type Form = {
@@ -1,6 +1,8 @@
1
1
  import React, { useEffect, useMemo, useReducer } from "react";
2
2
  import reducer from "./FormWorkflowReducer";
3
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,6 +42,7 @@ 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
47
  const activeFormUuid = formUuid.split("&")[0];
43
48
  const { search } = useLocation();
@@ -46,6 +51,11 @@ const FormWorkflowProvider = ({ children }) => {
46
51
  ...initialWorkflowState,
47
52
  ...initialActions,
48
53
  });
54
+ const systemSetting = useGetSystemSetting(
55
+ "@openmrs/esm-fast-data-entry-app.groupSessionVisitTypeUuid"
56
+ );
57
+ const singleSessionVisitTypeUuid =
58
+ systemSetting?.result?.data?.results?.[0]?.value;
49
59
 
50
60
  const actions = useMemo(
51
61
  () => ({
@@ -54,6 +64,7 @@ const FormWorkflowProvider = ({ children }) => {
54
64
  type: "INITIALIZE_WORKFLOW_STATE",
55
65
  activeFormUuid,
56
66
  newPatientUuid,
67
+ userUuid: user.uuid,
57
68
  }),
58
69
  addPatient: (patientUuid) =>
59
70
  dispatch({ type: "ADD_PATIENT", patientUuid }),
@@ -72,7 +83,7 @@ const FormWorkflowProvider = ({ children }) => {
72
83
  destroySession: () => dispatch({ type: "DESTROY_SESSION" }),
73
84
  closeSession: () => dispatch({ type: "CLOSE_SESSION" }),
74
85
  }),
75
- []
86
+ [user]
76
87
  );
77
88
 
78
89
  // if formUuid isn't a part of state yet, grab it from the url params
@@ -103,6 +114,7 @@ const FormWorkflowProvider = ({ children }) => {
103
114
  encounters:
104
115
  state.forms?.[state.activeFormUuid]?.encounters ??
105
116
  initialWorkflowState.encounters,
117
+ singleSessionVisitTypeUuid,
106
118
  }}
107
119
  >
108
120
  {children}
@@ -1,10 +1,13 @@
1
1
  import { navigate } from "@openmrs/esm-framework";
2
2
  import { initialWorkflowState } from "./FormWorkflowContext";
3
3
 
4
- export const fdeWorkflowStorageVersion = "1.0.13";
4
+ export const fdeWorkflowStorageVersion = "1.1.0";
5
5
  export const fdeWorkflowStorageName = "openmrs:fastDataEntryWorkflowState";
6
6
  const persistData = (data) => {
7
- localStorage.setItem(fdeWorkflowStorageName, JSON.stringify(data));
7
+ localStorage.setItem(
8
+ fdeWorkflowStorageName + ":" + data.userUuid,
9
+ JSON.stringify(data)
10
+ );
8
11
  };
9
12
 
10
13
  const initialFormState = {
@@ -18,7 +21,9 @@ const initialFormState = {
18
21
  const reducer = (state, action) => {
19
22
  switch (action.type) {
20
23
  case "INITIALIZE_WORKFLOW_STATE": {
21
- const savedData = localStorage.getItem(fdeWorkflowStorageName);
24
+ const savedData = localStorage.getItem(
25
+ fdeWorkflowStorageName + ":" + action.userUuid
26
+ );
22
27
  const savedDataObject = savedData ? JSON.parse(savedData) : {};
23
28
  let newState: { [key: string]: unknown } = {};
24
29
  const newPatient = action.newPatientUuid
@@ -69,6 +74,7 @@ const reducer = (state, action) => {
69
74
  [action.activeFormUuid]: initialFormState,
70
75
  },
71
76
  activeFormUuid: action.activeFormUuid,
77
+ userUuid: action.userUuid,
72
78
  };
73
79
  }
74
80
  persistData(newState);
@@ -259,6 +265,8 @@ const reducer = (state, action) => {
259
265
  activeFormUuid: null,
260
266
  };
261
267
  persistData(newState);
268
+ //eslint-disable-next-line
269
+ navigate({ to: "${openmrsSpaBase}/forms" });
262
270
  return newState;
263
271
  }
264
272
  case "CLOSE_SESSION": {
@@ -267,6 +275,8 @@ const reducer = (state, action) => {
267
275
  activeFormUuid: null,
268
276
  };
269
277
  persistData(newState);
278
+ //eslint-disable-next-line
279
+ navigate({ to: "${openmrsSpaBase}/forms" });
270
280
  return newState;
271
281
  }
272
282
  default:
@@ -1,7 +1,8 @@
1
1
  import React, { useEffect, useMemo, useReducer } from "react";
2
2
  import reducer from "./GroupFormWorkflowReducer";
3
3
  import { useParams } from "react-router-dom";
4
- import { Type } from "@openmrs/esm-framework";
4
+ import { type Type, useSession } from "@openmrs/esm-framework";
5
+ import useGetSystemSetting from "../hooks/useGetSystemSetting";
5
6
  interface ParamTypes {
6
7
  formUuid?: string;
7
8
  }
@@ -25,9 +26,14 @@ const initialActions = {
25
26
  openPatientSearch: () => undefined,
26
27
  saveEncounter: (encounterUuid: string | number) => undefined,
27
28
  editEncounter: (patientUuid: string | number) => undefined,
28
- submitForNext: () => undefined,
29
+ validateForNext: () => undefined,
30
+ validateForComplete: () => undefined,
31
+ updateVisitUuid: (visitUuid: string) => undefined,
32
+ submitForNext: (nextPatientUuid: string = null) => undefined,
29
33
  submitForReview: () => undefined,
30
34
  submitForComplete: () => undefined,
35
+ addPatientUuid: (patientUuid: string) => undefined,
36
+ removePatientUuid: (patientUuid: string) => undefined,
31
37
  goToReview: () => undefined,
32
38
  destroySession: () => undefined,
33
39
  closeSession: () => undefined,
@@ -42,17 +48,23 @@ export const initialWorkflowState = {
42
48
  // aciveFormUuid
43
49
  workflowState: null, // pseudo field from state[activeFormUuid].workflowState
44
50
  activePatientUuid: null, // pseudo field from state[activeFormUuid].activePatientUuid
45
- activeEncounterUuid: null, // pseudo field from state[activeFormUuid].encounterUuid
51
+ activeEncounterUuid: null, // pseudo field from state[activeFormUuid].activeEncounterUuid
52
+ activeSessionUuid: null, // pseudo field from state[activeFormUuid].activeSessionUuid
53
+ activeVisitUuid: null, // pseudo field from state[activeFormUuid].activeVisitUuid
46
54
  patientUuids: [], // pseudo field from state[activeFormUuid].patientUuids
47
55
  encounters: {}, // pseudo field from state[activeFormUuid].encounters
56
+ visits: {}, // pseudo field from state[activeFormUuid].visits
48
57
  activeGroupUuid: null, // pseudo field from state[activeFormUuid].groupUuid
49
- activeGroupName: null, // pseudo field from state[activeFormUuid].groupname
58
+ activeGroupName: null, // pseudo field from state[activeFormUuid].groupName
59
+ activeGroupMembers: [], // pseudo field from state[activeFormUuid].groupMembers
50
60
  activeSessionMeta: {
51
61
  sessionName: null,
52
62
  practitionerName: null,
53
63
  sessionDate: null,
54
64
  sessionNotes: null,
55
65
  },
66
+ groupVisitTypeUuid: null,
67
+ userUuid: null, // UUID of the user to which this workflow state belongs to
56
68
  };
57
69
 
58
70
  const GroupFormWorkflowContext = React.createContext({
@@ -61,8 +73,13 @@ const GroupFormWorkflowContext = React.createContext({
61
73
  });
62
74
 
63
75
  const GroupFormWorkflowProvider = ({ children }) => {
76
+ const { user } = useSession();
64
77
  const { formUuid } = useParams() as ParamTypes;
65
78
  const activeFormUuid = formUuid.split("&")[0];
79
+ const systemSetting = useGetSystemSetting(
80
+ "@openmrs/esm-fast-data-entry-app.groupSessionVisitTypeUuid"
81
+ );
82
+ const groupVisitTypeUuid = systemSetting?.result?.data?.results?.[0]?.value;
66
83
  const [state, dispatch] = useReducer(reducer, {
67
84
  ...initialWorkflowState,
68
85
  ...initialActions,
@@ -74,17 +91,27 @@ const GroupFormWorkflowProvider = ({ children }) => {
74
91
  dispatch({
75
92
  type: "INITIALIZE_WORKFLOW_STATE",
76
93
  activeFormUuid,
94
+ userUuid: user.uuid,
77
95
  }),
78
96
  setGroup: (group) => dispatch({ type: "SET_GROUP", group }),
79
97
  unsetGroup: () => dispatch({ type: "UNSET_GROUP" }),
80
98
  setSessionMeta: (meta) => dispatch({ type: "SET_SESSION_META", meta }),
99
+ addPatientUuid: (patientUuid) =>
100
+ dispatch({ type: "ADD_PATIENT_UUID", patientUuid }),
101
+ removePatientUuid: (patientUuid) =>
102
+ dispatch({ type: "REMOVE_PATIENT_UUID", patientUuid }),
81
103
  openPatientSearch: () => dispatch({ type: "OPEN_PATIENT_SEARCH" }),
82
104
  saveEncounter: (encounterUuid) =>
83
105
  dispatch({
84
106
  type: "SAVE_ENCOUNTER",
85
107
  encounterUuid,
86
108
  }),
87
- submitForNext: () => dispatch({ type: "SUBMIT_FOR_NEXT" }),
109
+ validateForNext: () => dispatch({ type: "VALIDATE_FOR_NEXT" }),
110
+ validateForComplete: () => dispatch({ type: "VALIDATE_FOR_COMPLETE" }),
111
+ updateVisitUuid: (visitUuid) =>
112
+ dispatch({ type: "UPDATE_VISIT_UUID", visitUuid }),
113
+ submitForNext: (nextPatientUuid) =>
114
+ dispatch({ type: "SUBMIT_FOR_NEXT", nextPatientUuid }),
88
115
  submitForComplete: () => dispatch({ type: "SUBMIT_FOR_COMPLETE" }),
89
116
  editEncounter: (patientUuid) =>
90
117
  dispatch({ type: "EDIT_ENCOUNTER", patientUuid }),
@@ -92,7 +119,7 @@ const GroupFormWorkflowProvider = ({ children }) => {
92
119
  destroySession: () => dispatch({ type: "DESTROY_SESSION" }),
93
120
  closeSession: () => dispatch({ type: "CLOSE_SESSION" }),
94
121
  }),
95
- []
122
+ [user]
96
123
  );
97
124
 
98
125
  // if formUuid isn't a part of state yet, grab it from the url params
@@ -106,17 +133,24 @@ const GroupFormWorkflowProvider = ({ children }) => {
106
133
  return (
107
134
  <GroupFormWorkflowContext.Provider
108
135
  value={{
136
+ groupVisitTypeUuid,
109
137
  ...state,
110
138
  ...actions,
111
139
  workflowState:
112
140
  state.forms?.[state.activeFormUuid]?.workflowState ??
113
141
  initialWorkflowState.workflowState,
142
+ activeSessionUuid:
143
+ state.forms?.[state.activeFormUuid]?.activeSessionUuid ??
144
+ initialWorkflowState.activeSessionUuid,
114
145
  activePatientUuid:
115
146
  state.forms?.[state.activeFormUuid]?.activePatientUuid ??
116
147
  initialWorkflowState.activePatientUuid,
117
148
  activeEncounterUuid:
118
149
  state.forms?.[state.activeFormUuid]?.activeEncounterUuid ??
119
150
  initialWorkflowState.activeEncounterUuid,
151
+ activeVisitUuid:
152
+ state.forms?.[state.activeFormUuid]?.activeVisitUuid ??
153
+ initialWorkflowState.activeVisitUuid,
120
154
  patientUuids:
121
155
  state.forms?.[state.activeFormUuid]?.patientUuids ??
122
156
  initialWorkflowState.patientUuids,
@@ -129,6 +163,9 @@ const GroupFormWorkflowProvider = ({ children }) => {
129
163
  activeGroupName:
130
164
  state.forms?.[state.activeFormUuid]?.groupName ??
131
165
  initialWorkflowState.activeGroupName,
166
+ activeGroupMembers:
167
+ state.forms?.[state.activeFormUuid]?.groupMembers ??
168
+ initialWorkflowState.activeGroupMembers,
132
169
  activeSessionMeta:
133
170
  state.forms?.[state.activeFormUuid]?.sessionMeta ??
134
171
  initialWorkflowState.activeSessionMeta,
@@ -1,27 +1,37 @@
1
1
  import { navigate } from "@openmrs/esm-framework";
2
2
  import { initialWorkflowState } from "./FormWorkflowContext";
3
+ import { v4 as uuid } from "uuid";
3
4
 
4
5
  export const fdeGroupWorkflowStorageVersion = "1.0.5";
5
6
  export const fdeGroupWorkflowStorageName =
6
7
  "openmrs:fastDataEntryGroupWorkflowState";
7
8
  const persistData = (data) => {
8
- localStorage.setItem(fdeGroupWorkflowStorageName, JSON.stringify(data));
9
+ localStorage.setItem(
10
+ fdeGroupWorkflowStorageName + ":" + data.userUuid,
11
+ JSON.stringify(data)
12
+ );
9
13
  };
10
14
 
11
15
  const initialFormState = {
12
16
  workflowState: "NEW_GROUP_SESSION",
13
17
  groupUuid: null,
14
18
  groupName: null,
19
+ groupMembers: [],
15
20
  activePatientUuid: null,
16
21
  activeEncounterUuid: null,
22
+ activeVisitUuid: null,
23
+ activeSessionUuid: null,
17
24
  patientUuids: [],
18
25
  encounters: {},
26
+ visits: {},
19
27
  };
20
28
 
21
29
  const reducer = (state, action) => {
22
30
  switch (action.type) {
23
31
  case "INITIALIZE_WORKFLOW_STATE": {
24
- const savedData = localStorage.getItem(fdeGroupWorkflowStorageName);
32
+ const savedData = localStorage.getItem(
33
+ fdeGroupWorkflowStorageName + ":" + action.userUuid
34
+ );
25
35
  const savedDataObject = savedData ? JSON.parse(savedData) : {};
26
36
  let newState: { [key: string]: unknown } = {};
27
37
  if (
@@ -37,6 +47,7 @@ const reducer = (state, action) => {
37
47
  thisSavedForm?.patientUuids?.[0] ||
38
48
  // something probably went wrong...
39
49
  null;
50
+ const activeSessionUuid = thisSavedForm?.activeSessionUuid || uuid();
40
51
  newState = {
41
52
  ...savedDataObject,
42
53
  // set current form to this one
@@ -50,6 +61,9 @@ const reducer = (state, action) => {
50
61
  activePatientUuid: activePatientUuid,
51
62
  activeEncounterUuid:
52
63
  thisSavedForm?.encounters?.[activePatientUuid] || null,
64
+ activeVisitUuid:
65
+ thisSavedForm?.visits?.[activePatientUuid] || null,
66
+ activeSessionUuid: activeSessionUuid,
53
67
  },
54
68
  },
55
69
  };
@@ -62,6 +76,7 @@ const reducer = (state, action) => {
62
76
  [action.activeFormUuid]: initialFormState,
63
77
  },
64
78
  activeFormUuid: action.activeFormUuid,
79
+ userUuid: action.userUuid,
65
80
  };
66
81
  }
67
82
  persistData(newState);
@@ -84,8 +99,14 @@ const reducer = (state, action) => {
84
99
  action.group.cohortMembers?.map(
85
100
  (member) => member?.patient?.uuid
86
101
  ) ?? [],
102
+ groupMembers:
103
+ action.group.cohortMembers?.map(
104
+ (member) => member?.patient?.uuid
105
+ ) ?? [],
87
106
  activePatientUuid: null,
88
107
  activeEncounterUuid: null,
108
+ activeVisitUuid: null,
109
+ activeSessionUuid: null,
89
110
  },
90
111
  },
91
112
  };
@@ -102,8 +123,11 @@ const reducer = (state, action) => {
102
123
  groupUuid: null,
103
124
  groupName: null,
104
125
  patientUuids: [],
126
+ groupMembers: [],
105
127
  activePatientUuid: null,
106
128
  activeEncounterUuid: null,
129
+ activeVisitUuid: null,
130
+ activeSessionUuid: null,
107
131
  },
108
132
  },
109
133
  };
@@ -125,6 +149,11 @@ const reducer = (state, action) => {
125
149
  state.forms[state.activeFormUuid].encounters[
126
150
  state.forms[state.activeFormUuid].patientUuids?.[0]
127
151
  ] || null,
152
+ activeVisitUuid:
153
+ state.forms[state.activeFormUuid].visits[
154
+ state.forms[state.activeFormUuid].patientUuids?.[0]
155
+ ] || null,
156
+ activeSessionUuid: uuid(),
128
157
  workflowState: "EDIT_FORM",
129
158
  },
130
159
  },
@@ -132,7 +161,47 @@ const reducer = (state, action) => {
132
161
  persistData(newState);
133
162
  return newState;
134
163
  }
164
+ case "ADD_PATIENT_UUID": {
165
+ if (
166
+ state.forms[state.activeFormUuid].patientUuids.includes(
167
+ action.patientUuid
168
+ )
169
+ ) {
170
+ return state;
171
+ }
135
172
 
173
+ const newState = {
174
+ ...state,
175
+ forms: {
176
+ ...state.forms,
177
+ [state.activeFormUuid]: {
178
+ ...state.forms[state.activeFormUuid],
179
+ patientUuids: [
180
+ ...state.forms[state.activeFormUuid].patientUuids,
181
+ action.patientUuid,
182
+ ],
183
+ },
184
+ },
185
+ };
186
+ persistData(newState);
187
+ return newState;
188
+ }
189
+ case "REMOVE_PATIENT_UUID": {
190
+ const newState = {
191
+ ...state,
192
+ forms: {
193
+ ...state.forms,
194
+ [state.activeFormUuid]: {
195
+ ...state.forms[state.activeFormUuid],
196
+ patientUuids: state.forms[
197
+ state.activeFormUuid
198
+ ].patientUuids?.filter((uuid) => action.patientUuid !== uuid),
199
+ },
200
+ },
201
+ };
202
+ persistData(newState);
203
+ return newState;
204
+ }
136
205
  case "SAVE_ENCOUNTER": {
137
206
  const thisForm = state.forms[state.activeFormUuid];
138
207
  if (thisForm.workflowState === "SUBMIT_FOR_COMPLETE") {
@@ -147,25 +216,29 @@ const reducer = (state, action) => {
147
216
  navigate({ to: "${openmrsSpaBase}/forms" });
148
217
  return newState;
149
218
  } else if (thisForm.workflowState === "SUBMIT_FOR_NEXT") {
150
- const nextPatientUuid =
151
- thisForm.patientUuids[
152
- Math.min(
153
- thisForm.patientUuids.indexOf(thisForm.activePatientUuid) + 1,
154
- thisForm.patientUuids.length - 1
155
- )
156
- ];
219
+ const nextPatientUuid = state.nextPatientUuid
220
+ ? state.nextPatientUuid
221
+ : thisForm.patientUuids[
222
+ Math.min(
223
+ thisForm.patientUuids.indexOf(thisForm.activePatientUuid) + 1,
224
+ thisForm.patientUuids.length - 1
225
+ )
226
+ ];
227
+ const encounters = {
228
+ ...thisForm.encounters,
229
+ [thisForm.activePatientUuid]: action.encounterUuid,
230
+ };
157
231
  const newState = {
158
232
  ...state,
159
233
  forms: {
160
234
  ...state.forms,
161
235
  [state.activeFormUuid]: {
162
236
  ...thisForm,
163
- encounters: {
164
- ...thisForm.encounters,
165
- [thisForm.activePatientUuid]: action.encounterUuid,
166
- },
237
+ encounters,
167
238
  activePatientUuid: nextPatientUuid,
168
- activeEncounterUuid: thisForm.encounters[nextPatientUuid] || null,
239
+ activeEncounterUuid: encounters[nextPatientUuid] || null,
240
+ activeVisitUuid: thisForm.visits[nextPatientUuid] || null,
241
+ activeSessionUuid: thisForm.activeSessionUuid,
169
242
  workflowState: "EDIT_FORM",
170
243
  },
171
244
  },
@@ -183,7 +256,10 @@ const reducer = (state, action) => {
183
256
  ...state.forms[state.activeFormUuid],
184
257
  activeEncounterUuid:
185
258
  state.forms[state.activeFormUuid].encounters[action.patientUuid],
259
+ activeVisitUuid:
260
+ state.forms[state.activeFormUuid].visits[action.patientUuid],
186
261
  activePatientUuid: action.patientUuid,
262
+ activeSessionUuid: action.activeSessionUuid,
187
263
  workflowState: "EDIT_FORM",
188
264
  },
189
265
  },
@@ -191,6 +267,46 @@ const reducer = (state, action) => {
191
267
  persistData(newState);
192
268
  return newState;
193
269
  }
270
+ case "VALIDATE_FOR_NEXT":
271
+ // this state should not be persisted
272
+ window.dispatchEvent(
273
+ new CustomEvent("ampath-form-action", {
274
+ detail: {
275
+ formUuid: state.activeFormUuid,
276
+ patientUuid: state.forms[state.activeFormUuid].activePatientUuid,
277
+ action: "validateForm",
278
+ },
279
+ })
280
+ );
281
+ return {
282
+ ...state,
283
+ forms: {
284
+ ...state.forms,
285
+ [state.activeFormUuid]: {
286
+ ...state.forms[state.activeFormUuid],
287
+ workflowState: "VALIDATE_FOR_NEXT",
288
+ },
289
+ },
290
+ };
291
+ case "UPDATE_VISIT_UUID":
292
+ // this state should not be persisted
293
+ // we don't pers
294
+ return {
295
+ ...state,
296
+ forms: {
297
+ ...state.forms,
298
+ [state.activeFormUuid]: {
299
+ ...state.forms[state.activeFormUuid],
300
+ visits: {
301
+ ...state.forms[state.activeFormUuid].visits,
302
+ [state.forms[state.activeFormUuid].activePatientUuid]:
303
+ action.visitUuid,
304
+ },
305
+ activeVisitUuid: action.visitUuid,
306
+ },
307
+ },
308
+ };
309
+
194
310
  case "SUBMIT_FOR_NEXT":
195
311
  // this state should not be persisted
196
312
  window.dispatchEvent(
@@ -211,6 +327,7 @@ const reducer = (state, action) => {
211
327
  workflowState: "SUBMIT_FOR_NEXT",
212
328
  },
213
329
  },
330
+ nextPatientUuid: action.nextPatientUuid,
214
331
  };
215
332
  case "SUBMIT_FOR_REVIEW":
216
333
  // this state should not be persisted
@@ -233,6 +350,28 @@ const reducer = (state, action) => {
233
350
  },
234
351
  },
235
352
  };
353
+
354
+ case "VALIDATE_FOR_COMPLETE":
355
+ // this state should not be persisted
356
+ window.dispatchEvent(
357
+ new CustomEvent("ampath-form-action", {
358
+ detail: {
359
+ formUuid: state.activeFormUuid,
360
+ patientUuid: state.forms[state.activeFormUuid].activePatientUuid,
361
+ action: "validateForm",
362
+ },
363
+ })
364
+ );
365
+ return {
366
+ ...state,
367
+ forms: {
368
+ ...state.forms,
369
+ [state.activeFormUuid]: {
370
+ ...state.forms[state.activeFormUuid],
371
+ workflowState: "VALIDATE_FOR_COMPLETE",
372
+ },
373
+ },
374
+ };
236
375
  case "SUBMIT_FOR_COMPLETE":
237
376
  // this state should not be persisted
238
377
  window.dispatchEvent(
@@ -262,7 +401,9 @@ const reducer = (state, action) => {
262
401
  [state.activeFormUuid]: {
263
402
  ...state.forms[state.activeFormUuid],
264
403
  activeEncounterUuid: null,
404
+ activVisitUuid: null,
265
405
  activePatientUuid: null,
406
+ activeSessionUuid: null,
266
407
  workflowState: "REVIEW",
267
408
  },
268
409
  },
@@ -278,7 +419,9 @@ const reducer = (state, action) => {
278
419
  activeFormUuid: null,
279
420
  };
280
421
  persistData(newState);
281
- return newState;
422
+ //eslint-disable-next-line
423
+ navigate({ to: "${openmrsSpaBase}/forms" });
424
+ return { ...newState, formDestroyed: true };
282
425
  }
283
426
  case "CLOSE_SESSION": {
284
427
  const newState = {
@@ -286,6 +429,8 @@ const reducer = (state, action) => {
286
429
  activeFormUuid: null,
287
430
  };
288
431
  persistData(newState);
432
+ //eslint-disable-next-line
433
+ navigate({ to: "${openmrsSpaBase}/forms" });
289
434
  return newState;
290
435
  }
291
436
  default:
@@ -0,0 +1,4 @@
1
+ declare module "@carbon/react";
2
+ declare module "*.css";
3
+ declare module "*.scss";
4
+ declare type SideNavProps = object;
@@ -1,36 +1,36 @@
1
- @import "~@openmrs/esm-styleguide/src/vars";
2
- @import "~carbon-components/src/globals/scss/vars";
3
- @import "~carbon-components/src/globals/scss/mixins";
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/type';
4
4
 
5
5
  .action {
6
- margin-bottom: $spacing-03;
6
+ margin-bottom: layout.$spacing-03;
7
7
  }
8
8
 
9
9
  .content {
10
- @include carbon--type-style("productive-heading-01");
11
- color: $text-02;
12
- margin-top: $spacing-05;
13
- margin-bottom: $spacing-03;
10
+ @include type.type-style("heading-compact-01");
11
+ color: colors.$gray-70;
12
+ margin-top: layout.$spacing-05;
13
+ margin-bottom: layout.$spacing-03;
14
14
  }
15
15
 
16
16
  .desktopHeading {
17
17
  h4 {
18
- @include carbon--type-style('productive-heading-02');
19
- color: $text-02;
18
+ @include type.type-style('heading-compact-02');
19
+ color: colors.$gray-70;
20
20
  }
21
21
  }
22
22
 
23
23
  .tabletHeading {
24
24
  h4 {
25
- @include carbon--type-style('productive-heading-03');
26
- color: $text-02;
25
+ @include type.type-style('heading-03');
26
+ color: colors.$gray-70;
27
27
  }
28
28
  }
29
29
 
30
30
  .desktopHeading, .tabletHeading {
31
31
  text-align: left;
32
32
  text-transform: capitalize;
33
- margin-bottom: $spacing-05;
33
+ margin-bottom: layout.$spacing-05;
34
34
 
35
35
  h4:after {
36
36
  content: "";
@@ -51,5 +51,5 @@
51
51
 
52
52
  .tile {
53
53
  text-align: center;
54
- border: 1px solid $ui-03;
54
+ border: 1px solid colors.$gray-20;
55
55
  }