@openmrs/esm-fast-data-entry-app 1.0.0-pre.59 → 1.0.1-pre.8
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/.husky/pre-push +0 -0
- package/.yarn/plugins/@yarnpkg/plugin-version.cjs +550 -0
- package/.yarn/versions/7ee3eceb.yml +0 -0
- package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
- package/jest.config.json +20 -18
- package/package.json +31 -38
- package/src/FormBootstrap.tsx +9 -2
- package/src/Root.tsx +12 -5
- package/src/add-group-modal/AddGroupModal.tsx +209 -0
- package/src/add-group-modal/styles.scss +35 -0
- package/src/context/FormWorkflowContext.tsx +1 -1
- package/src/context/FormWorkflowReducer.ts +1 -1
- package/src/context/GroupFormWorkflowContext.tsx +141 -0
- package/src/context/GroupFormWorkflowReducer.ts +272 -0
- package/src/empty-state/EmptyState.tsx +12 -8
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +23 -13
- package/src/{form-review-card → form-entry-workflow/form-review-card}/FormReviewCard.tsx +3 -3
- package/src/{form-review-card → form-entry-workflow/form-review-card}/index.ts +0 -0
- package/src/form-entry-workflow/form-review-card/styles.scss +39 -0
- package/src/{patient-banner → form-entry-workflow/patient-banner}/PatientBanner.test.tsx +0 -0
- package/src/{patient-banner → form-entry-workflow/patient-banner}/PatientBanner.tsx +3 -3
- package/src/{patient-banner → form-entry-workflow/patient-banner}/index.ts +0 -0
- package/src/{patient-banner → form-entry-workflow/patient-banner}/styles.scss +8 -7
- package/src/{patient-search-header → form-entry-workflow/patient-search-header}/PatientSearchHeader.tsx +13 -11
- package/src/{patient-search-header → form-entry-workflow/patient-search-header}/index.ts +0 -0
- package/src/form-entry-workflow/patient-search-header/styles.scss +22 -0
- package/src/form-entry-workflow/styles.scss +14 -13
- package/src/{workflow-review → form-entry-workflow/workflow-review}/WorkflowReview.tsx +6 -6
- package/src/{workflow-review → form-entry-workflow/workflow-review}/index.ts +0 -0
- package/src/{workflow-review → form-entry-workflow/workflow-review}/styles.scss +0 -0
- package/src/forms-app-menu-link.tsx +2 -2
- package/src/forms-page/FormsPage.tsx +55 -21
- package/src/{forms-table → forms-page/forms-table}/FormsTable.tsx +14 -6
- package/src/{forms-table → forms-page/forms-table}/index.ts +0 -0
- package/src/{forms-table → forms-page/forms-table}/styles.scss +0 -0
- package/src/forms-page/styles.scss +5 -5
- package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +413 -0
- package/src/group-form-entry-workflow/group-banner/GroupBanner.test.tsx +9 -0
- package/src/group-form-entry-workflow/group-banner/GroupBanner.tsx +45 -0
- package/src/group-form-entry-workflow/group-banner/index.ts +3 -0
- package/src/group-form-entry-workflow/group-banner/styles.scss +60 -0
- package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +106 -0
- package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +63 -0
- package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +93 -0
- package/src/group-form-entry-workflow/group-search/compact-group-result.scss +64 -0
- package/src/group-form-entry-workflow/group-search/compact-group-search.scss +35 -0
- package/src/group-form-entry-workflow/group-search/group-search.scss +94 -0
- package/src/group-form-entry-workflow/group-search/mock-group-data.ts +79 -0
- package/src/group-form-entry-workflow/group-search/useGroupSearch.ts +14 -0
- package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +42 -0
- package/src/group-form-entry-workflow/group-search-header/index.ts +3 -0
- package/src/{patient-search-header → group-form-entry-workflow/group-search-header}/styles.scss +5 -6
- package/src/group-form-entry-workflow/index.ts +3 -0
- package/src/group-form-entry-workflow/styles.scss +86 -0
- package/src/hooks/useKeyPress.ts +31 -0
- package/src/hooks/usePostCohort.ts +18 -0
- package/src/index.ts +5 -1
- package/src/patient-card/PatientCard.tsx +11 -9
- package/src/patient-card/styles.scss +9 -8
- package/translations/en.json +30 -1
- package/.github/pull_request_template.md +0 -18
- package/.github/workflows/node.js.yml +0 -121
- package/dist/132.js +0 -1
- package/dist/187.js +0 -1
- package/dist/247.js +0 -1
- package/dist/294.js +0 -2
- package/dist/294.js.LICENSE.txt +0 -14
- package/dist/312.js +0 -1
- package/dist/412.js +0 -1
- package/dist/536.js +0 -2
- package/dist/536.js.LICENSE.txt +0 -8
- package/dist/574.js +0 -1
- package/dist/592.js +0 -1
- package/dist/595.js +0 -2
- package/dist/595.js.LICENSE.txt +0 -1
- package/dist/776.js +0 -1
- package/dist/804.js +0 -1
- package/dist/880.js +0 -2
- package/dist/880.js.LICENSE.txt +0 -20
- package/dist/906.js +0 -1
- package/dist/935.js +0 -2
- package/dist/935.js.LICENSE.txt +0 -23
- package/dist/990.js +0 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +0 -433
- package/dist/openmrs-esm-fast-data-entry-app.old +0 -1
- package/src/form-review-card/styles.scss +0 -38
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useReducer } from "react";
|
|
2
|
+
import reducer from "./GroupFormWorkflowReducer";
|
|
3
|
+
import { useParams } from "react-router-dom";
|
|
4
|
+
import { Type } from "@openmrs/esm-framework";
|
|
5
|
+
interface ParamTypes {
|
|
6
|
+
formUuid?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface GroupType {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
members: Array<Type.Object>;
|
|
13
|
+
}
|
|
14
|
+
export interface MetaType {
|
|
15
|
+
sessionName: string;
|
|
16
|
+
sessionDate: string;
|
|
17
|
+
practitionerName: string;
|
|
18
|
+
sessionNotes: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const initialActions = {
|
|
22
|
+
setGroup: (group: GroupType) => undefined,
|
|
23
|
+
setSessionMeta: (meta: MetaType) => undefined,
|
|
24
|
+
openPatientSearch: () => undefined,
|
|
25
|
+
saveEncounter: (encounterUuid: string | number) => undefined,
|
|
26
|
+
editEncounter: (patientUuid: string | number) => undefined,
|
|
27
|
+
submitForNext: () => undefined,
|
|
28
|
+
submitForReview: () => undefined,
|
|
29
|
+
submitForComplete: () => undefined,
|
|
30
|
+
goToReview: () => undefined,
|
|
31
|
+
destroySession: () => undefined,
|
|
32
|
+
closeSession: () => undefined,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const initialWorkflowState = {
|
|
36
|
+
// activeFormUuid and forms are the only two real values stored at state root level
|
|
37
|
+
activeFormUuid: null, // the corrently open form
|
|
38
|
+
forms: {}, // object containing all forms session data
|
|
39
|
+
// the following fields will be available in context but are not stored at the
|
|
40
|
+
// state root level, but refer to nested values for the current
|
|
41
|
+
// aciveFormUuid
|
|
42
|
+
workflowState: null, // pseudo field from state[activeFormUuid].workflowState
|
|
43
|
+
activePatientUuid: null, // pseudo field from state[activeFormUuid].activePatientUuid
|
|
44
|
+
activeEncounterUuid: null, // pseudo field from state[activeFormUuid].encounterUuid
|
|
45
|
+
patientUuids: [], // pseudo field from state[activeFormUuid].patientUuids
|
|
46
|
+
encounters: {}, // pseudo field from state[activeFormUuid].encounters
|
|
47
|
+
activeGroupUuid: null, // pseudo field from state[activeFormUuid].groupUuid
|
|
48
|
+
activeGroupName: null, // pseudo field from state[activeFormUuid].groupname
|
|
49
|
+
activeSessionMeta: {
|
|
50
|
+
sessionName: null,
|
|
51
|
+
practitionerName: null,
|
|
52
|
+
sessionDate: null,
|
|
53
|
+
sessionNotes: null,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const GroupFormWorkflowContext = React.createContext({
|
|
58
|
+
...initialWorkflowState,
|
|
59
|
+
...initialActions,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const GroupFormWorkflowProvider = ({ children }) => {
|
|
63
|
+
const { formUuid } = useParams() as ParamTypes;
|
|
64
|
+
const activeFormUuid = formUuid.split("&")[0];
|
|
65
|
+
const [state, dispatch] = useReducer(reducer, {
|
|
66
|
+
...initialWorkflowState,
|
|
67
|
+
...initialActions,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const actions = useMemo(
|
|
71
|
+
() => ({
|
|
72
|
+
initializeWorkflowState: ({ activeFormUuid }) =>
|
|
73
|
+
dispatch({
|
|
74
|
+
type: "INITIALIZE_WORKFLOW_STATE",
|
|
75
|
+
activeFormUuid,
|
|
76
|
+
}),
|
|
77
|
+
setGroup: (group) => dispatch({ type: "SET_GROUP", group }),
|
|
78
|
+
setSessionMeta: (meta) => dispatch({ type: "SET_SESSION_META", meta }),
|
|
79
|
+
openPatientSearch: () => dispatch({ type: "OPEN_PATIENT_SEARCH" }),
|
|
80
|
+
saveEncounter: (encounterUuid) =>
|
|
81
|
+
dispatch({
|
|
82
|
+
type: "SAVE_ENCOUNTER",
|
|
83
|
+
encounterUuid,
|
|
84
|
+
}),
|
|
85
|
+
submitForNext: () => dispatch({ type: "SUBMIT_FOR_NEXT" }),
|
|
86
|
+
submitForComplete: () => dispatch({ type: "SUBMIT_FOR_COMPLETE" }),
|
|
87
|
+
editEncounter: (patientUuid) =>
|
|
88
|
+
dispatch({ type: "EDIT_ENCOUNTER", patientUuid }),
|
|
89
|
+
goToReview: () => dispatch({ type: "GO_TO_REVIEW" }),
|
|
90
|
+
destroySession: () => dispatch({ type: "DESTROY_SESSION" }),
|
|
91
|
+
closeSession: () => dispatch({ type: "CLOSE_SESSION" }),
|
|
92
|
+
}),
|
|
93
|
+
[]
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// if formUuid isn't a part of state yet, grab it from the url params
|
|
97
|
+
// this is the entry into the workflow system
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (state?.workflowState === null && activeFormUuid) {
|
|
100
|
+
actions.initializeWorkflowState({ activeFormUuid });
|
|
101
|
+
}
|
|
102
|
+
}, [activeFormUuid, state?.workflowState, actions]);
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<GroupFormWorkflowContext.Provider
|
|
106
|
+
value={{
|
|
107
|
+
...state,
|
|
108
|
+
...actions,
|
|
109
|
+
workflowState:
|
|
110
|
+
state.forms?.[state.activeFormUuid]?.workflowState ??
|
|
111
|
+
initialWorkflowState.workflowState,
|
|
112
|
+
activePatientUuid:
|
|
113
|
+
state.forms?.[state.activeFormUuid]?.activePatientUuid ??
|
|
114
|
+
initialWorkflowState.activePatientUuid,
|
|
115
|
+
activeEncounterUuid:
|
|
116
|
+
state.forms?.[state.activeFormUuid]?.activeEncounterUuid ??
|
|
117
|
+
initialWorkflowState.activeEncounterUuid,
|
|
118
|
+
patientUuids:
|
|
119
|
+
state.forms?.[state.activeFormUuid]?.patientUuids ??
|
|
120
|
+
initialWorkflowState.patientUuids,
|
|
121
|
+
encounters:
|
|
122
|
+
state.forms?.[state.activeFormUuid]?.encounters ??
|
|
123
|
+
initialWorkflowState.encounters,
|
|
124
|
+
activeGroupUuid:
|
|
125
|
+
state.forms?.[state.activeFormUuid]?.groupUuid ??
|
|
126
|
+
initialWorkflowState.activeGroupUuid,
|
|
127
|
+
activeGroupName:
|
|
128
|
+
state.forms?.[state.activeFormUuid]?.groupName ??
|
|
129
|
+
initialWorkflowState.activeGroupName,
|
|
130
|
+
activeSessionMeta:
|
|
131
|
+
state.forms?.[state.activeFormUuid]?.sessionMeta ??
|
|
132
|
+
initialWorkflowState.activeSessionMeta,
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
{children}
|
|
136
|
+
</GroupFormWorkflowContext.Provider>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export default GroupFormWorkflowContext;
|
|
141
|
+
export { GroupFormWorkflowProvider };
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { navigate } from "@openmrs/esm-framework";
|
|
2
|
+
import { initialWorkflowState } from "./FormWorkflowContext";
|
|
3
|
+
|
|
4
|
+
export const fdeGroupWorkflowStorageVersion = "1.0.5";
|
|
5
|
+
export const fdeGroupWorkflowStorageName =
|
|
6
|
+
"openmrs:fastDataEntryGroupWorkflowState";
|
|
7
|
+
const persistData = (data) => {
|
|
8
|
+
localStorage.setItem(fdeGroupWorkflowStorageName, JSON.stringify(data));
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const initialFormState = {
|
|
12
|
+
workflowState: "NEW_GROUP_SESSION",
|
|
13
|
+
groupUuid: null,
|
|
14
|
+
groupName: null,
|
|
15
|
+
activePatientUuid: null,
|
|
16
|
+
activeEncounterUuid: null,
|
|
17
|
+
patientUuids: [],
|
|
18
|
+
encounters: {},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const reducer = (state, action) => {
|
|
22
|
+
switch (action.type) {
|
|
23
|
+
case "INITIALIZE_WORKFLOW_STATE": {
|
|
24
|
+
const savedData = localStorage.getItem(fdeGroupWorkflowStorageName);
|
|
25
|
+
const savedDataObject = savedData ? JSON.parse(savedData) : {};
|
|
26
|
+
let newState: { [key: string]: unknown } = {};
|
|
27
|
+
if (
|
|
28
|
+
savedData &&
|
|
29
|
+
savedDataObject["_storageVersion"] === fdeGroupWorkflowStorageVersion
|
|
30
|
+
) {
|
|
31
|
+
// there is localStorage data and it is still valid
|
|
32
|
+
const thisSavedForm = savedDataObject.forms?.[action.activeFormUuid];
|
|
33
|
+
// set active patient to the last one we were on
|
|
34
|
+
const activePatientUuid =
|
|
35
|
+
thisSavedForm?.activePatientUuid ||
|
|
36
|
+
// or set it to the first member in the list
|
|
37
|
+
thisSavedForm?.patientUuids?.[0] ||
|
|
38
|
+
// something probably went wrong...
|
|
39
|
+
null;
|
|
40
|
+
newState = {
|
|
41
|
+
...savedDataObject,
|
|
42
|
+
// set current form to this one
|
|
43
|
+
activeFormUuid: action.activeFormUuid,
|
|
44
|
+
forms: {
|
|
45
|
+
...savedDataObject.forms,
|
|
46
|
+
// initialize this particular form if it hasn't been created already
|
|
47
|
+
[action.activeFormUuid]: {
|
|
48
|
+
...initialFormState,
|
|
49
|
+
...thisSavedForm,
|
|
50
|
+
activePatientUuid: activePatientUuid,
|
|
51
|
+
activeEncounterUuid:
|
|
52
|
+
thisSavedForm?.encounters?.[activePatientUuid] || null,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
} else {
|
|
57
|
+
// no localStorage data, or we should void it
|
|
58
|
+
newState = {
|
|
59
|
+
...initialWorkflowState,
|
|
60
|
+
_storageVersion: fdeGroupWorkflowStorageVersion,
|
|
61
|
+
forms: {
|
|
62
|
+
[action.activeFormUuid]: initialFormState,
|
|
63
|
+
},
|
|
64
|
+
activeFormUuid: action.activeFormUuid,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
persistData(newState);
|
|
68
|
+
return newState;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
case "SET_GROUP": {
|
|
72
|
+
const newState = {
|
|
73
|
+
...state,
|
|
74
|
+
forms: {
|
|
75
|
+
...state.forms,
|
|
76
|
+
[state.activeFormUuid]: {
|
|
77
|
+
...state.forms[state.activeFormUuid],
|
|
78
|
+
groupUuid: action.group.id,
|
|
79
|
+
groupName: action.group.name,
|
|
80
|
+
patientUuids: action.group.members.map((member) => member.uuid),
|
|
81
|
+
activePatientUuid: null,
|
|
82
|
+
activeEncounterUuid: null,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
persistData(newState);
|
|
87
|
+
return newState;
|
|
88
|
+
}
|
|
89
|
+
case "SET_SESSION_META": {
|
|
90
|
+
// requires that group is already entered and contains patientUuids
|
|
91
|
+
const newState = {
|
|
92
|
+
...state,
|
|
93
|
+
forms: {
|
|
94
|
+
...state.forms,
|
|
95
|
+
[state.activeFormUuid]: {
|
|
96
|
+
...state.forms[state.activeFormUuid],
|
|
97
|
+
sessionMeta: action.meta,
|
|
98
|
+
activePatientUuid:
|
|
99
|
+
state.forms[state.activeFormUuid].patientUuids?.[0],
|
|
100
|
+
activeEncounterUuid:
|
|
101
|
+
state.forms[state.activeFormUuid].encounters[
|
|
102
|
+
state.forms[state.activeFormUuid].patientUuids?.[0]
|
|
103
|
+
] || null,
|
|
104
|
+
workflowState: "EDIT_FORM",
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
persistData(newState);
|
|
109
|
+
return newState;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
case "SAVE_ENCOUNTER": {
|
|
113
|
+
const thisForm = state.forms[state.activeFormUuid];
|
|
114
|
+
if (thisForm.workflowState === "SUBMIT_FOR_COMPLETE") {
|
|
115
|
+
const { [state.activeFormUuid]: activeForm, ...formRest } = state.forms;
|
|
116
|
+
const newState = {
|
|
117
|
+
...state,
|
|
118
|
+
forms: formRest,
|
|
119
|
+
activeFormUuid: null,
|
|
120
|
+
};
|
|
121
|
+
persistData(newState);
|
|
122
|
+
// eslint-disable-next-line
|
|
123
|
+
navigate({ to: "${openmrsSpaBase}/forms" });
|
|
124
|
+
return newState;
|
|
125
|
+
} else if (thisForm.workflowState === "SUBMIT_FOR_NEXT") {
|
|
126
|
+
const nextPatientUuid =
|
|
127
|
+
thisForm.patientUuids[
|
|
128
|
+
Math.min(
|
|
129
|
+
thisForm.patientUuids.indexOf(thisForm.activePatientUuid) + 1,
|
|
130
|
+
thisForm.patientUuids.length - 1
|
|
131
|
+
)
|
|
132
|
+
];
|
|
133
|
+
const newState = {
|
|
134
|
+
...state,
|
|
135
|
+
forms: {
|
|
136
|
+
...state.forms,
|
|
137
|
+
[state.activeFormUuid]: {
|
|
138
|
+
...thisForm,
|
|
139
|
+
encounters: {
|
|
140
|
+
...thisForm.encounters,
|
|
141
|
+
[thisForm.activePatientUuid]: action.encounterUuid,
|
|
142
|
+
},
|
|
143
|
+
activePatientUuid: nextPatientUuid,
|
|
144
|
+
activeEncounterUuid: thisForm.encounters[nextPatientUuid] || null,
|
|
145
|
+
workflowState: "EDIT_FORM",
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
persistData(newState);
|
|
150
|
+
return newState;
|
|
151
|
+
} else return state;
|
|
152
|
+
}
|
|
153
|
+
case "EDIT_ENCOUNTER": {
|
|
154
|
+
const newState = {
|
|
155
|
+
...state,
|
|
156
|
+
forms: {
|
|
157
|
+
...state.forms,
|
|
158
|
+
[state.activeFormUuid]: {
|
|
159
|
+
...state.forms[state.activeFormUuid],
|
|
160
|
+
activeEncounterUuid:
|
|
161
|
+
state.forms[state.activeFormUuid].encounters[action.patientUuid],
|
|
162
|
+
activePatientUuid: action.patientUuid,
|
|
163
|
+
workflowState: "EDIT_FORM",
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
persistData(newState);
|
|
168
|
+
return newState;
|
|
169
|
+
}
|
|
170
|
+
case "SUBMIT_FOR_NEXT":
|
|
171
|
+
// this state should not be persisted
|
|
172
|
+
window.dispatchEvent(
|
|
173
|
+
new CustomEvent("ampath-form-action", {
|
|
174
|
+
detail: {
|
|
175
|
+
formUuid: state.activeFormUuid,
|
|
176
|
+
patientUuid: state.forms[state.activeFormUuid].activePatientUuid,
|
|
177
|
+
action: "onSubmit",
|
|
178
|
+
},
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
return {
|
|
182
|
+
...state,
|
|
183
|
+
forms: {
|
|
184
|
+
...state.forms,
|
|
185
|
+
[state.activeFormUuid]: {
|
|
186
|
+
...state.forms[state.activeFormUuid],
|
|
187
|
+
workflowState: "SUBMIT_FOR_NEXT",
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
case "SUBMIT_FOR_REVIEW":
|
|
192
|
+
// this state should not be persisted
|
|
193
|
+
window.dispatchEvent(
|
|
194
|
+
new CustomEvent("ampath-form-action", {
|
|
195
|
+
detail: {
|
|
196
|
+
formUuid: state.activeFormUuid,
|
|
197
|
+
patientUuid: state.forms[state.activeFormUuid].activePatientUuid,
|
|
198
|
+
action: "onSubmit",
|
|
199
|
+
},
|
|
200
|
+
})
|
|
201
|
+
);
|
|
202
|
+
return {
|
|
203
|
+
...state,
|
|
204
|
+
forms: {
|
|
205
|
+
...state.forms,
|
|
206
|
+
[state.activeFormUuid]: {
|
|
207
|
+
...state.forms[state.activeFormUuid],
|
|
208
|
+
workflowState: "SUBMIT_FOR_REVIEW",
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
case "SUBMIT_FOR_COMPLETE":
|
|
213
|
+
// this state should not be persisted
|
|
214
|
+
window.dispatchEvent(
|
|
215
|
+
new CustomEvent("ampath-form-action", {
|
|
216
|
+
detail: {
|
|
217
|
+
formUuid: state.activeFormUuid,
|
|
218
|
+
patientUuid: state.forms[state.activeFormUuid].activePatientUuid,
|
|
219
|
+
action: "onSubmit",
|
|
220
|
+
},
|
|
221
|
+
})
|
|
222
|
+
);
|
|
223
|
+
return {
|
|
224
|
+
...state,
|
|
225
|
+
forms: {
|
|
226
|
+
...state.forms,
|
|
227
|
+
[state.activeFormUuid]: {
|
|
228
|
+
...state.forms[state.activeFormUuid],
|
|
229
|
+
workflowState: "SUBMIT_FOR_COMPLETE",
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
case "GO_TO_REVIEW": {
|
|
234
|
+
const newState = {
|
|
235
|
+
...state,
|
|
236
|
+
forms: {
|
|
237
|
+
...state.forms,
|
|
238
|
+
[state.activeFormUuid]: {
|
|
239
|
+
...state.forms[state.activeFormUuid],
|
|
240
|
+
activeEncounterUuid: null,
|
|
241
|
+
activePatientUuid: null,
|
|
242
|
+
workflowState: "REVIEW",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
persistData(newState);
|
|
247
|
+
return newState;
|
|
248
|
+
}
|
|
249
|
+
case "DESTROY_SESSION": {
|
|
250
|
+
const { [state.activeFormUuid]: activeForm, ...formRest } = state.forms;
|
|
251
|
+
const newState = {
|
|
252
|
+
...state,
|
|
253
|
+
forms: formRest,
|
|
254
|
+
activeFormUuid: null,
|
|
255
|
+
};
|
|
256
|
+
persistData(newState);
|
|
257
|
+
return newState;
|
|
258
|
+
}
|
|
259
|
+
case "CLOSE_SESSION": {
|
|
260
|
+
const newState = {
|
|
261
|
+
...state,
|
|
262
|
+
activeFormUuid: null,
|
|
263
|
+
};
|
|
264
|
+
persistData(newState);
|
|
265
|
+
return newState;
|
|
266
|
+
}
|
|
267
|
+
default:
|
|
268
|
+
return state;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
export default reducer;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Tile } from "carbon
|
|
2
|
+
import { Tile, Layer } from "@carbon/react";
|
|
3
3
|
import styles from "./styles.scss";
|
|
4
4
|
import { useLayoutType } from "@openmrs/esm-framework";
|
|
5
5
|
import { EmptyDataIllustration } from "./EmptyDataIllustration";
|
|
@@ -15,13 +15,17 @@ const EmptyState: React.FC<EmptyStateProps> = ({
|
|
|
15
15
|
const isTablet = useLayoutType() === "tablet";
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
<Layer>
|
|
19
|
+
<Tile className={styles.tile}>
|
|
20
|
+
<div
|
|
21
|
+
className={isTablet ? styles.tabletHeading : styles.desktopHeading}
|
|
22
|
+
>
|
|
23
|
+
<h4>{headerTitle}</h4>
|
|
24
|
+
</div>
|
|
25
|
+
<EmptyDataIllustration />
|
|
26
|
+
<p className={styles.content}>{displayText}</p>
|
|
27
|
+
</Tile>
|
|
28
|
+
</Layer>
|
|
25
29
|
);
|
|
26
30
|
};
|
|
27
31
|
|
|
@@ -9,37 +9,37 @@ import {
|
|
|
9
9
|
ModalBody,
|
|
10
10
|
ModalFooter,
|
|
11
11
|
ModalHeader,
|
|
12
|
-
} from "carbon
|
|
12
|
+
} from "@carbon/react";
|
|
13
13
|
import React, { useContext, useState } from "react";
|
|
14
|
-
import {
|
|
14
|
+
import { useNavigate } from "react-router-dom";
|
|
15
15
|
import FormBootstrap from "../FormBootstrap";
|
|
16
16
|
import PatientCard from "../patient-card/PatientCard";
|
|
17
|
-
import PatientBanner from "../patient-banner";
|
|
18
17
|
import styles from "./styles.scss";
|
|
19
|
-
import PatientSearchHeader from "
|
|
18
|
+
import PatientSearchHeader from "./patient-search-header";
|
|
20
19
|
import { useTranslation } from "react-i18next";
|
|
21
20
|
import FormWorkflowContext, {
|
|
22
21
|
FormWorkflowProvider,
|
|
23
22
|
} from "../context/FormWorkflowContext";
|
|
24
|
-
import WorkflowReview from "
|
|
23
|
+
import WorkflowReview from "./workflow-review";
|
|
24
|
+
import PatientBanner from "./patient-banner";
|
|
25
25
|
|
|
26
26
|
const formStore = getGlobalStore("ampath-form-state");
|
|
27
27
|
|
|
28
28
|
const CancelModal = ({ open, setOpen }) => {
|
|
29
29
|
const { destroySession, closeSession } = useContext(FormWorkflowContext);
|
|
30
30
|
const { t } = useTranslation();
|
|
31
|
-
const
|
|
31
|
+
const navigate = useNavigate();
|
|
32
32
|
|
|
33
|
-
const discard = () => {
|
|
34
|
-
destroySession();
|
|
33
|
+
const discard = async () => {
|
|
34
|
+
await destroySession();
|
|
35
35
|
setOpen(false);
|
|
36
|
-
|
|
36
|
+
navigate("../");
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
const saveAndClose = () => {
|
|
40
|
-
closeSession();
|
|
39
|
+
const saveAndClose = async () => {
|
|
40
|
+
await closeSession();
|
|
41
41
|
setOpen(false);
|
|
42
|
-
|
|
42
|
+
navigate("../");
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
return (
|
|
@@ -145,6 +145,8 @@ const FormWorkspace = () => {
|
|
|
145
145
|
activeEncounterUuid,
|
|
146
146
|
saveEncounter,
|
|
147
147
|
activeFormUuid,
|
|
148
|
+
editEncounter,
|
|
149
|
+
encounters,
|
|
148
150
|
} = useContext(FormWorkflowContext);
|
|
149
151
|
const { t } = useTranslation();
|
|
150
152
|
|
|
@@ -177,7 +179,15 @@ const FormWorkspace = () => {
|
|
|
177
179
|
<h4>Forms filled</h4>
|
|
178
180
|
<div className={styles.patientCardsSection}>
|
|
179
181
|
{patientUuids.map((patientUuid) => (
|
|
180
|
-
<PatientCard
|
|
182
|
+
<PatientCard
|
|
183
|
+
key={patientUuid}
|
|
184
|
+
{...{
|
|
185
|
+
patientUuid,
|
|
186
|
+
activePatientUuid,
|
|
187
|
+
editEncounter,
|
|
188
|
+
encounters,
|
|
189
|
+
}}
|
|
190
|
+
/>
|
|
181
191
|
))}
|
|
182
192
|
</div>
|
|
183
193
|
<WorkflowNavigationButtons />
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Accordion, AccordionItem, Button } from "carbon
|
|
1
|
+
import { Accordion, AccordionItem, Button } from "@carbon/react";
|
|
2
2
|
import React, { useContext } from "react";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
|
-
import FormWorkflowContext from "
|
|
5
|
-
import { useGetPatient, useGetEncounter } from "
|
|
4
|
+
import FormWorkflowContext from "../../context/FormWorkflowContext";
|
|
5
|
+
import { useGetPatient, useGetEncounter } from "../../hooks";
|
|
6
6
|
import styles from "./styles.scss";
|
|
7
7
|
|
|
8
8
|
const FormReviewCard = ({ patientUuid }) => {
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
@use '@carbon/styles/scss/spacing';
|
|
2
|
+
// @use '@carbon/colors';
|
|
3
|
+
@use '@carbon/styles/scss/type';
|
|
4
|
+
@import '~@openmrs/esm-styleguide/src/vars';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
.formReviewCard {
|
|
8
|
+
background-color: $ui-02;
|
|
9
|
+
padding: spacing.$spacing-02;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.formReviewCard :global(.cds--accordion) :global(.cds--accordion__item) {
|
|
13
|
+
border: none;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.formReviewCard :global(.cds--accordion__title) {
|
|
17
|
+
display: flex;
|
|
18
|
+
align-items: baseline;
|
|
19
|
+
column-gap: spacing.$spacing-05;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.formReviewCard :global(.cds--accordion__content) {
|
|
23
|
+
padding: spacing.$spacing-03;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.dataField {
|
|
27
|
+
@include type.type-style('code-02');
|
|
28
|
+
background-color: $ui-01;
|
|
29
|
+
padding: spacing.$spacing-03;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.displayName {
|
|
33
|
+
@include type.type-style('heading-02');
|
|
34
|
+
font-weight: bold;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.identifier {
|
|
38
|
+
@include type.type-style('body-compact-01')
|
|
39
|
+
}
|
|
File without changes
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { age, ExtensionSlot } from "@openmrs/esm-framework";
|
|
2
|
-
import { SkeletonPlaceholder, SkeletonText } from "carbon
|
|
2
|
+
import { SkeletonPlaceholder, SkeletonText } from "@carbon/react";
|
|
3
3
|
import React, { useContext } from "react";
|
|
4
4
|
import styles from "./styles.scss";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
|
-
import useGetPatient from "
|
|
7
|
-
import FormWorkflowContext from "
|
|
6
|
+
import useGetPatient from "../../hooks/useGetPatient";
|
|
7
|
+
import FormWorkflowContext from "../../context/FormWorkflowContext";
|
|
8
8
|
|
|
9
9
|
const SkeletonPatientInfo = () => {
|
|
10
10
|
return (
|
|
File without changes
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
@use '@carbon/styles/scss/spacing';
|
|
2
|
+
// @use '@carbon/colors';
|
|
3
|
+
@use '@carbon/styles/scss/type';
|
|
1
4
|
@import '~@openmrs/esm-styleguide/src/vars';
|
|
2
|
-
@import '~carbon-components/src/globals/scss/vars';
|
|
3
|
-
@import '~carbon-components/src/globals/scss/mixins';
|
|
4
5
|
|
|
5
6
|
.container {
|
|
6
|
-
height:
|
|
7
|
+
height: spacing.$spacing-11;
|
|
7
8
|
display: flex;
|
|
8
9
|
align-items: center;
|
|
9
10
|
background-color: $ui-02;
|
|
10
11
|
border-top: 0.0125rem solid $ui-03;
|
|
11
12
|
border-bottom: 0.0125rem solid $ui-03;
|
|
12
|
-
padding: 0
|
|
13
|
+
padding: 0 spacing.$spacing-05;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
.photoPlaceholder {
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
.patientName {
|
|
21
|
-
@include
|
|
22
|
+
@include type.type-style('heading-03');
|
|
22
23
|
font-weight: 600;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -33,12 +34,12 @@
|
|
|
33
34
|
& > button {
|
|
34
35
|
min-height: 2rem;
|
|
35
36
|
}
|
|
36
|
-
@include
|
|
37
|
+
@include type.type-style('body-compact-02');
|
|
37
38
|
color: $text-02;
|
|
38
39
|
column-gap: 0.8rem;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
.patientEditBtn {
|
|
42
43
|
color: $ui-05;
|
|
43
|
-
margin:
|
|
44
|
+
margin: spacing.$spacing-03;
|
|
44
45
|
}
|