@pih/esm-commons-app 2.1.1-pre.10 → 2.1.1-pre.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.turbo/turbo-build.log +5 -33
  2. package/dist/117.js +1 -0
  3. package/dist/117.js.map +1 -0
  4. package/dist/125.js +1 -0
  5. package/dist/125.js.map +1 -0
  6. package/dist/154.js +1 -0
  7. package/dist/154.js.map +1 -0
  8. package/dist/163.js +1 -0
  9. package/dist/163.js.map +1 -0
  10. package/dist/294.js +1 -0
  11. package/dist/294.js.map +1 -0
  12. package/dist/335.js +1 -0
  13. package/dist/335.js.map +1 -0
  14. package/dist/349.js +1 -0
  15. package/dist/349.js.map +1 -0
  16. package/dist/361.js +1 -0
  17. package/dist/361.js.map +1 -0
  18. package/dist/466.js +1 -0
  19. package/dist/466.js.map +1 -0
  20. package/dist/508.js +1 -0
  21. package/dist/508.js.map +1 -0
  22. package/dist/530.js +11 -0
  23. package/dist/530.js.map +1 -0
  24. package/dist/557.js +1 -0
  25. package/dist/557.js.map +1 -0
  26. package/dist/701.js +1 -0
  27. package/dist/701.js.map +1 -0
  28. package/dist/744.js +1 -0
  29. package/dist/744.js.map +1 -0
  30. package/dist/761.js +49 -0
  31. package/dist/761.js.map +1 -0
  32. package/dist/830.js +1 -0
  33. package/dist/830.js.map +1 -0
  34. package/dist/867.js +1 -0
  35. package/dist/867.js.map +1 -0
  36. package/dist/912.js +1 -0
  37. package/dist/912.js.map +1 -0
  38. package/dist/913.js +1 -0
  39. package/dist/913.js.map +1 -0
  40. package/dist/main.js +6 -1
  41. package/dist/main.js.map +1 -1
  42. package/dist/pih-esm-commons-app.js +6 -1
  43. package/dist/pih-esm-commons-app.js.buildmanifest.json +329 -93
  44. package/dist/pih-esm-commons-app.js.map +1 -1
  45. package/dist/routes.json +1 -1
  46. package/package.json +8 -13
  47. package/rspack.config.js +1 -0
  48. package/src/declarations.d.ts +2 -0
  49. package/src/hooks/useEncounters.ts +22 -0
  50. package/src/hooks/useProgramEnrollment.ts +19 -0
  51. package/src/index.ts +28 -9
  52. package/src/routes.json +58 -9
  53. package/src/service-queues-app/maternal-triage-form.workspace.tsx +111 -0
  54. package/src/service-queues-app/maternal-triage-queue-actions.extension.tsx +132 -0
  55. package/src/service-queues-app/maternal-triage-queue-actions.resource.ts +84 -0
  56. package/src/service-queues-app/maternal-trial-queue-actions.scss +14 -0
  57. package/src/service-queues-app/types.ts +58 -0
  58. package/src/ward-app/o2-iframe.component.tsx +86 -0
  59. package/src/ward-app/o2-iframe.scss +20 -0
  60. package/src/ward-app/o2-pregnancy-infant-dashboard.extension.tsx +87 -0
  61. package/src/ward-app/o2-pregnancy-infant-dashboard.scss +5 -0
  62. package/src/ward-app/o2-visit-summary-action-button.component.tsx +17 -0
  63. package/src/ward-app/o2-visit-summary-workspace.component.tsx +72 -26
  64. package/src/ward-app/o2-vital-signs-action-button.component.tsx +17 -0
  65. package/src/ward-app/o2-vital-signs-workspace.component.tsx +61 -0
  66. package/src/ward-app/types.ts +24 -4
  67. package/translations/en.json +18 -2
  68. package/dist/138.js +0 -1
  69. package/dist/138.js.map +0 -1
  70. package/dist/291.js +0 -1
  71. package/dist/291.js.map +0 -1
  72. package/dist/300.js +0 -1
  73. package/dist/39.js +0 -1
  74. package/dist/39.js.map +0 -1
  75. package/dist/41.js +0 -2
  76. package/dist/41.js.LICENSE.txt +0 -9
  77. package/dist/41.js.map +0 -1
  78. package/dist/55.js +0 -1
  79. package/dist/641.js +0 -1
  80. package/dist/641.js.map +0 -1
  81. package/dist/831.js +0 -2
  82. package/dist/831.js.LICENSE.txt +0 -5
  83. package/dist/831.js.map +0 -1
  84. package/dist/90.js +0 -1
  85. package/dist/90.js.map +0 -1
  86. package/dist/99.js +0 -1
  87. package/src/ward-app/o2-visit-summary-action-button.extension.tsx +0 -18
  88. package/src/ward-app/o2-visit-summary-workspace.scss +0 -9
  89. package/webpack.config.js +0 -1
