@openmrs/esm-fast-data-entry-app 1.0.1-pre.15 → 1.0.1-pre.159
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/README.md +21 -2
- package/dist/101.js +1 -0
- package/dist/101.js.map +1 -0
- package/dist/132.js +1 -0
- package/dist/143.js +1 -0
- package/dist/143.js.map +1 -0
- package/dist/188.js +1 -0
- package/dist/188.js.map +1 -0
- package/dist/197.js +1 -0
- package/dist/219.js +1 -0
- package/dist/219.js.map +1 -0
- package/dist/221.js +1 -0
- package/dist/221.js.map +1 -0
- package/dist/259.js +1 -0
- package/dist/259.js.map +1 -0
- package/dist/29.js +2 -0
- package/dist/29.js.LICENSE.txt +3 -0
- package/dist/29.js.map +1 -0
- package/dist/300.js +1 -0
- package/dist/31.js +2 -0
- package/dist/31.js.LICENSE.txt +30 -0
- package/dist/31.js.map +1 -0
- package/dist/326.js +1 -0
- package/dist/326.js.map +1 -0
- package/dist/335.js +1 -0
- package/dist/367.js +1 -0
- package/dist/367.js.map +1 -0
- package/dist/480.js +1 -0
- package/dist/491.js +1 -0
- package/dist/491.js.map +1 -0
- package/dist/540.js +2 -0
- package/dist/540.js.LICENSE.txt +9 -0
- package/dist/540.js.map +1 -0
- package/dist/55.js +1 -0
- package/dist/564.js +1 -0
- package/dist/564.js.map +1 -0
- package/dist/602.js +1 -0
- package/dist/602.js.map +1 -0
- package/dist/626.js +2 -0
- package/dist/626.js.LICENSE.txt +9 -0
- package/dist/626.js.map +1 -0
- package/dist/652.js +1 -0
- package/dist/685.js +1 -0
- package/dist/685.js.map +1 -0
- package/dist/773.js +2 -0
- package/dist/773.js.LICENSE.txt +32 -0
- package/dist/773.js.map +1 -0
- package/dist/91.js +1 -0
- package/dist/91.js.map +1 -0
- package/dist/961.js +2 -0
- package/dist/961.js.LICENSE.txt +19 -0
- package/dist/961.js.map +1 -0
- package/dist/99.js +1 -0
- package/dist/99.js.map +1 -0
- package/dist/main.js +1 -0
- package/dist/main.js.map +1 -0
- package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +811 -0
- package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -0
- package/dist/routes.json +1 -0
- package/jest.config.json +2 -1
- package/package.json +42 -37
- package/src/CancelModal.tsx +48 -0
- package/src/CompleteModal.tsx +46 -0
- package/src/FormBootstrap.tsx +30 -3
- package/src/add-group-modal/AddGroupModal.tsx +106 -61
- package/src/add-group-modal/styles.scss +7 -3
- package/src/config-schema.ts +57 -0
- package/src/context/FormWorkflowContext.tsx +13 -1
- package/src/context/FormWorkflowReducer.ts +13 -3
- package/src/context/GroupFormWorkflowContext.tsx +43 -6
- package/src/context/GroupFormWorkflowReducer.ts +154 -10
- package/src/declarations.d.ts +4 -0
- package/src/empty-state/styles.scss +14 -14
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +74 -102
- package/src/form-entry-workflow/form-review-card/styles.scss +9 -11
- package/src/form-entry-workflow/patient-banner/styles.scss +11 -12
- package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +2 -2
- package/src/form-entry-workflow/patient-search-header/styles.scss +13 -10
- package/src/form-entry-workflow/styles.scss +13 -14
- package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +5 -3
- package/src/form-entry-workflow/workflow-review/styles.scss +0 -4
- package/src/forms-page/FormsPage.tsx +10 -5
- package/src/forms-page/forms-table/FormsTable.tsx +11 -5
- package/src/forms-page/forms-table/styles.scss +4 -5
- package/src/forms-page/styles.scss +3 -5
- package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +12 -399
- package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +238 -0
- package/src/group-form-entry-workflow/SessionDetailsForm.tsx +177 -0
- package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +107 -0
- package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +144 -0
- package/src/group-form-entry-workflow/attendance-table/index.ts +1 -0
- package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +47 -0
- package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +1 -9
- package/src/group-form-entry-workflow/group-display-header/styles.scss +20 -20
- package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +1 -1
- package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +1 -1
- package/src/group-form-entry-workflow/group-search/compact-group-result.scss +16 -17
- package/src/group-form-entry-workflow/group-search/compact-group-search.scss +7 -8
- package/src/group-form-entry-workflow/group-search/group-search.scss +20 -23
- package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +33 -6
- package/src/group-form-entry-workflow/group-search-header/styles.scss +8 -8
- package/src/group-form-entry-workflow/styles.scss +15 -17
- package/src/hooks/index.ts +8 -1
- package/src/hooks/useForm.ts +73 -0
- package/src/hooks/useGetAllForms.ts +3 -2
- package/src/hooks/useGetEncounter.ts +2 -2
- package/src/hooks/useGetPatient.ts +1 -1
- package/src/hooks/useGetPatients.ts +34 -0
- package/src/hooks/useGetSystemSetting.ts +38 -0
- package/src/hooks/usePostEndpoint.ts +10 -4
- package/src/hooks/useSearchEndpoint.ts +14 -8
- package/src/hooks/useStartVisit.ts +93 -0
- package/src/index.ts +13 -65
- package/src/patient-card/styles.scss +3 -4
- package/src/routes.json +24 -0
- package/src/types.ts +20 -0
- package/tools/i18next-parser.config.js +93 -0
- package/translations/am.json +75 -0
- package/translations/ar.json +75 -0
- package/translations/en.json +32 -11
- package/translations/es.json +75 -0
- package/translations/fr.json +75 -0
- package/translations/he.json +75 -0
- package/translations/km.json +75 -0
- package/turbo.json +18 -0
- package/.editorconfig +0 -12
- package/.eslintignore +0 -2
- package/.eslintrc.js +0 -10
- package/.husky/pre-push +0 -1
- package/.prettierignore +0 -14
- package/.tx/config +0 -9
- package/.yarn/plugins/@yarnpkg/plugin-version.cjs +0 -550
- package/.yarn/versions/c1451405.yml +0 -0
- package/src/declarations.d.tsx +0 -2
package/src/config-schema.ts
CHANGED
|
@@ -60,6 +60,63 @@ 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
|
+
cohortId: {
|
|
85
|
+
_type: Type.UUID,
|
|
86
|
+
_description: "UUID of concept for cohort identifier",
|
|
87
|
+
_default: "5461f231-7e59-4be8-93a4-6d49fd13c00a",
|
|
88
|
+
},
|
|
89
|
+
cohortName: {
|
|
90
|
+
_type: Type.UUID,
|
|
91
|
+
_description: "UUID of concept for cohort name",
|
|
92
|
+
_default: "6029f289-92a6-4a68-80f1-3078d0152449",
|
|
93
|
+
},
|
|
94
|
+
sessionUuid: {
|
|
95
|
+
_type: Type.UUID,
|
|
96
|
+
_description: "UUID of concept for session identifier",
|
|
97
|
+
_default: "6a803908-8a5b-4598-adea-19358c83529a",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
specificQuestions: {
|
|
101
|
+
_type: Type.Array,
|
|
102
|
+
_description: "List of specific questions to populate forms.",
|
|
103
|
+
_elements: {
|
|
104
|
+
forms: {
|
|
105
|
+
_type: Type.Array,
|
|
106
|
+
_description: "List of form UUIDs for which the question applies.",
|
|
107
|
+
_elements: {
|
|
108
|
+
_type: Type.UUID,
|
|
109
|
+
},
|
|
110
|
+
_default: [],
|
|
111
|
+
},
|
|
112
|
+
questionId: {
|
|
113
|
+
_type: Type.String,
|
|
114
|
+
_description: "ID of the question.",
|
|
115
|
+
_default: "",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
_default: [],
|
|
119
|
+
},
|
|
63
120
|
};
|
|
64
121
|
|
|
65
122
|
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
|
|
4
|
+
export const fdeWorkflowStorageVersion = "1.1.0";
|
|
5
5
|
export const fdeWorkflowStorageName = "openmrs:fastDataEntryWorkflowState";
|
|
6
6
|
const persistData = (data) => {
|
|
7
|
-
localStorage.setItem(
|
|
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(
|
|
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
|
-
|
|
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].
|
|
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].
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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,13 +216,14 @@ 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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
+
];
|
|
157
227
|
const newState = {
|
|
158
228
|
...state,
|
|
159
229
|
forms: {
|
|
@@ -166,6 +236,8 @@ const reducer = (state, action) => {
|
|
|
166
236
|
},
|
|
167
237
|
activePatientUuid: nextPatientUuid,
|
|
168
238
|
activeEncounterUuid: thisForm.encounters[nextPatientUuid] || null,
|
|
239
|
+
activeVisitUuid: thisForm.visits[nextPatientUuid] || null,
|
|
240
|
+
activeSessionUuid: thisForm.activeSessionUuid,
|
|
169
241
|
workflowState: "EDIT_FORM",
|
|
170
242
|
},
|
|
171
243
|
},
|
|
@@ -183,7 +255,10 @@ const reducer = (state, action) => {
|
|
|
183
255
|
...state.forms[state.activeFormUuid],
|
|
184
256
|
activeEncounterUuid:
|
|
185
257
|
state.forms[state.activeFormUuid].encounters[action.patientUuid],
|
|
258
|
+
activeVisitUuid:
|
|
259
|
+
state.forms[state.activeFormUuid].visits[action.patientUuid],
|
|
186
260
|
activePatientUuid: action.patientUuid,
|
|
261
|
+
activeSessionUuid: action.activeSessionUuid,
|
|
187
262
|
workflowState: "EDIT_FORM",
|
|
188
263
|
},
|
|
189
264
|
},
|
|
@@ -191,6 +266,46 @@ const reducer = (state, action) => {
|
|
|
191
266
|
persistData(newState);
|
|
192
267
|
return newState;
|
|
193
268
|
}
|
|
269
|
+
case "VALIDATE_FOR_NEXT":
|
|
270
|
+
// this state should not be persisted
|
|
271
|
+
window.dispatchEvent(
|
|
272
|
+
new CustomEvent("ampath-form-action", {
|
|
273
|
+
detail: {
|
|
274
|
+
formUuid: state.activeFormUuid,
|
|
275
|
+
patientUuid: state.forms[state.activeFormUuid].activePatientUuid,
|
|
276
|
+
action: "validateForm",
|
|
277
|
+
},
|
|
278
|
+
})
|
|
279
|
+
);
|
|
280
|
+
return {
|
|
281
|
+
...state,
|
|
282
|
+
forms: {
|
|
283
|
+
...state.forms,
|
|
284
|
+
[state.activeFormUuid]: {
|
|
285
|
+
...state.forms[state.activeFormUuid],
|
|
286
|
+
workflowState: "VALIDATE_FOR_NEXT",
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
case "UPDATE_VISIT_UUID":
|
|
291
|
+
// this state should not be persisted
|
|
292
|
+
// we don't pers
|
|
293
|
+
return {
|
|
294
|
+
...state,
|
|
295
|
+
forms: {
|
|
296
|
+
...state.forms,
|
|
297
|
+
[state.activeFormUuid]: {
|
|
298
|
+
...state.forms[state.activeFormUuid],
|
|
299
|
+
visits: {
|
|
300
|
+
...state.forms[state.activeFormUuid].visits,
|
|
301
|
+
[state.forms[state.activeFormUuid].activePatientUuid]:
|
|
302
|
+
action.visitUuid,
|
|
303
|
+
},
|
|
304
|
+
activeVisitUuid: action.visitUuid,
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
|
|
194
309
|
case "SUBMIT_FOR_NEXT":
|
|
195
310
|
// this state should not be persisted
|
|
196
311
|
window.dispatchEvent(
|
|
@@ -211,6 +326,7 @@ const reducer = (state, action) => {
|
|
|
211
326
|
workflowState: "SUBMIT_FOR_NEXT",
|
|
212
327
|
},
|
|
213
328
|
},
|
|
329
|
+
nextPatientUuid: action.nextPatientUuid,
|
|
214
330
|
};
|
|
215
331
|
case "SUBMIT_FOR_REVIEW":
|
|
216
332
|
// this state should not be persisted
|
|
@@ -233,6 +349,28 @@ const reducer = (state, action) => {
|
|
|
233
349
|
},
|
|
234
350
|
},
|
|
235
351
|
};
|
|
352
|
+
|
|
353
|
+
case "VALIDATE_FOR_COMPLETE":
|
|
354
|
+
// this state should not be persisted
|
|
355
|
+
window.dispatchEvent(
|
|
356
|
+
new CustomEvent("ampath-form-action", {
|
|
357
|
+
detail: {
|
|
358
|
+
formUuid: state.activeFormUuid,
|
|
359
|
+
patientUuid: state.forms[state.activeFormUuid].activePatientUuid,
|
|
360
|
+
action: "validateForm",
|
|
361
|
+
},
|
|
362
|
+
})
|
|
363
|
+
);
|
|
364
|
+
return {
|
|
365
|
+
...state,
|
|
366
|
+
forms: {
|
|
367
|
+
...state.forms,
|
|
368
|
+
[state.activeFormUuid]: {
|
|
369
|
+
...state.forms[state.activeFormUuid],
|
|
370
|
+
workflowState: "VALIDATE_FOR_COMPLETE",
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
};
|
|
236
374
|
case "SUBMIT_FOR_COMPLETE":
|
|
237
375
|
// this state should not be persisted
|
|
238
376
|
window.dispatchEvent(
|
|
@@ -262,7 +400,9 @@ const reducer = (state, action) => {
|
|
|
262
400
|
[state.activeFormUuid]: {
|
|
263
401
|
...state.forms[state.activeFormUuid],
|
|
264
402
|
activeEncounterUuid: null,
|
|
403
|
+
activVisitUuid: null,
|
|
265
404
|
activePatientUuid: null,
|
|
405
|
+
activeSessionUuid: null,
|
|
266
406
|
workflowState: "REVIEW",
|
|
267
407
|
},
|
|
268
408
|
},
|
|
@@ -278,7 +418,9 @@ const reducer = (state, action) => {
|
|
|
278
418
|
activeFormUuid: null,
|
|
279
419
|
};
|
|
280
420
|
persistData(newState);
|
|
281
|
-
|
|
421
|
+
//eslint-disable-next-line
|
|
422
|
+
navigate({ to: "${openmrsSpaBase}/forms" });
|
|
423
|
+
return { ...newState, formDestroyed: true };
|
|
282
424
|
}
|
|
283
425
|
case "CLOSE_SESSION": {
|
|
284
426
|
const newState = {
|
|
@@ -286,6 +428,8 @@ const reducer = (state, action) => {
|
|
|
286
428
|
activeFormUuid: null,
|
|
287
429
|
};
|
|
288
430
|
persistData(newState);
|
|
431
|
+
//eslint-disable-next-line
|
|
432
|
+
navigate({ to: "${openmrsSpaBase}/forms" });
|
|
289
433
|
return newState;
|
|
290
434
|
}
|
|
291
435
|
default:
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
@
|
|
2
|
-
@
|
|
3
|
-
@
|
|
1
|
+
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/type';
|
|
4
4
|
|
|
5
5
|
.action {
|
|
6
|
-
margin-bottom:
|
|
6
|
+
margin-bottom: layout.$spacing-03;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
.content {
|
|
10
|
-
@include
|
|
11
|
-
color:
|
|
12
|
-
margin-top:
|
|
13
|
-
margin-bottom:
|
|
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
|
|
19
|
-
color:
|
|
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
|
|
26
|
-
color:
|
|
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:
|
|
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
|
|
54
|
+
border: 1px solid colors.$gray-20;
|
|
55
55
|
}
|