@pih/esm-commons-app 2.1.1-pre.9 → 2.1.1-pre.93
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/.turbo/turbo-build.log +29 -27
- package/dist/123.js +2 -0
- package/dist/123.js.LICENSE.txt +9 -0
- package/dist/123.js.map +1 -0
- package/dist/157.js +2 -0
- package/dist/157.js.LICENSE.txt +40 -0
- package/dist/157.js.map +1 -0
- package/dist/300.js +1 -1
- package/dist/304.js +1 -0
- package/dist/304.js.map +1 -0
- package/dist/400.js +1 -0
- package/dist/400.js.map +1 -0
- package/dist/41.js +1 -1
- package/dist/41.js.map +1 -1
- package/dist/421.js +1 -0
- package/dist/421.js.map +1 -0
- package/dist/47.js +1 -0
- package/dist/47.js.map +1 -0
- package/dist/481.js +1 -0
- package/dist/481.js.map +1 -0
- package/dist/502.js +1 -0
- package/dist/502.js.map +1 -0
- package/dist/55.js +1 -1
- package/dist/659.js +1 -0
- package/dist/659.js.map +1 -0
- package/dist/685.js +1 -0
- package/dist/685.js.map +1 -0
- package/dist/704.js +1 -0
- package/dist/704.js.map +1 -0
- package/dist/737.js +2 -0
- package/dist/737.js.LICENSE.txt +38 -0
- package/dist/737.js.map +1 -0
- package/dist/773.js +1 -0
- package/dist/773.js.map +1 -0
- package/dist/848.js +1 -0
- package/dist/848.js.map +1 -0
- package/dist/92.js +2 -0
- package/dist/92.js.LICENSE.txt +9 -0
- package/dist/92.js.map +1 -0
- package/dist/99.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/pih-esm-commons-app.js +1 -1
- package/dist/pih-esm-commons-app.js.buildmanifest.json +314 -66
- package/dist/pih-esm-commons-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +3 -7
- package/src/declarations.d.ts +2 -0
- package/src/hooks/useEncounters.ts +22 -0
- package/src/hooks/useProgramEnrollment.ts +19 -0
- package/src/index.ts +28 -9
- package/src/routes.json +58 -9
- package/src/service-queues-app/maternal-triage-form.workspace.tsx +111 -0
- package/src/service-queues-app/maternal-triage-queue-actions.extension.tsx +132 -0
- package/src/service-queues-app/maternal-triage-queue-actions.resource.ts +80 -0
- package/src/service-queues-app/maternal-trial-queue-actions.scss +14 -0
- package/src/service-queues-app/types.ts +58 -0
- package/src/ward-app/o2-iframe.component.tsx +86 -0
- package/src/ward-app/o2-iframe.scss +20 -0
- package/src/ward-app/o2-pregnancy-infant-dashboard.extension.tsx +87 -0
- package/src/ward-app/o2-pregnancy-infant-dashboard.scss +5 -0
- package/src/ward-app/o2-visit-summary-action-button.component.tsx +17 -0
- package/src/ward-app/o2-visit-summary-workspace.component.tsx +28 -23
- package/src/ward-app/o2-vital-signs-action-button.component.tsx +17 -0
- package/src/ward-app/o2-vital-signs-workspace.component.tsx +61 -0
- package/src/ward-app/types.ts +19 -4
- package/translations/en.json +16 -2
- package/dist/138.js +0 -1
- package/dist/138.js.map +0 -1
- package/dist/291.js +0 -1
- package/dist/291.js.map +0 -1
- package/dist/39.js +0 -1
- package/dist/39.js.map +0 -1
- package/dist/641.js +0 -1
- package/dist/641.js.map +0 -1
- package/dist/831.js +0 -2
- package/dist/831.js.LICENSE.txt +0 -5
- package/dist/831.js.map +0 -1
- package/dist/90.js +0 -1
- package/dist/90.js.map +0 -1
- package/src/ward-app/o2-visit-summary-action-button.extension.tsx +0 -18
- package/src/ward-app/o2-visit-summary-workspace.scss +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pih/esm-commons-app",
|
|
3
|
-
"version": "2.1.1-pre.
|
|
3
|
+
"version": "2.1.1-pre.93",
|
|
4
4
|
"description": "An app to define extensions to be slotted into other apps that are not PIH specific.",
|
|
5
5
|
"browser": "dist/pih-esm-commons-app.js",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js --color",
|
|
19
19
|
"coverage": "yarn test --coverage",
|
|
20
20
|
"typescript": "tsc",
|
|
21
|
-
"extract-translations": "i18next 'src/**/*.component.tsx'"
|
|
21
|
+
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.extension.tsx' 'src/**/*modal.tsx' 'src/**/*.workspace.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js"
|
|
22
22
|
},
|
|
23
23
|
"browserslist": [
|
|
24
24
|
"extends browserslist-config-openmrs"
|
|
@@ -38,18 +38,14 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@babel/runtime": "^7.24.0",
|
|
41
|
-
"@carbon/react": "~1.37.0",
|
|
42
41
|
"moment": "^2.30.1",
|
|
43
42
|
"react-dates": "^21.8.0",
|
|
44
43
|
"webpack": "^5.74.0"
|
|
45
44
|
},
|
|
46
45
|
"peerDependencies": {
|
|
47
46
|
"@openmrs/esm-framework": "5.x",
|
|
48
|
-
"i18next": "^19.0.0",
|
|
49
47
|
"react": "18.x",
|
|
50
|
-
"react-i18next": "
|
|
51
|
-
"react-router-dom": "^6.x",
|
|
52
|
-
"swr": "2.x"
|
|
48
|
+
"react-i18next": "16.x"
|
|
53
49
|
},
|
|
54
50
|
"devDependencies": {
|
|
55
51
|
"webpack": "^5.74.0"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
|
|
2
|
+
import { type Encounter } from '../service-queues-app/types';
|
|
3
|
+
|
|
4
|
+
interface EncounterSearchParams {
|
|
5
|
+
patient: string;
|
|
6
|
+
visit?: string;
|
|
7
|
+
encounterType?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function useEncounters(params: EncounterSearchParams) {
|
|
11
|
+
const url = `${restBaseUrl}/encounter?`;
|
|
12
|
+
const searchParams = new URLSearchParams();
|
|
13
|
+
searchParams.append('patient', params.patient);
|
|
14
|
+
if (params.visit) {
|
|
15
|
+
searchParams.append('visit', params.visit);
|
|
16
|
+
}
|
|
17
|
+
if (params.encounterType) {
|
|
18
|
+
searchParams.append('encounterType', params.encounterType);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return useOpenmrsFetchAll<Encounter>(url + searchParams.toString());
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
+
import useSWR from 'swr';
|
|
3
|
+
const customRepresentation = `custom:(uuid,display,program,dateEnrolled,dateCompleted,location:(uuid,display))`;
|
|
4
|
+
|
|
5
|
+
export interface PatientProgram {
|
|
6
|
+
uuid: string;
|
|
7
|
+
program: {
|
|
8
|
+
uuid: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const useActivePatientEnrollment = (patientUuid: string) => {
|
|
13
|
+
const result = useSWR<{ data: { results: Array<PatientProgram> } }>(
|
|
14
|
+
patientUuid ? `${restBaseUrl}/programenrollment?patient=${patientUuid}&v=${customRepresentation}` : null,
|
|
15
|
+
openmrsFetch,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
return result;
|
|
19
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -8,23 +8,42 @@
|
|
|
8
8
|
import { getAsyncLifecycle } from '@openmrs/esm-framework';
|
|
9
9
|
|
|
10
10
|
const moduleName = '@pih/esm-commons-app';
|
|
11
|
-
const options = {
|
|
12
|
-
featureName: 'commons',
|
|
13
|
-
moduleName,
|
|
14
|
-
};
|
|
15
11
|
|
|
16
12
|
export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
|
|
17
13
|
|
|
18
|
-
// export const root = getAsyncLifecycle(() => import('./root.component'), options);
|
|
19
|
-
|
|
20
14
|
export const o2VisitSummaryWorkspaceSideRailIcon = getAsyncLifecycle(
|
|
21
|
-
() => import('./ward-app/o2-visit-summary-action-button.
|
|
22
|
-
|
|
15
|
+
() => import('./ward-app/o2-visit-summary-action-button.component'),
|
|
16
|
+
{ featureName: 'o2VisitSummaryWorkspaceSideRailIcon', moduleName },
|
|
23
17
|
);
|
|
24
18
|
|
|
25
19
|
export const o2VisitSummaryWorkspace = getAsyncLifecycle(
|
|
26
20
|
() => import('./ward-app/o2-visit-summary-workspace.component'),
|
|
27
|
-
|
|
21
|
+
{ featureName: 'o2VisitSummaryWorkspace', moduleName },
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const o2VitalSignsWorkspaceSideRailIcon = getAsyncLifecycle(
|
|
25
|
+
() => import('./ward-app/o2-vital-signs-action-button.component'),
|
|
26
|
+
{ featureName: 'o2VitalSignsWorkspaceSideRailIcon', moduleName },
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const o2VitalSignsWorkspace = getAsyncLifecycle(() => import('./ward-app/o2-vital-signs-workspace.component'), {
|
|
30
|
+
featureName: 'o2VitalSignsWorkspace',
|
|
31
|
+
moduleName,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const o2PregnancyInfantDashboard = getAsyncLifecycle(
|
|
35
|
+
() => import('./ward-app/o2-pregnancy-infant-dashboard.extension'),
|
|
36
|
+
{ featureName: 'o2PregnancyInfantDashboard', moduleName },
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export const maternalTriageFormWorkspace = getAsyncLifecycle(
|
|
40
|
+
() => import('./service-queues-app/maternal-triage-form.workspace'),
|
|
41
|
+
{ featureName: 'maternalTriageFormWorkspace', moduleName },
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const triageWaitingQueueActions = getAsyncLifecycle(
|
|
45
|
+
() => import('./service-queues-app/maternal-triage-queue-actions.extension'),
|
|
46
|
+
{ featureName: 'triageWaitingQueueActions', moduleName },
|
|
28
47
|
);
|
|
29
48
|
|
|
30
49
|
export function startupApp() {}
|
package/src/routes.json
CHANGED
|
@@ -1,23 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.openmrs.org/routes.schema.json",
|
|
3
3
|
"pages": [
|
|
4
|
+
{
|
|
5
|
+
"component": "root",
|
|
6
|
+
"route": "appointments"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"component": "root",
|
|
10
|
+
"route": "service-queues"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"component": "root",
|
|
14
|
+
"route": "dispensing2"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"component": "root",
|
|
18
|
+
"route": "ward"
|
|
19
|
+
}
|
|
4
20
|
],
|
|
5
21
|
"extensions": [
|
|
6
22
|
{
|
|
7
|
-
"name": "o2-
|
|
8
|
-
"component": "
|
|
9
|
-
"slot": "
|
|
23
|
+
"name": "o2-pregnancy-infant-dashboard",
|
|
24
|
+
"component": "o2PregnancyInfantDashboard",
|
|
25
|
+
"slot": "ward-patient-workspace-content-slot"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "triage-waiting-queue-actions",
|
|
29
|
+
"component": "triageWaitingQueueActions",
|
|
30
|
+
"slot": "queue-table-triage-waiting-queue-actions-slot"
|
|
10
31
|
}
|
|
11
32
|
],
|
|
12
|
-
"
|
|
33
|
+
"workspaces2": [
|
|
13
34
|
{
|
|
14
35
|
"name": "o2-visit-summary-workspace",
|
|
15
36
|
"component": "o2VisitSummaryWorkspace",
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
"
|
|
37
|
+
"window": "o2-visit-summary-window"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "o2-vital-signs-workspace",
|
|
41
|
+
"component": "o2VitalSignsWorkspace",
|
|
42
|
+
"window": "o2-vital-signs-window"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "maternal-triage-form-workspace",
|
|
46
|
+
"component": "maternalTriageFormWorkspace",
|
|
47
|
+
"window": "maternal-triage-form-window"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"workspaceWindows2": [
|
|
51
|
+
{
|
|
52
|
+
"name": "o2-visit-summary-window",
|
|
53
|
+
"icon": "o2VisitSummaryWorkspaceSideRailIcon",
|
|
54
|
+
"group": "ward-patient",
|
|
55
|
+
"width": "extra-wide",
|
|
56
|
+
"canMaximize": true
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "o2-vital-signs-window",
|
|
60
|
+
"icon": "o2VitalSignsWorkspaceSideRailIcon",
|
|
61
|
+
"group": "ward-patient",
|
|
62
|
+
"width": "extra-wide",
|
|
63
|
+
"canMaximize": true
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "maternal-triage-form-window",
|
|
67
|
+
"group": "service-queues",
|
|
68
|
+
"width": "extra-wide",
|
|
69
|
+
"canMaximize": true
|
|
21
70
|
}
|
|
22
71
|
]
|
|
23
72
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { type Patient, showSnackbar, Workspace2, type Workspace2DefinitionProps } from '@openmrs/esm-framework';
|
|
2
|
+
import React, { useEffect } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import O2IFrame from '../ward-app/o2-iframe.component';
|
|
5
|
+
import { updateQueueEntry, useMutateQueueEntries } from './maternal-triage-queue-actions.resource';
|
|
6
|
+
import { type QueueEntry } from './types';
|
|
7
|
+
import { useEncounters } from '../hooks/useEncounters';
|
|
8
|
+
import { Loading } from '@carbon/react';
|
|
9
|
+
import { InlineNotification } from '@carbon/react';
|
|
10
|
+
|
|
11
|
+
interface MaternalTriageFormWorkspaceProps {
|
|
12
|
+
queueEntry: QueueEntry;
|
|
13
|
+
patient: Patient;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const MATERNAL_TRIAGE_FORM_ENCOUNTER_TYPE = '41911448-71a1-43d7-bba8-dc86339850da';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Workspace to display the Maternal Triage HTML Form, rendered in a iframe
|
|
20
|
+
*/
|
|
21
|
+
const MaternalTriageFormWorkspace: React.FC<Workspace2DefinitionProps<MaternalTriageFormWorkspaceProps>> = ({
|
|
22
|
+
workspaceProps: { queueEntry, patient },
|
|
23
|
+
closeWorkspace,
|
|
24
|
+
}) => {
|
|
25
|
+
const { t } = useTranslation();
|
|
26
|
+
const { mutateQueueEntries } = useMutateQueueEntries();
|
|
27
|
+
const {
|
|
28
|
+
data: filledOutTriageForms,
|
|
29
|
+
isLoading,
|
|
30
|
+
error,
|
|
31
|
+
} = useEncounters({
|
|
32
|
+
patient: patient.uuid,
|
|
33
|
+
visit: queueEntry.visit.uuid,
|
|
34
|
+
encounterType: MATERNAL_TRIAGE_FORM_ENCOUNTER_TYPE,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const onMessage = async (event: MessageEvent) => {
|
|
39
|
+
if (event.data == 'triageFormSubmitted') {
|
|
40
|
+
const endQueueEntry = () => {
|
|
41
|
+
return updateQueueEntry(queueEntry.uuid, {
|
|
42
|
+
endedAt: new Date().toISOString(),
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
await endQueueEntry();
|
|
47
|
+
await mutateQueueEntries();
|
|
48
|
+
closeWorkspace({ discardUnsavedChanges: true });
|
|
49
|
+
showSnackbar({
|
|
50
|
+
isLowContrast: true,
|
|
51
|
+
kind: 'success',
|
|
52
|
+
title: t('triageFormSubmitted', 'Triage form successfully submitted for {{patient}}.', {
|
|
53
|
+
patient: patient.person.display,
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
window.addEventListener('message', onMessage);
|
|
60
|
+
return () => window.removeEventListener('message', onMessage);
|
|
61
|
+
}, []);
|
|
62
|
+
|
|
63
|
+
const patientUuid = patient.uuid;
|
|
64
|
+
const visitUuid = queueEntry.visit.uuid;
|
|
65
|
+
|
|
66
|
+
const elementsToHide = [
|
|
67
|
+
'header',
|
|
68
|
+
'#breadcrumbs',
|
|
69
|
+
|
|
70
|
+
// prevent O2 success toast from showing; After submitting form for a patient,
|
|
71
|
+
// the success toast for that patient shows when opening form for another patient
|
|
72
|
+
'.toast-type-success',
|
|
73
|
+
// UHM-8822: remove Cancel button from the triage form
|
|
74
|
+
'.cancel',
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const customJavaScript = `
|
|
78
|
+
htmlForm.setSuccessFunction(() => window.top.postMessage('triageFormSubmitted'))
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
if (isLoading) {
|
|
82
|
+
return <Loading withOverlay={false} small />;
|
|
83
|
+
} else if (error) {
|
|
84
|
+
return (
|
|
85
|
+
<InlineNotification
|
|
86
|
+
kind="error"
|
|
87
|
+
lowContrast={true}
|
|
88
|
+
hideCloseButton={true}
|
|
89
|
+
title={t('errorLoadingPatientForm', 'Error loading patient form')}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
} else {
|
|
93
|
+
// If patient does not have triage form filled out already, we load a new one,
|
|
94
|
+
// else, we load the last filled out form to edit
|
|
95
|
+
const src =
|
|
96
|
+
filledOutTriageForms.length == 0
|
|
97
|
+
? `${window.openmrsBase}/htmlformentryui/htmlform/enterHtmlFormWithStandardUi.page?patientId=${patientUuid}&visitId=${visitUuid}&definitionUiResource=file:configuration/pih/htmlforms/triage.xml&returnUrl=%2Fopenmrs%2Fcoreapps%2Fclinicianfacing%2Fpatient.page%3FpatientId%3D${patientUuid}%26`
|
|
98
|
+
: `${window.openmrsBase}/htmlformentryui/htmlform/editHtmlFormWithStandardUi.page?patientId=${patientUuid}&encounterId=${filledOutTriageForms[filledOutTriageForms.length - 1].uuid}`;
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<Workspace2
|
|
102
|
+
title={t('maternalTriageForm', 'Maternal triage form')}
|
|
103
|
+
hasUnsavedChanges={true} // assume there are unsaved changes to prevent accidental closure
|
|
104
|
+
>
|
|
105
|
+
<O2IFrame key={patientUuid} src={src} elementsToHide={elementsToHide} customJavaScript={customJavaScript} />
|
|
106
|
+
</Workspace2>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export default MaternalTriageFormWorkspace;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Button, OverflowMenu, OverflowMenuItem } from '@carbon/react';
|
|
2
|
+
import { isDesktop, launchWorkspace2, showModal, useConfig, useLayoutType } from '@openmrs/esm-framework';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import styles from './maternal-trial-queue-actions.scss';
|
|
6
|
+
import { type QueueEntry } from './types';
|
|
7
|
+
import { transitionQueueEntry, useMutateQueueEntries } from './maternal-triage-queue-actions.resource';
|
|
8
|
+
|
|
9
|
+
// types taken from esm-service-queues-app
|
|
10
|
+
interface QueueTableCellComponentProps {
|
|
11
|
+
queueEntry: QueueEntry;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ConfigObject {
|
|
15
|
+
concepts: {
|
|
16
|
+
defaultTransitionStatus: string;
|
|
17
|
+
};
|
|
18
|
+
// other fields not shown
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* This extension provides an extra "Triage" action, along with the other standard actions for
|
|
23
|
+
* queue entries in the queues table. The Triage action opens the maternal triage form, and also
|
|
24
|
+
* has the side effect of putting the patient's queue entry into the "in service" status, if they have
|
|
25
|
+
* not yet already
|
|
26
|
+
* @param param0
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
const MaternalTriageQueueActions: React.FC<QueueTableCellComponentProps> = ({ queueEntry }) => {
|
|
30
|
+
const { t } = useTranslation();
|
|
31
|
+
const layout = useLayoutType();
|
|
32
|
+
|
|
33
|
+
const { mutateQueueEntries } = useMutateQueueEntries();
|
|
34
|
+
const { concepts } = useConfig<ConfigObject>({ externalModuleName: '@openmrs/esm-service-queues-app' });
|
|
35
|
+
const inServiceStatus = concepts.defaultTransitionStatus;
|
|
36
|
+
|
|
37
|
+
const { patient } = queueEntry;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className={styles.actionsCell}>
|
|
41
|
+
<Button
|
|
42
|
+
kind="ghost"
|
|
43
|
+
aria-label={t('triage', 'Triage')}
|
|
44
|
+
onClick={async () => {
|
|
45
|
+
if (queueEntry.status.uuid !== inServiceStatus) {
|
|
46
|
+
const res = await transitionQueueEntry({
|
|
47
|
+
queueEntryToTransition: queueEntry.uuid,
|
|
48
|
+
newStatus: inServiceStatus,
|
|
49
|
+
});
|
|
50
|
+
mutateQueueEntries();
|
|
51
|
+
const updatedQueueEntry = { ...res.data, visit: queueEntry.visit };
|
|
52
|
+
launchWorkspace2('maternal-triage-form-workspace', { queueEntry: updatedQueueEntry, patient });
|
|
53
|
+
} else {
|
|
54
|
+
launchWorkspace2('maternal-triage-form-workspace', { queueEntry, patient });
|
|
55
|
+
}
|
|
56
|
+
}}
|
|
57
|
+
size={isDesktop(layout) ? 'sm' : 'lg'}>
|
|
58
|
+
{t('triage', 'Triage')}
|
|
59
|
+
</Button>
|
|
60
|
+
|
|
61
|
+
<OverflowMenu aria-label="Actions menu" size={isDesktop(layout) ? 'sm' : 'lg'} align="left" flipped>
|
|
62
|
+
<OverflowMenuItem
|
|
63
|
+
className={styles.menuItem}
|
|
64
|
+
aria-label={t('transition', 'Transition')}
|
|
65
|
+
hasDivider
|
|
66
|
+
onClick={() => {
|
|
67
|
+
const dispose = showModal('transition-queue-entry-modal', {
|
|
68
|
+
closeModal: () => dispose(),
|
|
69
|
+
queueEntry,
|
|
70
|
+
});
|
|
71
|
+
}}
|
|
72
|
+
itemText={t('transition', 'Transition')}
|
|
73
|
+
/>
|
|
74
|
+
<OverflowMenuItem
|
|
75
|
+
className={styles.menuItem}
|
|
76
|
+
aria-label={t('edit', 'Edit')}
|
|
77
|
+
hasDivider
|
|
78
|
+
onClick={() => {
|
|
79
|
+
const dispose = showModal('edit-queue-entry-modal', {
|
|
80
|
+
closeModal: () => dispose(),
|
|
81
|
+
queueEntry,
|
|
82
|
+
});
|
|
83
|
+
}}
|
|
84
|
+
itemText={t('edit', 'Edit')}
|
|
85
|
+
/>
|
|
86
|
+
<OverflowMenuItem
|
|
87
|
+
className={styles.menuItem}
|
|
88
|
+
aria-label={t('removePatient', 'Remove patient')}
|
|
89
|
+
hasDivider
|
|
90
|
+
onClick={() => {
|
|
91
|
+
const dispose = showModal('remove-queue-entry-modal', {
|
|
92
|
+
closeModal: () => dispose(),
|
|
93
|
+
queueEntry,
|
|
94
|
+
});
|
|
95
|
+
}}
|
|
96
|
+
itemText={t('removePatient', 'Remove patient')}
|
|
97
|
+
/>
|
|
98
|
+
{queueEntry.previousQueueEntry == null ? (
|
|
99
|
+
<OverflowMenuItem
|
|
100
|
+
className={styles.menuItem}
|
|
101
|
+
aria-label={t('delete', 'Delete')}
|
|
102
|
+
hasDivider
|
|
103
|
+
isDelete
|
|
104
|
+
onClick={() => {
|
|
105
|
+
const dispose = showModal('delete-queue-entry-modal', {
|
|
106
|
+
closeModal: () => dispose(),
|
|
107
|
+
queueEntry,
|
|
108
|
+
});
|
|
109
|
+
}}
|
|
110
|
+
itemText={t('delete', 'Delete')}
|
|
111
|
+
/>
|
|
112
|
+
) : (
|
|
113
|
+
<OverflowMenuItem
|
|
114
|
+
className={styles.menuItem}
|
|
115
|
+
aria-label={t('undoTransition', 'Undo transition')}
|
|
116
|
+
hasDivider
|
|
117
|
+
isDelete
|
|
118
|
+
onClick={() => {
|
|
119
|
+
const dispose = showModal('undo-transition-queue-entry-modal', {
|
|
120
|
+
closeModal: () => dispose(),
|
|
121
|
+
queueEntry,
|
|
122
|
+
});
|
|
123
|
+
}}
|
|
124
|
+
itemText={t('undoTransition', 'Undo transition')}
|
|
125
|
+
/>
|
|
126
|
+
)}
|
|
127
|
+
</OverflowMenu>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export default MaternalTriageQueueActions;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type Concept, type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
|
|
2
|
+
import { useSWRConfig } from 'swr';
|
|
3
|
+
import { type QueueEntry } from './types';
|
|
4
|
+
|
|
5
|
+
// Hooks here copied from esm-service-queues-app
|
|
6
|
+
|
|
7
|
+
export function useMutateQueueEntries() {
|
|
8
|
+
const { mutate } = useSWRConfig();
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
mutateQueueEntries: () => {
|
|
12
|
+
return mutate((key) => {
|
|
13
|
+
return (
|
|
14
|
+
typeof key === 'string' &&
|
|
15
|
+
(key.includes(`${restBaseUrl}/queue-entry`) || key.includes(`${restBaseUrl}/visit-queue-entry`))
|
|
16
|
+
);
|
|
17
|
+
}).then(() => {
|
|
18
|
+
window.dispatchEvent(new CustomEvent('queue-entry-updated'));
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TransitionQueueEntryParams {
|
|
25
|
+
queueEntryToTransition: string;
|
|
26
|
+
transitionDate?: string;
|
|
27
|
+
newQueue?: string;
|
|
28
|
+
newStatus?: string;
|
|
29
|
+
newPriority?: string;
|
|
30
|
+
newPriorityComment?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A transition is defined as an action that ends a current queue entry and immediately starts a new one
|
|
35
|
+
* with (slightly) different values. For now, this could be used to transition the queue entry's status,
|
|
36
|
+
* priority or queue. This allows us to keep a history of queue entries through a patient's visit.
|
|
37
|
+
* Note that there are some use cases (like RDE or data correction) where a transition is NOT appropriate.
|
|
38
|
+
* @param params
|
|
39
|
+
* @param abortController
|
|
40
|
+
* @returns
|
|
41
|
+
*/
|
|
42
|
+
export function transitionQueueEntry(
|
|
43
|
+
params: TransitionQueueEntryParams,
|
|
44
|
+
abortController?: AbortController,
|
|
45
|
+
): Promise<FetchResponse<QueueEntry>> {
|
|
46
|
+
return openmrsFetch(`${restBaseUrl}/queue-entry/transition`, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
},
|
|
51
|
+
signal: abortController?.signal,
|
|
52
|
+
body: params,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface UpdateQueueEntryParams {
|
|
57
|
+
status?: Concept;
|
|
58
|
+
priority?: Concept;
|
|
59
|
+
priorityComment?: string;
|
|
60
|
+
sortWeight?: number;
|
|
61
|
+
startedAt?: string;
|
|
62
|
+
endedAt?: string;
|
|
63
|
+
loationWaitingFor?: Location;
|
|
64
|
+
providerWaitingFor?: Location;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function updateQueueEntry(
|
|
68
|
+
queueEntryUuid: string,
|
|
69
|
+
params: UpdateQueueEntryParams,
|
|
70
|
+
abortController?: AbortController,
|
|
71
|
+
) {
|
|
72
|
+
return openmrsFetch(`${restBaseUrl}/queue-entry/${queueEntryUuid}`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: {
|
|
75
|
+
'Content-Type': 'application/json',
|
|
76
|
+
},
|
|
77
|
+
signal: abortController?.signal,
|
|
78
|
+
body: params,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type Concept, type OpenmrsResource, type Patient, type Visit } from '@openmrs/esm-framework';
|
|
2
|
+
|
|
3
|
+
export interface Queue {
|
|
4
|
+
uuid: string;
|
|
5
|
+
display: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
location: Location;
|
|
9
|
+
service: Concept;
|
|
10
|
+
allowedPriorities: Array<Concept>;
|
|
11
|
+
allowedStatuses: Array<Concept>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface QueueEntry {
|
|
15
|
+
uuid: string;
|
|
16
|
+
display: string;
|
|
17
|
+
endedAt: string;
|
|
18
|
+
locationWaitingFor: Location;
|
|
19
|
+
patient: Patient;
|
|
20
|
+
priority: Concept;
|
|
21
|
+
priorityComment: string | null;
|
|
22
|
+
providerWaitingFor: Provider;
|
|
23
|
+
queue: Queue;
|
|
24
|
+
startedAt: string;
|
|
25
|
+
status: Concept;
|
|
26
|
+
visit: Visit;
|
|
27
|
+
sortWeight: number;
|
|
28
|
+
queueComingFrom: Queue;
|
|
29
|
+
previousQueueEntry: QueueEntry;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface Provider extends OpenmrsResource {}
|
|
33
|
+
|
|
34
|
+
export interface Encounter {
|
|
35
|
+
uuid: string;
|
|
36
|
+
encounterDateTime: string;
|
|
37
|
+
encounterProviders: Array<{
|
|
38
|
+
uuid: string;
|
|
39
|
+
display: string;
|
|
40
|
+
encounterRole: {
|
|
41
|
+
uuid: string;
|
|
42
|
+
display: string;
|
|
43
|
+
};
|
|
44
|
+
provider: {
|
|
45
|
+
uuid: string;
|
|
46
|
+
person: {
|
|
47
|
+
uuid: string;
|
|
48
|
+
display: string;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
}>;
|
|
52
|
+
encounterType: {
|
|
53
|
+
uuid: string;
|
|
54
|
+
display: string;
|
|
55
|
+
};
|
|
56
|
+
obs: Array<OpenmrsResource>;
|
|
57
|
+
orders: Array<OpenmrsResource>;
|
|
58
|
+
}
|