@@ -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,84 @@
1
+ import { type Concept, type FetchResponse, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { useSWRConfig } from 'swr';
3
+ import { type QueueEntry } from './types';
4
+ import { useCallback, useMemo } from 'react';
5
+
6
+ // Hooks here copied from esm-service-queues-app
7
+
8
+ export function useMutateQueueEntries() {
9
+ const { mutate, cache } = useSWRConfig();
10
+ const mutateQueueEntries = useCallback(() => {
11
+ const promises: Promise<unknown>[] = [];
12
+ for (const key of cache.keys()) {
13
+ if (key.includes(`${restBaseUrl}/queue-entry`) || key.includes(`${restBaseUrl}/visit-queue-entry`)) {
14
+ promises.push(mutate(key));
15
+ }
16
+ }
17
+ return Promise.all(promises);
18
+ }, [mutate, cache]);
19
+
20
+ return useMemo(
21
+ () => ({
22
+ mutateQueueEntries,
23
+ }),
24
+ [mutateQueueEntries],
25
+ );
26
+ }
27
+
28
+ interface TransitionQueueEntryParams {
29
+ queueEntryToTransition: string;
30
+ transitionDate?: string;
31
+ newQueue?: string;
32
+ newStatus?: string;
33
+ newPriority?: string;
34
+ newPriorityComment?: string;
35
+ }
36
+
37
+ /**
38
+ * A transition is defined as an action that ends a current queue entry and immediately starts a new one
39
+ * with (slightly) different values. For now, this could be used to transition the queue entry's status,
40
+ * priority or queue. This allows us to keep a history of queue entries through a patient's visit.
41
+ * Note that there are some use cases (like RDE or data correction) where a transition is NOT appropriate.
42
+ * @param params
43
+ * @param abortController
44
+ * @returns
45
+ */
46
+ export function transitionQueueEntry(
47
+ params: TransitionQueueEntryParams,
48
+ abortController?: AbortController,
49
+ ): Promise<FetchResponse<QueueEntry>> {
50
+ return openmrsFetch(`${restBaseUrl}/queue-entry/transition`, {
51
+ method: 'POST',
52
+ headers: {
53
+ 'Content-Type': 'application/json',
54
+ },
55
+ signal: abortController?.signal,
56
+ body: params,
57
+ });
58
+ }
59
+
60
+ interface UpdateQueueEntryParams {
61
+ status?: Concept;
62
+ priority?: Concept;
63
+ priorityComment?: string;
64
+ sortWeight?: number;
65
+ startedAt?: string;
66
+ endedAt?: string;
67
+ loationWaitingFor?: Location;
68
+ providerWaitingFor?: Location;
69
+ }
70
+
71
+ export function updateQueueEntry(
72
+ queueEntryUuid: string,
73
+ params: UpdateQueueEntryParams,
74
+ abortController?: AbortController,
75
+ ) {
76
+ return openmrsFetch(`${restBaseUrl}/queue-entry/${queueEntryUuid}`, {
77
+ method: 'POST',
78
+ headers: {
79
+ 'Content-Type': 'application/json',
80
+ },
81
+ signal: abortController?.signal,
82
+ body: params,
83
+ });
84
+ }
@@ -0,0 +1,14 @@
1
+ .actionCellContainer {
2
+ white-space: nowrap;
3
+ }
4
+
5
+ .menuItem {
6
+ max-width: none;
7
+ }
8
+
9
+ .actionsCell {
10
+ display: flex;
11
+ justify-content: flex-end;
12
+ height: 100%;
13
+ align-items: center;
14
+ }
@@ -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
+ }
@@ -0,0 +1,86 @@
1
+ import { ArrowLeft } from '@carbon/react/icons';
2
+
3
+ import { IconButton, InlineLoading } from '@carbon/react';
4
+ import React, { useMemo, useRef, useState } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import styles from './o2-iframe.scss';
7
+
8
+ interface O2IFrame {
9
+ src: string;
10
+ /**
11
+ * a list of css selectors defining elements to hide within the iframe
12
+ */
13
+ elementsToHide?: string[];
14
+
15
+ /**
16
+ * a list of css selectors defining elements to be made un-clickable within the iframe
17
+ */
18
+ elementsToDisable?: string[];
19
+
20
+ /**
21
+ * JavaScript code to inject into the iframe to run
22
+ */
23
+ customJavaScript?: string;
24
+ }
25
+
26
+ const O2IFrame: React.FC<O2IFrame> = ({ src, elementsToHide, elementsToDisable, customJavaScript = '' }) => {
27
+ const iframeRef = useRef<HTMLIFrameElement>();
28
+ const [isIframeLoading, setIsIframeLoading] = useState(true);
29
+ const [isGoingBack, setIsGoingBack] = useState(false);
30
+ const [iframeHistoryCount, setIframeHistoryCount] = useState(0);
31
+ const { t } = useTranslation();
32
+
33
+ const customCss = useMemo(() => {
34
+ const toHide = elementsToHide?.map((e) => `${e} {display: none !important;}`)?.join('\n') ?? '';
35
+ const toDisable =
36
+ elementsToDisable?.map((e) => `${e} {pointer-events: none; cursor: not-allowed;}`)?.join('\n') ?? '';
37
+
38
+ return `@media screen {
39
+ ${toHide}
40
+ ${toDisable}
41
+ }`;
42
+ }, [elementsToHide, elementsToDisable]);
43
+
44
+ const onLoad = () => {
45
+ setIsIframeLoading(false);
46
+ if (!isGoingBack) {
47
+ setIframeHistoryCount(iframeHistoryCount + 1);
48
+ }
49
+ setIsGoingBack(false);
50
+ iframeRef.current.contentWindow.addEventListener('beforeunload', () => setIsIframeLoading(true));
51
+ const contentDocument = iframeRef.current.contentDocument;
52
+
53
+ const styleTag = contentDocument.createElement('style');
54
+ styleTag.innerHTML = customCss;
55
+ contentDocument.head.appendChild(styleTag);
56
+
57
+ const scriptTag = contentDocument.createElement('script');
58
+ scriptTag.innerHTML = customJavaScript;
59
+ contentDocument.body.appendChild(scriptTag);
60
+ };
61
+
62
+ const goBack = () => {
63
+ iframeRef.current.contentWindow.history.back();
64
+ setIframeHistoryCount(iframeHistoryCount - 1);
65
+ setIsIframeLoading(true);
66
+ setIsGoingBack(true);
67
+ };
68
+
69
+ return (
70
+ <div className={styles.iframeWrapper}>
71
+ <div className={styles.navigation}>
72
+ <IconButton
73
+ align="top-start"
74
+ label={t('back', 'Back')}
75
+ onClick={goBack}
76
+ disabled={isIframeLoading || iframeHistoryCount <= 1}>
77
+ <ArrowLeft />
78
+ </IconButton>
79
+ {isIframeLoading && <InlineLoading />}
80
+ </div>
81
+ <iframe ref={iframeRef} src={src} onLoad={onLoad} className={styles.o2Iframe} />
82
+ </div>
83
+ );
84
+ };
85
+
86
+ export default O2IFrame;
@@ -0,0 +1,20 @@
1
+ :global(div[data-extension-id='o2-pregnancy-infant-dashboard']) {
2
+ flex: 1;
3
+ }
4
+
5
+ .iframeWrapper {
6
+ height: 100%;
7
+ width: 100%;
8
+ display: flex;
9
+ flex-direction: column;
10
+ }
11
+
12
+ .o2Iframe {
13
+ height: 100%;
14
+ width: 100%;
15
+ }
16
+
17
+ .navigation {
18
+ display: flex;
19
+ flex: 1;
20
+ }
@@ -0,0 +1,87 @@
1
+ import { InlineLoading } from '@carbon/react';
2
+ import React from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { useActivePatientEnrollment } from '../hooks/useProgramEnrollment';
5
+ import O2IFrame from './o2-iframe.component';
6
+ import styles from './o2-pregnancy-infant-dashboard.scss';
7
+
8
+ /**
9
+ * Extension to display either the O2 pregnancy program or infant program dashboard,
10
+ * if the patient is enrolled in it.
11
+ */
12
+ const O2PregnancyInfantProgramDashboard: React.FC<{ patientUuid: string }> = ({ patientUuid }) => {
13
+ const infantProgramUuid = 'dc1b588a-9b94-45e4-8346-71b7c9a24845';
14
+ const pregnancyProgramUuid = '6a5713c2-3fd5-46e7-8f25-36a0f7871e12';
15
+
16
+ const { data: programs, isLoading } = useActivePatientEnrollment(patientUuid);
17
+ const { t } = useTranslation();
18
+
19
+ const inInfantProgram = programs?.data?.results?.some((enrollment) => enrollment.program.uuid == infantProgramUuid);
20
+ const inPregnancyProgram = programs?.data?.results?.some(
21
+ (enrollment) => enrollment.program.uuid == pregnancyProgramUuid,
22
+ );
23
+
24
+ const elementsToHide = [
25
+ 'header',
26
+ '.patient-header',
27
+ '#breadcrumbs',
28
+ '.action-section',
29
+ '.visits-section',
30
+ '.pregnancy\\.dashboard\\.ancInitialEncounters',
31
+ '.pregnancy\\.dashboard\\.ancFollowupEncounters',
32
+ '.pregnancy\\.dashboard\\.riskFactors a.right',
33
+ '.pregnancy\\.dashboard\\.temperature a.right',
34
+ '.pregnancy\\.dashboard\\.postpartumDailyProgressEncounters',
35
+ '.pregnancy\\.dashboard\\.laborAndDeliverySummaryEncounters',
36
+ '.pregnancy\\.dashboard\\.maternalAdmissionEncounters',
37
+ '.patient-location',
38
+ '.pregnancy\\.dashboard\\.currentEnrollment',
39
+ '.infant\\.dashboard\\.newbornAssesmentEncounters',
40
+ '.infant\\.dashboard\\.newbornDailyProgressEncounters',
41
+ '.infant\\.dashboard\\.currentEnrollment',
42
+ '.program-history',
43
+ '.allergies .cancel',
44
+ ];
45
+
46
+ const elementsToDisable = [
47
+ '.pregnancy\\.dashboard\\.riskFactors a',
48
+ '.pregnancy\\.dashboard\\.temperature a',
49
+ '.infant\\.dashboard\\.indicator a',
50
+ ];
51
+
52
+ if (isLoading) {
53
+ return <InlineLoading />;
54
+ } else if (inInfantProgram) {
55
+ const infantProgramUrl = `${window.openmrsBase}/coreapps/clinicianfacing/patient.page?patientId=${patientUuid}&dashboard=${infantProgramUuid}`;
56
+ return (
57
+ <>
58
+ <div className={styles.patientChartLinkContainer}>
59
+ <a href={infantProgramUrl}>{t('fullInfantDashboard', 'Full Infant Dashboard')}</a>
60
+ </div>
61
+ <O2IFrame key={patientUuid} {...{ src: infantProgramUrl, elementsToDisable, elementsToHide }} />
62
+ </>
63
+ );
64
+ } else if (inPregnancyProgram) {
65
+ const pregnancyProgramUrl = `${window.openmrsBase}/coreapps/clinicianfacing/patient.page?patientId=${patientUuid}&dashboard=${pregnancyProgramUuid}`;
66
+ return (
67
+ <>
68
+ <div className={styles.patientChartLinkContainer}>
69
+ <a href={pregnancyProgramUrl}>{t('fullPregnancyDashboard', 'Full Pregnancy Dashboard')}</a>
70
+ </div>
71
+ <O2IFrame key={patientUuid} {...{ src: pregnancyProgramUrl, elementsToDisable, elementsToHide }} />
72
+ </>
73
+ );
74
+ } else {
75
+ const patientChartUrl = `${window.openmrsBase}/coreapps/clinicianfacing/patient.page?patientId=${patientUuid}`;
76
+ return (
77
+ <>
78
+ <div className={styles.patientChartLinkContainer}>
79
+ <a href={patientChartUrl}>{t('fullPatientChart', 'Full Patient Chart')}</a>
80
+ </div>
81
+ <O2IFrame key={patientUuid} {...{ src: patientChartUrl, elementsToDisable, elementsToHide }} />
82
+ </>
83
+ );
84
+ }
85
+ };
86
+
87
+ export default O2PregnancyInfantProgramDashboard;
@@ -0,0 +1,5 @@
1
+ @use '@carbon/layout';
2
+
3
+ .patientChartLinkContainer {
4
+ padding: layout.$spacing-05;
5
+ }
@@ -0,0 +1,17 @@
1
+ import { ActionMenuButton2, CalendarHeatMapIcon } from '@openmrs/esm-framework';
2
+ import React from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ export default function WardPatientActionButton() {
6
+ const { t } = useTranslation();
7
+
8
+ return (
9
+ <ActionMenuButton2
10
+ icon={(props) => <CalendarHeatMapIcon {...props} />}
11
+ label={t('visitSummary', 'Visit summary')}
12
+ workspaceToLaunch={{
13
+ workspaceName: 'o2-visit-summary-workspace',
14
+ }}
15
+ />
16
+ );
17
+ }