@openmrs/esm-fast-data-entry-app 1.0.0-pre.19 → 1.0.0-pre.25
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/dist/147.js +2 -0
- package/dist/{737.js.LICENSE.txt → 147.js.LICENSE.txt} +0 -0
- package/dist/247.js +1 -0
- package/dist/508.js +1 -0
- package/dist/574.js +1 -1
- package/dist/595.js +1 -1
- package/dist/595.js.LICENSE.txt +2 -0
- package/dist/634.js +2 -0
- package/dist/{900.js.LICENSE.txt → 634.js.LICENSE.txt} +0 -0
- package/dist/804.js +1 -1
- package/dist/954.js +1 -0
- package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +74 -74
- package/dist/openmrs-esm-fast-data-entry-app.old +1 -1
- package/package.json +1 -1
- package/src/FormBootstrap.tsx +142 -0
- package/src/Root.tsx +11 -8
- package/src/context/FormWorkflowContext.tsx +40 -0
- package/src/context/FormWorkflowReducer.ts +38 -0
- package/src/empty-state/EmptyDataIllustration.tsx +51 -0
- package/src/empty-state/EmptyState.tsx +29 -0
- package/src/empty-state/styles.scss +55 -0
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +88 -0
- package/src/form-entry-workflow/index.ts +3 -0
- package/src/form-entry-workflow/styles.scss +59 -0
- package/src/forms-page/FormsPage.tsx +54 -0
- package/src/forms-page/index.ts +3 -0
- package/src/forms-page/styles.scss +11 -0
- package/src/{forms → forms-table}/FormsTable.tsx +51 -23
- package/src/forms-table/index.ts +3 -0
- package/src/forms-table/styles.scss +20 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useGetAllForms.ts +31 -0
- package/src/{forms → hooks}/useGetPatient.ts +0 -0
- package/src/{forms/PatientInfo.test.tsx → patient-banner/PatientBanner.test.tsx} +3 -3
- package/src/{forms/PatientInfo.tsx → patient-banner/PatientBanner.tsx} +2 -2
- package/src/patient-banner/index.ts +3 -0
- package/src/{forms/patient-info.scss → patient-banner/styles.scss} +0 -0
- package/src/patient-card/PatientCard.tsx +51 -0
- package/src/patient-card/index.ts +3 -0
- package/src/patient-card/styles.scss +30 -0
- package/src/patient-search-header/PatientSearchHeader.tsx +47 -0
- package/src/patient-search-header/index.ts +3 -0
- package/src/patient-search-header/styles.scss +17 -0
- package/translations/en.json +13 -4
- package/dist/375.js +0 -1
- package/dist/418.js +0 -1
- package/dist/737.js +0 -2
- package/dist/900.js +0 -2
- package/dist/947.js +0 -1
- package/src/FormEntry.tsx +0 -42
- package/src/Loader.tsx +0 -16
- package/src/forms/FormWorkflow.tsx +0 -135
- package/src/forms/FormsRoot.tsx +0 -73
- package/src/forms/PatientCard.tsx +0 -37
- package/src/forms/mockData.ts +0 -20
- package/src/forms/styles.scss +0 -13
- package/src/loader.scss +0 -9
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ExtensionSlot } from "@openmrs/esm-framework";
|
|
3
|
+
import useGetPatient from "./hooks/useGetPatient";
|
|
4
|
+
|
|
5
|
+
export interface Order {
|
|
6
|
+
uuid: string;
|
|
7
|
+
dateActivated: string;
|
|
8
|
+
dose: number;
|
|
9
|
+
doseUnits: {
|
|
10
|
+
uuid: string;
|
|
11
|
+
display: string;
|
|
12
|
+
};
|
|
13
|
+
orderNumber: number;
|
|
14
|
+
display: string;
|
|
15
|
+
drug: {
|
|
16
|
+
uuid: string;
|
|
17
|
+
name: string;
|
|
18
|
+
strength: string;
|
|
19
|
+
};
|
|
20
|
+
duration: number;
|
|
21
|
+
durationUnits: {
|
|
22
|
+
uuid: string;
|
|
23
|
+
display: string;
|
|
24
|
+
};
|
|
25
|
+
frequency: {
|
|
26
|
+
uuid: string;
|
|
27
|
+
display: string;
|
|
28
|
+
};
|
|
29
|
+
numRefills: number;
|
|
30
|
+
orderer: {
|
|
31
|
+
uuid: string;
|
|
32
|
+
person: {
|
|
33
|
+
uuid: string;
|
|
34
|
+
display: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
orderType: {
|
|
38
|
+
uuid: string;
|
|
39
|
+
display: string;
|
|
40
|
+
};
|
|
41
|
+
route: {
|
|
42
|
+
uuid: string;
|
|
43
|
+
display: string;
|
|
44
|
+
};
|
|
45
|
+
auditInfo: {
|
|
46
|
+
dateVoided: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface Observation {
|
|
51
|
+
uuid: string;
|
|
52
|
+
concept: {
|
|
53
|
+
uuid: string;
|
|
54
|
+
display: string;
|
|
55
|
+
conceptClass: {
|
|
56
|
+
uuid: string;
|
|
57
|
+
display: string;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
display: string;
|
|
61
|
+
groupMembers: null | Array<{
|
|
62
|
+
uuid: string;
|
|
63
|
+
concept: {
|
|
64
|
+
uuid: string;
|
|
65
|
+
display: string;
|
|
66
|
+
};
|
|
67
|
+
value: {
|
|
68
|
+
uuid: string;
|
|
69
|
+
display: string;
|
|
70
|
+
};
|
|
71
|
+
}>;
|
|
72
|
+
value: any;
|
|
73
|
+
obsDatetime: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface Encounter {
|
|
77
|
+
uuid: string;
|
|
78
|
+
encounterDatetime: string;
|
|
79
|
+
encounterProviders: Array<{
|
|
80
|
+
uuid: string;
|
|
81
|
+
display: string;
|
|
82
|
+
encounterRole: {
|
|
83
|
+
uuid: string;
|
|
84
|
+
display: string;
|
|
85
|
+
};
|
|
86
|
+
provider: {
|
|
87
|
+
uuid: string;
|
|
88
|
+
person: {
|
|
89
|
+
uuid: string;
|
|
90
|
+
display: string;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
}>;
|
|
94
|
+
encounterType: {
|
|
95
|
+
uuid: string;
|
|
96
|
+
display: string;
|
|
97
|
+
};
|
|
98
|
+
obs: Array<Observation>;
|
|
99
|
+
orders: Array<Order>;
|
|
100
|
+
}
|
|
101
|
+
interface FormParams {
|
|
102
|
+
formUuid: string;
|
|
103
|
+
patientUuid: string;
|
|
104
|
+
visitUuid?: string;
|
|
105
|
+
visitTypeUuid?: string;
|
|
106
|
+
encounterUuid?: string;
|
|
107
|
+
handlePostResponse?: (Encounter) => void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const FormBootstrap = ({
|
|
111
|
+
formUuid,
|
|
112
|
+
patientUuid,
|
|
113
|
+
visitUuid,
|
|
114
|
+
visitTypeUuid,
|
|
115
|
+
encounterUuid,
|
|
116
|
+
handlePostResponse,
|
|
117
|
+
}: FormParams) => {
|
|
118
|
+
const patient = useGetPatient(patientUuid);
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div>
|
|
122
|
+
{formUuid && patientUuid && patient && (
|
|
123
|
+
<ExtensionSlot
|
|
124
|
+
extensionSlotName="form-widget-slot"
|
|
125
|
+
state={{
|
|
126
|
+
view: "form",
|
|
127
|
+
formUuid,
|
|
128
|
+
visitUuid: visitUuid ?? "",
|
|
129
|
+
visitTypeUuid: visitTypeUuid ?? "",
|
|
130
|
+
patientUuid,
|
|
131
|
+
patient,
|
|
132
|
+
encounterUuid: encounterUuid ?? "",
|
|
133
|
+
closeWorkspace: () => {},
|
|
134
|
+
handlePostResponse,
|
|
135
|
+
}}
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export default FormBootstrap;
|
package/src/Root.tsx
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { BrowserRouter, Route, Switch } from "react-router-dom";
|
|
3
3
|
import { appPath } from "./constant";
|
|
4
|
-
|
|
5
|
-
const
|
|
4
|
+
import { FormWorkflowProvider } from "./context/FormWorkflowContext";
|
|
5
|
+
const FormsPage = React.lazy(() => import("./forms-page"));
|
|
6
|
+
const FormEntryWorkflow = React.lazy(() => import("./form-entry-workflow"));
|
|
6
7
|
|
|
7
8
|
const Root = () => {
|
|
8
9
|
return (
|
|
9
10
|
<main>
|
|
10
|
-
<
|
|
11
|
-
<
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
<FormWorkflowProvider>
|
|
12
|
+
<BrowserRouter basename={appPath}>
|
|
13
|
+
<Switch>
|
|
14
|
+
<Route exact path="/" children={<FormsPage />} />
|
|
15
|
+
<Route path="/:formUuid?" children={<FormEntryWorkflow />} />
|
|
16
|
+
</Switch>
|
|
17
|
+
</BrowserRouter>
|
|
18
|
+
</FormWorkflowProvider>
|
|
16
19
|
</main>
|
|
17
20
|
);
|
|
18
21
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React, { useReducer } from "react";
|
|
2
|
+
import reducer from "./FormWorkflowReducer";
|
|
3
|
+
|
|
4
|
+
const initialState = {
|
|
5
|
+
patientUuids: [],
|
|
6
|
+
activePatientUuid: null,
|
|
7
|
+
activeEncounterUuid: null,
|
|
8
|
+
encounters: {},
|
|
9
|
+
addPatient: (uuid: string | number) => {},
|
|
10
|
+
openPatientSearch: () => {},
|
|
11
|
+
saveEncounter: (encounterUuid: string | number) => {},
|
|
12
|
+
editEncounter: (patientUuid: string | number) => {},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const FormWorkflowContext = React.createContext(initialState);
|
|
16
|
+
|
|
17
|
+
const FormWorkflowProvider = ({ children }) => {
|
|
18
|
+
const [state, dispatch] = useReducer(reducer, initialState);
|
|
19
|
+
|
|
20
|
+
const actions = {
|
|
21
|
+
addPatient: (patientUuid) =>
|
|
22
|
+
dispatch({ type: "ADD_PATIENT", patientUuid: patientUuid }),
|
|
23
|
+
openPatientSearch: () => dispatch({ type: "OPEN_PATIENT_SEARCH" }),
|
|
24
|
+
saveEncounter: (encounterUuid) =>
|
|
25
|
+
dispatch({
|
|
26
|
+
type: "SAVE_ENCOUNTER",
|
|
27
|
+
encounterUuid,
|
|
28
|
+
}),
|
|
29
|
+
editEncounter: (patientUuid) =>
|
|
30
|
+
dispatch({ type: "EDIT_ENCOUNTER", patientUuid }),
|
|
31
|
+
};
|
|
32
|
+
return (
|
|
33
|
+
<FormWorkflowContext.Provider value={{ ...state, ...actions }}>
|
|
34
|
+
{children}
|
|
35
|
+
</FormWorkflowContext.Provider>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default FormWorkflowContext;
|
|
40
|
+
export { FormWorkflowProvider };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const reducer = (state, action) => {
|
|
2
|
+
switch (action.type) {
|
|
3
|
+
case "ADD_PATIENT":
|
|
4
|
+
return {
|
|
5
|
+
...state,
|
|
6
|
+
patientUuids: [...state.patientUuids, action.patientUuid],
|
|
7
|
+
activePatientUuid: action.patientUuid,
|
|
8
|
+
activeEncounterUuid: null,
|
|
9
|
+
};
|
|
10
|
+
case "OPEN_PATIENT_SEARCH":
|
|
11
|
+
// this will need to be updated once AMPATH hook is available
|
|
12
|
+
return {
|
|
13
|
+
...state,
|
|
14
|
+
activePatientUuid: null,
|
|
15
|
+
activeEncounterUuid: null,
|
|
16
|
+
};
|
|
17
|
+
case "SAVE_ENCOUNTER":
|
|
18
|
+
return {
|
|
19
|
+
...state,
|
|
20
|
+
encounters: {
|
|
21
|
+
...state.encounters,
|
|
22
|
+
[state.activePatientUuid]: action.encounterUuid,
|
|
23
|
+
},
|
|
24
|
+
activePatientUuid: null,
|
|
25
|
+
activeEncounterUuid: null,
|
|
26
|
+
};
|
|
27
|
+
case "EDIT_ENCOUNTER":
|
|
28
|
+
return {
|
|
29
|
+
...state,
|
|
30
|
+
activeEncounterUuid: state.encounters[action.patientUuid],
|
|
31
|
+
activePatientUuid: action.patientUuid,
|
|
32
|
+
};
|
|
33
|
+
default:
|
|
34
|
+
return state;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default reducer;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
export const EmptyDataIllustration = ({ width = "64", height = "64" }) => {
|
|
4
|
+
return (
|
|
5
|
+
<svg width={width} height={height} viewBox="0 0 64 64">
|
|
6
|
+
<title>Empty data illustration</title>
|
|
7
|
+
<g fill="none" fillRule="evenodd">
|
|
8
|
+
<path
|
|
9
|
+
d="M38.133 13.186H21.947c-.768.001-1.39.623-1.39 1.391V50.55l-.186.057-3.97 1.216a.743.743 0 01-.927-.493L3.664 12.751a.742.742 0 01.492-.926l6.118-1.874 17.738-5.43 6.119-1.873a.741.741 0 01.926.492L38.076 13l.057.186z"
|
|
10
|
+
fill="#F4F4F4"
|
|
11
|
+
/>
|
|
12
|
+
<path
|
|
13
|
+
d="M41.664 13L38.026 1.117A1.576 1.576 0 0036.056.07l-8.601 2.633-17.737 5.43-8.603 2.634a1.578 1.578 0 00-1.046 1.97l12.436 40.616a1.58 1.58 0 001.969 1.046l5.897-1.805.185-.057v-.194l-.185.057-5.952 1.822a1.393 1.393 0 01-1.737-.923L.247 12.682a1.39 1.39 0 01.923-1.738L9.772 8.31 27.51 2.881 36.112.247a1.393 1.393 0 011.737.923L41.47 13l.057.186h.193l-.057-.185z"
|
|
14
|
+
fill="#8D8D8D"
|
|
15
|
+
/>
|
|
16
|
+
<path
|
|
17
|
+
d="M11.378 11.855a.836.836 0 01-.798-.59L9.385 7.361a.835.835 0 01.554-1.042l16.318-4.996a.836.836 0 011.042.554l1.195 3.902a.836.836 0 01-.554 1.043l-16.318 4.995a.831.831 0 01-.244.037z"
|
|
18
|
+
fill="#C6C6C6"
|
|
19
|
+
/>
|
|
20
|
+
<circle fill="#C6C6C6" cx={17.636} cy={2.314} r={1.855} />
|
|
21
|
+
<circle
|
|
22
|
+
fill="#FFF"
|
|
23
|
+
fillRule="nonzero"
|
|
24
|
+
cx={17.636}
|
|
25
|
+
cy={2.314}
|
|
26
|
+
r={1.175}
|
|
27
|
+
/>
|
|
28
|
+
<path
|
|
29
|
+
d="M55.893 53.995H24.544a.79.79 0 01-.788-.789V15.644a.79.79 0 01.788-.788h31.349a.79.79 0 01.788.788v37.562a.79.79 0 01-.788.789z"
|
|
30
|
+
fill="#F4F4F4"
|
|
31
|
+
/>
|
|
32
|
+
<path
|
|
33
|
+
d="M41.47 13H21.948a1.579 1.579 0 00-1.576 1.577V52.4l.185-.057V14.577c.001-.768.623-1.39 1.391-1.39h19.581L41.471 13zm17.02 0H21.947a1.579 1.579 0 00-1.576 1.577v42.478c0 .87.706 1.576 1.576 1.577H58.49a1.579 1.579 0 001.576-1.577V14.577a1.579 1.579 0 00-1.576-1.576zm1.39 44.055c0 .768-.622 1.39-1.39 1.392H21.947c-.768-.001-1.39-.624-1.39-1.392V14.577c0-.768.622-1.39 1.39-1.39H58.49c.768 0 1.39.622 1.39 1.39v42.478z"
|
|
34
|
+
fill="#8D8D8D"
|
|
35
|
+
/>
|
|
36
|
+
<path
|
|
37
|
+
d="M48.751 17.082H31.686a.836.836 0 01-.835-.835v-4.081c0-.46.374-.834.835-.835H48.75c.461 0 .834.374.835.835v4.08c0 .462-.374.835-.835.836z"
|
|
38
|
+
fill="#C6C6C6"
|
|
39
|
+
/>
|
|
40
|
+
<circle fill="#C6C6C6" cx={40.218} cy={9.755} r={1.855} />
|
|
41
|
+
<circle
|
|
42
|
+
fill="#FFF"
|
|
43
|
+
fillRule="nonzero"
|
|
44
|
+
cx={40.218}
|
|
45
|
+
cy={9.755}
|
|
46
|
+
r={1.13}
|
|
47
|
+
/>
|
|
48
|
+
</g>
|
|
49
|
+
</svg>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Tile } from "carbon-components-react";
|
|
3
|
+
import styles from "./styles.scss";
|
|
4
|
+
import { useLayoutType } from "@openmrs/esm-framework";
|
|
5
|
+
import { EmptyDataIllustration } from "./EmptyDataIllustration";
|
|
6
|
+
|
|
7
|
+
export interface EmptyStateProps {
|
|
8
|
+
headerTitle: string;
|
|
9
|
+
displayText: string;
|
|
10
|
+
}
|
|
11
|
+
const EmptyState: React.FC<EmptyStateProps> = ({
|
|
12
|
+
headerTitle,
|
|
13
|
+
displayText,
|
|
14
|
+
}) => {
|
|
15
|
+
const isTablet = useLayoutType() === "tablet";
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Tile light className={styles.tile}>
|
|
19
|
+
<div className={isTablet ? styles.tabletHeading : styles.desktopHeading}>
|
|
20
|
+
<h4>{headerTitle}</h4>
|
|
21
|
+
</div>
|
|
22
|
+
<EmptyDataIllustration />
|
|
23
|
+
<p className={styles.content}>{displayText}</p>
|
|
24
|
+
</Tile>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default EmptyState;
|
|
29
|
+
export { EmptyState };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
@import "~@openmrs/esm-styleguide/src/vars";
|
|
2
|
+
@import "~carbon-components/src/globals/scss/vars";
|
|
3
|
+
@import "~carbon-components/src/globals/scss/mixins";
|
|
4
|
+
|
|
5
|
+
.action {
|
|
6
|
+
margin-bottom: $spacing-03;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.content {
|
|
10
|
+
@include carbon--type-style("productive-heading-01");
|
|
11
|
+
color: $text-02;
|
|
12
|
+
margin-top: $spacing-05;
|
|
13
|
+
margin-bottom: $spacing-03;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.desktopHeading {
|
|
17
|
+
h4 {
|
|
18
|
+
@include carbon--type-style('productive-heading-02');
|
|
19
|
+
color: $text-02;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.tabletHeading {
|
|
24
|
+
h4 {
|
|
25
|
+
@include carbon--type-style('productive-heading-03');
|
|
26
|
+
color: $text-02;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.desktopHeading, .tabletHeading {
|
|
31
|
+
text-align: left;
|
|
32
|
+
text-transform: capitalize;
|
|
33
|
+
margin-bottom: $spacing-05;
|
|
34
|
+
|
|
35
|
+
h4:after {
|
|
36
|
+
content: "";
|
|
37
|
+
display: block;
|
|
38
|
+
width: 2rem;
|
|
39
|
+
padding-top: 0.188rem;
|
|
40
|
+
border-bottom: 0.375rem solid var(--brand-03);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.heading:after {
|
|
45
|
+
content: "";
|
|
46
|
+
display: block;
|
|
47
|
+
width: 2rem;
|
|
48
|
+
padding-top: 0.188rem;
|
|
49
|
+
border-bottom: 0.375rem solid var(--brand-03);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.tile {
|
|
53
|
+
text-align: center;
|
|
54
|
+
border: 1px solid $ui-03;
|
|
55
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ExtensionSlot } from "@openmrs/esm-framework";
|
|
2
|
+
import { Button } from "carbon-components-react";
|
|
3
|
+
import React, { useContext, useState } from "react";
|
|
4
|
+
import { useHistory, useParams } from "react-router-dom";
|
|
5
|
+
import FormBootstrap from "../FormBootstrap";
|
|
6
|
+
import PatientCard from "../patient-card/PatientCard";
|
|
7
|
+
import PatientBanner from "../patient-banner";
|
|
8
|
+
import styles from "./styles.scss";
|
|
9
|
+
import PatientSearchHeader from "../patient-search-header";
|
|
10
|
+
import { useTranslation } from "react-i18next";
|
|
11
|
+
import FormWorkflowContext from "../context/FormWorkflowContext";
|
|
12
|
+
|
|
13
|
+
interface ParamTypes {
|
|
14
|
+
formUuid: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const FormEntryWorkflow = () => {
|
|
18
|
+
const { formUuid } = useParams() as ParamTypes;
|
|
19
|
+
const history = useHistory();
|
|
20
|
+
const {
|
|
21
|
+
patientUuids,
|
|
22
|
+
activePatientUuid,
|
|
23
|
+
activeEncounterUuid,
|
|
24
|
+
openPatientSearch,
|
|
25
|
+
saveEncounter,
|
|
26
|
+
} = useContext(FormWorkflowContext);
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
|
|
29
|
+
const handlePostResponse = (encounter) => {
|
|
30
|
+
if (encounter && encounter.uuid) {
|
|
31
|
+
saveEncounter(encounter.uuid);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div>
|
|
37
|
+
<div className={styles.breadcrumbsContainer}>
|
|
38
|
+
<ExtensionSlot extensionSlotName="breadcrumbs-slot" />
|
|
39
|
+
</div>
|
|
40
|
+
{!activePatientUuid && <PatientSearchHeader />}
|
|
41
|
+
{activePatientUuid && <PatientBanner patientUuid={activePatientUuid} />}
|
|
42
|
+
<div className={styles.workspaceWrapper}>
|
|
43
|
+
<div className={styles.workspace}>
|
|
44
|
+
{!patientUuids.length && (
|
|
45
|
+
<div className={styles.selectPatientMessage}>
|
|
46
|
+
{t("selectPatientFirst", "Please select a patient first")}
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
{!!patientUuids.length && (
|
|
50
|
+
<div className={styles.formMainContent}>
|
|
51
|
+
<div className={styles.formContainer}>
|
|
52
|
+
<FormBootstrap
|
|
53
|
+
patientUuid={activePatientUuid}
|
|
54
|
+
encounterUuid={activeEncounterUuid}
|
|
55
|
+
{...{
|
|
56
|
+
formUuid,
|
|
57
|
+
handlePostResponse,
|
|
58
|
+
}}
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
<div className={styles.rightPanel}>
|
|
62
|
+
<h4>Forms filled</h4>
|
|
63
|
+
<div className={styles.patientCardsSection}>
|
|
64
|
+
{patientUuids.map((patientUuid) => (
|
|
65
|
+
<PatientCard patientUuid={patientUuid} key={patientUuid} />
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
<div className={styles.rightPanelActionButtons}>
|
|
69
|
+
<Button kind="primary" onClick={() => openPatientSearch()}>
|
|
70
|
+
{t("nextPatient", "Next Patient")}
|
|
71
|
+
</Button>
|
|
72
|
+
<Button kind="secondary" disabled>
|
|
73
|
+
{t("reviewSave", "Review & Save")}
|
|
74
|
+
</Button>
|
|
75
|
+
<Button kind="tertiary" onClick={() => history.push("/")}>
|
|
76
|
+
{t("cancel", "Cancel")}
|
|
77
|
+
</Button>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export default FormEntryWorkflow;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
@import "~@openmrs/esm-styleguide/src/vars";
|
|
2
|
+
@import "~carbon-components/src/globals/scss/vars";
|
|
3
|
+
@import "~carbon-components/src/globals/scss/mixins";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
.breadcrumbsContainer > div > div > nav {
|
|
7
|
+
background-color: white;
|
|
8
|
+
padding: 0.5rem;
|
|
9
|
+
border-bottom: 1px solid $openmrs-background-grey;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.workspaceWrapper {
|
|
13
|
+
display: flex;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.workspace {
|
|
18
|
+
width: 1100px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.selectPatientMessage {
|
|
22
|
+
@include carbon--type-style('productive-heading-03');
|
|
23
|
+
margin: $spacing-07;
|
|
24
|
+
text-align: center;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.formMainContent {
|
|
28
|
+
display: flex;
|
|
29
|
+
text-align: center;
|
|
30
|
+
margin-top: 1rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.formContainer {
|
|
34
|
+
flex-grow: 1;
|
|
35
|
+
max-height: calc(100vh - 14rem);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.rightPanel {
|
|
39
|
+
width: 13rem;
|
|
40
|
+
text-align: left;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.patientCardsSection {
|
|
44
|
+
margin: 1rem 0;
|
|
45
|
+
border-bottom: 1px solid $carbon--gray-10;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.rightPanelActionButtons {
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
row-gap: 0.5rem;
|
|
52
|
+
& button {
|
|
53
|
+
width: 100%;
|
|
54
|
+
text-decoration: "none";
|
|
55
|
+
& :hover {
|
|
56
|
+
background-color: $carbon--gray-30;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useConfig } from "@openmrs/esm-framework";
|
|
2
|
+
import { Tab, Tabs } from "carbon-components-react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Config } from "../config-schema";
|
|
5
|
+
import { useGetAllForms } from "../hooks";
|
|
6
|
+
import FormsTable from "../forms-table";
|
|
7
|
+
import styles from "./styles.scss";
|
|
8
|
+
import { useTranslation } from "react-i18next";
|
|
9
|
+
|
|
10
|
+
const cleanForms = (rawFormData) => {
|
|
11
|
+
if (rawFormData) {
|
|
12
|
+
return rawFormData?.map((form) => ({
|
|
13
|
+
...form,
|
|
14
|
+
id: form.uuid,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const FormsPage = () => {
|
|
21
|
+
const config = useConfig() as Config;
|
|
22
|
+
const { t } = useTranslation();
|
|
23
|
+
const { formCategories, formCategoriesToShow } = config;
|
|
24
|
+
const { forms, isLoading, error } = useGetAllForms();
|
|
25
|
+
const cleanRows = cleanForms(forms);
|
|
26
|
+
|
|
27
|
+
const categoryRows = formCategoriesToShow.map((name) => {
|
|
28
|
+
const category = formCategories.find((category) => category.name === name);
|
|
29
|
+
let rows = [];
|
|
30
|
+
if (category && cleanRows && cleanRows.length) {
|
|
31
|
+
const uuids = category.forms?.map((form) => form.formUUID);
|
|
32
|
+
rows = cleanRows.filter((row) => uuids.includes(row.uuid));
|
|
33
|
+
}
|
|
34
|
+
return { ...{ name, rows } };
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div className={styles.mainContent}>
|
|
39
|
+
<h3 className={styles.pageTitle}>{t("forms", "Forms")}</h3>
|
|
40
|
+
<Tabs type="container">
|
|
41
|
+
<Tab label={t("allForms", "All Forms")}>
|
|
42
|
+
<FormsTable rows={cleanRows} {...{ error, isLoading }} />
|
|
43
|
+
</Tab>
|
|
44
|
+
{categoryRows?.map((category, index) => (
|
|
45
|
+
<Tab label={category.name} key={index}>
|
|
46
|
+
<FormsTable rows={category.rows} {...{ error, isLoading }} />
|
|
47
|
+
</Tab>
|
|
48
|
+
))}
|
|
49
|
+
</Tabs>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default FormsPage;
|