@ampath/esm-dha-workflow-app 4.0.0-next.21 → 4.0.0-next.23

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 (37) hide show
  1. package/dist/339.js +1 -1
  2. package/dist/339.js.map +1 -1
  3. package/dist/352.js +1 -0
  4. package/dist/352.js.map +1 -0
  5. package/dist/907.js +1 -0
  6. package/dist/907.js.map +1 -0
  7. package/dist/91.js +1 -1
  8. package/dist/91.js.map +1 -1
  9. package/dist/esm-dha-workflow-app.js.buildmanifest.json +50 -50
  10. package/dist/main.js +1 -1
  11. package/dist/main.js.map +1 -1
  12. package/dist/routes.json +1 -1
  13. package/package.json +1 -1
  14. package/src/registry/modal/send-to-triage/send-to-triage.modal.tsx +1 -1
  15. package/src/registry/types/index.ts +5 -0
  16. package/src/resources/visit.resource.ts +19 -1
  17. package/src/service-queues/consultation/consultation.component.tsx +0 -2
  18. package/src/service-queues/metrics/metrics-cards/attended-patients.extension.tsx +4 -1
  19. package/src/service-queues/metrics/metrics-container.component.tsx +8 -1
  20. package/src/service-queues/modals/serve/serve-patient.comppnent.tsx +3 -5
  21. package/src/service-queues/modals/sign-off/sign-off.modal.scss +0 -0
  22. package/src/service-queues/modals/sign-off/sign-off.modal.tsx +69 -0
  23. package/src/service-queues/modals/transition/transition-patient.component.tsx +1 -1
  24. package/src/service-queues/queue-list/queue-list.component.tsx +49 -6
  25. package/src/service-queues/service-queue/service-queue.component.scss +1 -1
  26. package/src/service-queues/service-queue/service-queue.component.tsx +40 -3
  27. package/src/service-queues/service-queue/stats/stat-card/stat-card.component.scss +10 -0
  28. package/src/service-queues/service-queue/stats/stat-card/stat-card.component.tsx +23 -0
  29. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.scss +7 -0
  30. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.tsx +34 -0
  31. package/src/triage/metrics/triage-metrics.component.tsx +8 -1
  32. package/src/triage/triage.component.tsx +0 -3
  33. package/src/types/types.ts +13 -0
  34. package/dist/5.js +0 -1
  35. package/dist/5.js.map +0 -1
  36. package/dist/635.js +0 -1
  37. package/dist/635.js.map +0 -1
@@ -24,7 +24,7 @@ const ServePatientModal: React.FC<ServePatientModal> = ({
24
24
  const payload = getServePatientPayload();
25
25
  try {
26
26
  await transitionQueueEntry(payload);
27
- showAlert('success', 'Cleint succesfully served', '');
27
+ showAlert('success', 'Client succesfully served', '');
28
28
  onSuccessfullServe();
29
29
  } catch (e) {
30
30
  showAlert('error', e.message, '');
@@ -49,6 +49,7 @@ const ServePatientModal: React.FC<ServePatientModal> = ({
49
49
  return (
50
50
  <>
51
51
  <Modal
52
+ modalHeading="Serve Client"
52
53
  open={open}
53
54
  size="md"
54
55
  onSecondarySubmit={() => onModalClose()}
@@ -59,13 +60,10 @@ const ServePatientModal: React.FC<ServePatientModal> = ({
59
60
  >
60
61
  <ModalBody>
61
62
  <div className={styles.serveModalLayout}>
62
- <div className={styles.serveModalSectionHeader}>
63
- <h4>Serve Client</h4>
64
- </div>
65
63
  <div className={styles.serveModalContentSection}>
66
64
  <div className={styles.formRow}>
67
65
  <p>
68
- Name: {currentQueueEntry.family_name} {currentQueueEntry.family_name}
66
+ Name: {currentQueueEntry.family_name} {currentQueueEntry.middle_name} {currentQueueEntry.given_name}
69
67
  </p>
70
68
  <p>Ticket No: {currentQueueEntry.queue_entry_id}</p>
71
69
  <p>Status: {currentQueueEntry.status}</p>
@@ -0,0 +1,69 @@
1
+ import React from 'react';
2
+ import { Modal, ModalBody, TextInput } from '@carbon/react';
3
+ import { type EndVisitDto, type QueueEntryResult } from '../../../registry/types';
4
+ import styles from './sign-off.modal.scss';
5
+ import { showSnackbar } from '@openmrs/esm-framework';
6
+ import { endVisit } from '../../../resources/visit.resource';
7
+
8
+ interface SignOffEntryModalProps {
9
+ open: boolean;
10
+ onModalClose: () => void;
11
+ currentQueueEntry: QueueEntryResult;
12
+ onSuccessfullSignOff: () => void;
13
+ }
14
+
15
+ const SignOffEntryModal: React.FC<SignOffEntryModalProps> = ({
16
+ open,
17
+ onModalClose,
18
+ currentQueueEntry,
19
+ onSuccessfullSignOff,
20
+ }) => {
21
+ const signOffEntry = async () => {
22
+ const payload = getEndVisitPayload();
23
+ try {
24
+ await endVisit(currentQueueEntry.visit_uuid, payload);
25
+ showAlert('success', 'Visit Ended successfully', '');
26
+ onSuccessfullSignOff();
27
+ } catch (e) {
28
+ showAlert('error', e.message, '');
29
+ }
30
+ };
31
+ const showAlert = (alertType: 'error' | 'success', title: string, subtitle: string) => {
32
+ showSnackbar({
33
+ kind: alertType,
34
+ title: title,
35
+ subtitle: subtitle,
36
+ });
37
+ };
38
+ const getEndVisitPayload = (): EndVisitDto => {
39
+ return {
40
+ stopDatetime: new Date().toISOString(),
41
+ };
42
+ };
43
+ return (
44
+ <>
45
+ <Modal
46
+ modalHeading="Sign Off"
47
+ open={open}
48
+ size="md"
49
+ onSecondarySubmit={() => onModalClose()}
50
+ onRequestClose={() => onModalClose()}
51
+ onRequestSubmit={signOffEntry}
52
+ primaryButtonText="Sign Off"
53
+ secondaryButtonText="Cancel"
54
+ >
55
+ <ModalBody>
56
+ <div className={styles.serveModalLayout}>
57
+ <div className={styles.serveModalContentSection}>
58
+ <div className={styles.formRow}>
59
+ <TextInput id="health-worker-id" labelText="Enter your Provider ID" onChange={() => {}} type="text" />
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </ModalBody>
64
+ </Modal>
65
+ </>
66
+ );
67
+ };
68
+
69
+ export default SignOffEntryModal;
@@ -24,7 +24,7 @@ const TransitionPatientModal: React.FC<TransitionPatientModalProps> = ({ open, o
24
24
  const payload = getTransitionQueueEntryPayload();
25
25
  try {
26
26
  await transitionQueueEntry(payload);
27
- showAlert('success', 'Cleint succesfully Transitioned', '');
27
+ showAlert('success', 'Client succesfully Transitioned', '');
28
28
  onModalClose();
29
29
  } catch (e) {
30
30
  showAlert('error', e.message, '');
@@ -9,16 +9,19 @@ import {
9
9
  TableHead,
10
10
  TableHeader,
11
11
  TableRow,
12
+ Tag,
12
13
  } from '@carbon/react';
13
14
  import { type QueueEntryResult } from '../../registry/types';
14
15
  import React, { useState } from 'react';
15
16
  import styles from './queue-list.component.scss';
17
+ import { QueueEntryPriority, QueueEntryStatus, type TagColor } from '../../types/types';
16
18
 
17
19
  interface QueueListProps {
18
20
  queueEntries: QueueEntryResult[];
19
21
  handleMovePatient: (queueEntryResult: QueueEntryResult) => void;
20
22
  handleTransitionPatient: (queueEntryResult: QueueEntryResult) => void;
21
23
  handleServePatient: (queueEntryResult: QueueEntryResult) => void;
24
+ handleSignOff: (queueEntryResult: QueueEntryResult) => void;
22
25
  }
23
26
 
24
27
  const QueueList: React.FC<QueueListProps> = ({
@@ -26,11 +29,43 @@ const QueueList: React.FC<QueueListProps> = ({
26
29
  handleMovePatient,
27
30
  handleTransitionPatient,
28
31
  handleServePatient,
32
+ handleSignOff,
29
33
  }) => {
30
34
  const [checkIn, setCheckIn] = useState<boolean>(false);
31
35
  const handleCheckin = () => {
32
36
  setCheckIn((prev) => !prev);
33
37
  };
38
+ const getTagTypeByStatus = (status: string): TagColor => {
39
+ let type: TagColor;
40
+ switch (status) {
41
+ case QueueEntryStatus.Completed:
42
+ type = 'green';
43
+ break;
44
+ case QueueEntryStatus.Waiting:
45
+ type = 'gray';
46
+ break;
47
+ case QueueEntryStatus.InService:
48
+ type = 'blue';
49
+ break;
50
+ default:
51
+ type = 'gray';
52
+ }
53
+ return type;
54
+ };
55
+ const getTagTypeByPriority = (priority: string): TagColor => {
56
+ let type: TagColor;
57
+ switch (priority) {
58
+ case QueueEntryPriority.Emergency:
59
+ type = 'red';
60
+ break;
61
+ case QueueEntryPriority.Normal:
62
+ type = 'blue';
63
+ break;
64
+ default:
65
+ type = 'gray';
66
+ }
67
+ return type;
68
+ };
34
69
  return (
35
70
  <>
36
71
  <div className={styles.queueListLayout}>
@@ -70,19 +105,27 @@ const QueueList: React.FC<QueueListProps> = ({
70
105
  <TableCell>
71
106
  {checkIn ? (
72
107
  <Link href={`${window.spaBase}/patient/${val.patient_uuid}/chart/`}>
73
- {val.family_name} {val.middle_name}
108
+ {val.family_name} {val.middle_name} {val.given_name}
74
109
  </Link>
75
110
  ) : (
76
111
  <>
77
- {val.family_name} {val.middle_name}
112
+ {val.family_name} {val.middle_name} {val.given_name}
78
113
  </>
79
114
  )}
80
115
  </TableCell>
81
116
  <TableCell>{val.queue_entry_id}</TableCell>
82
- <TableCell>{val.status}</TableCell>
83
- <TableCell>{val.priority}</TableCell>
84
117
  <TableCell>
85
- {val.status === 'WAITING' ? (
118
+ <Tag size="md" type={getTagTypeByStatus(val.status)}>
119
+ {val.status}
120
+ </Tag>
121
+ </TableCell>
122
+ <TableCell>
123
+ <Tag size="md" type={getTagTypeByPriority(val.priority)}>
124
+ {val.priority}
125
+ </Tag>
126
+ </TableCell>
127
+ <TableCell>
128
+ {val.status === QueueEntryStatus.Waiting ? (
86
129
  <>
87
130
  <Button kind="ghost" disabled={!checkIn} onClick={() => handleServePatient(val)}>
88
131
  Serve
@@ -95,7 +138,7 @@ const QueueList: React.FC<QueueListProps> = ({
95
138
  <OverflowMenu aria-label="overflow-menu">
96
139
  <OverflowMenuItem itemText="Move" onClick={() => handleMovePatient(val)} />
97
140
  <OverflowMenuItem itemText="Transition" onClick={() => handleTransitionPatient(val)} />
98
- <OverflowMenuItem itemText="Sign off" onClick={handleCheckin} />
141
+ <OverflowMenuItem itemText="Sign Off" onClick={() => handleSignOff(val)} />
99
142
  <OverflowMenuItem itemText="Remove Patient" />
100
143
  </OverflowMenu>
101
144
  </>
@@ -4,4 +4,4 @@
4
4
  width: 100%;
5
5
  padding: 15px 15px;
6
6
  row-gap: 15px;
7
- }
7
+ }
@@ -8,6 +8,8 @@ import styles from './service-queue.component.scss';
8
8
  import MovePatientModal from '../modals/move/move-patient.component';
9
9
  import TransitionPatientModal from '../modals/transition/transition-patient.component';
10
10
  import ServePatientModal from '../modals/serve/serve-patient.comppnent';
11
+ import StatDetails from './stats/stat-details/stat-details.component';
12
+ import SignOffEntryModal from '../modals/sign-off/sign-off.modal';
11
13
 
12
14
  interface ServiceQueueComponentProps {
13
15
  serviceTypeUuid: string;
@@ -17,9 +19,10 @@ interface ServiceQueueComponentProps {
17
19
  const ServiceQueueComponent: React.FC<ServiceQueueComponentProps> = ({ serviceTypeUuid, title }) => {
18
20
  const [queueEntries, setQueueEntries] = useState<QueueEntryResult[]>([]);
19
21
  const [selectedQueueEntry, setSelectedQueueEntry] = useState<QueueEntryResult>();
20
- const [displayMoveModal, setDisplayMoveModal] = useState<boolean>();
21
- const [displayTransitionModal, setDisplayTransitionModal] = useState<boolean>();
22
- const [displayServeModal, setDisplayServeModal] = useState<boolean>();
22
+ const [displayMoveModal, setDisplayMoveModal] = useState<boolean>(false);
23
+ const [displayTransitionModal, setDisplayTransitionModal] = useState<boolean>(false);
24
+ const [displayServeModal, setDisplayServeModal] = useState<boolean>(false);
25
+ const [displaySignOffModal, setDisplaySignOffModal] = useState<boolean>(false);
23
26
  const session = useSession();
24
27
  const locationUuid = session.sessionLocation.uuid;
25
28
 
@@ -59,6 +62,7 @@ const ServiceQueueComponent: React.FC<ServiceQueueComponentProps> = ({ serviceTy
59
62
  setDisplayMoveModal(false);
60
63
  setDisplayTransitionModal(false);
61
64
  setDisplayServeModal(false);
65
+ getEntryQueues();
62
66
  };
63
67
 
64
68
  const handleTransitionPatient = (queueEntry: QueueEntryResult) => {
@@ -82,6 +86,15 @@ const ServiceQueueComponent: React.FC<ServiceQueueComponentProps> = ({ serviceTy
82
86
  navigateToPatientChart();
83
87
  };
84
88
 
89
+ const handleSignOff = (queueEntry: QueueEntryResult) => {
90
+ setDisplaySignOffModal(true);
91
+ setSelectedQueueEntry(queueEntry);
92
+ };
93
+
94
+ const onSuccessfullSignOff = () => {
95
+ setDisplaySignOffModal(false);
96
+ };
97
+
85
98
  if (!serviceTypeUuid) {
86
99
  return <>No service type defined</>;
87
100
  }
@@ -92,6 +105,16 @@ const ServiceQueueComponent: React.FC<ServiceQueueComponentProps> = ({ serviceTy
92
105
  <div className={styles.headerSection}>
93
106
  <h4>{title}</h4>
94
107
  </div>
108
+ <div>
109
+ {queueEntries ? (
110
+ <>
111
+ <StatDetails queueEntries={queueEntries} />
112
+ </>
113
+ ) : (
114
+ <></>
115
+ )}
116
+ </div>
117
+
95
118
  <div className={styles.contentSection}>
96
119
  <Tabs>
97
120
  <TabList contained>
@@ -111,6 +134,7 @@ const ServiceQueueComponent: React.FC<ServiceQueueComponentProps> = ({ serviceTy
111
134
  handleMovePatient={handleMovePatient}
112
135
  handleTransitionPatient={handleTransitionPatient}
113
136
  handleServePatient={handleServePatient}
137
+ handleSignOff={handleSignOff}
114
138
  />
115
139
  }
116
140
  </TabPanel>
@@ -158,6 +182,19 @@ const ServiceQueueComponent: React.FC<ServiceQueueComponentProps> = ({ serviceTy
158
182
  ) : (
159
183
  <></>
160
184
  )}
185
+
186
+ {displaySignOffModal ? (
187
+ <>
188
+ <SignOffEntryModal
189
+ open={displaySignOffModal}
190
+ onModalClose={handleModalCloes}
191
+ currentQueueEntry={selectedQueueEntry}
192
+ onSuccessfullSignOff={onSuccessfullSignOff}
193
+ />
194
+ </>
195
+ ) : (
196
+ <></>
197
+ )}
161
198
  </>
162
199
  );
163
200
  };
@@ -0,0 +1,10 @@
1
+ .statsCard{
2
+ display: flex;
3
+ flex-direction: column;
4
+ width: 40%;
5
+ row-gap: 5px;
6
+ border-radius: 12px;
7
+ border: 1px solid #d2d2d2;
8
+ height: 100px;
9
+ padding: 10px 10px;
10
+ }
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import styles from './stat-card.component.scss';
3
+
4
+ interface StatCardProps {
5
+ title: string;
6
+ count: number;
7
+ }
8
+
9
+ const StatCard: React.FC<StatCardProps> = ({ title, count }) => {
10
+ if (!title) {
11
+ return <></>;
12
+ }
13
+ return (
14
+ <div className={styles.statsCard}>
15
+ <div className={styles.statsCardHeader}>
16
+ <h5>{title}</h5>
17
+ <h1>{count}</h1>
18
+ </div>
19
+ </div>
20
+ );
21
+ };
22
+
23
+ export default StatCard;
@@ -0,0 +1,7 @@
1
+ .statsSection{
2
+ display: flex;
3
+ flex-direction: row;
4
+ width: 100%;
5
+ column-gap: 15px;
6
+ margin-bottom: 15px;
7
+ }
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import styles from './stat-details.component.scss';
3
+ import { type QueueEntryResult } from '../../../../registry/types';
4
+ import StatCard from '../stat-card/stat-card.component';
5
+
6
+ interface StatDetailsProps {
7
+ queueEntries: QueueEntryResult[];
8
+ }
9
+
10
+ const StatDetails: React.FC<StatDetailsProps> = ({ queueEntries }) => {
11
+ if (!queueEntries) {
12
+ return 'No queue entry records';
13
+ }
14
+ const getCategoryTotal = (categories: string[]) => {
15
+ let total = 0;
16
+ queueEntries.forEach((q) => {
17
+ if (categories.includes(q.status)) {
18
+ total += 1;
19
+ }
20
+ });
21
+ return total;
22
+ };
23
+ const patientsInWaiting = getCategoryTotal(['WAITING']);
24
+ const patientsAttendedTo = getCategoryTotal(['IN SERVICE', 'COMPLETED']);
25
+
26
+ return (
27
+ <div className={styles.statsSection}>
28
+ <StatCard title="Patients in waiting" count={patientsInWaiting ?? 0} />
29
+ <StatCard title="Patients attended to" count={patientsAttendedTo ?? 0} />
30
+ </div>
31
+ );
32
+ };
33
+
34
+ export default StatDetails;
@@ -1,6 +1,8 @@
1
1
  import React from 'react';
2
2
  import { ExtensionSlot } from '@openmrs/esm-framework';
3
3
  import styles from './metrics.scss';
4
+ import TriageWaitingPatientsExtension from './waiting-patients.extension';
5
+ import TriageAttendedToPatientsExtension from './attended-patients.extension';
4
6
 
5
7
  export interface Service {
6
8
  display: string;
@@ -8,7 +10,12 @@ export interface Service {
8
10
  }
9
11
 
10
12
  function TriageMetricsContainer() {
11
- return <ExtensionSlot name="triage-metrics-slot" className={styles.cardContainer} data-testid="clinic-metrics" />;
13
+ return (
14
+ <div className={styles.cardContainer}>
15
+ <TriageWaitingPatientsExtension />
16
+ <TriageAttendedToPatientsExtension />
17
+ </div>
18
+ );
12
19
  }
13
20
 
14
21
  export default TriageMetricsContainer;
@@ -1,6 +1,4 @@
1
1
  import React from 'react';
2
-
3
- import TriageMetricsContainer from './metrics/triage-metrics.component';
4
2
  import ServiceQueueComponent from '../service-queues/service-queue/service-queue.component';
5
3
  import { QUEUE_SERVICE_UUIDS } from '../shared/constants/concepts';
6
4
 
@@ -8,7 +6,6 @@ interface TriageProps {}
8
6
  const Triage: React.FC<TriageProps> = () => {
9
7
  return (
10
8
  <>
11
- <TriageMetricsContainer />
12
9
  <div>
13
10
  <ServiceQueueComponent serviceTypeUuid={QUEUE_SERVICE_UUIDS.TRIAGE_SERVICE_UUID} title="Triage" />
14
11
  </div>
@@ -113,3 +113,16 @@ export type TransitionQueueEntryDto = {
113
113
  newPriority?: string;
114
114
  newPriorityComment?: string;
115
115
  };
116
+
117
+ export type TagColor = 'green' | 'gray' | 'blue' | 'red';
118
+
119
+ export enum QueueEntryStatus {
120
+ Completed = 'COMPLETED',
121
+ Waiting = 'WAITING',
122
+ InService = 'IN SERVICE',
123
+ }
124
+
125
+ export enum QueueEntryPriority {
126
+ Emergency = 'EMERGENCY',
127
+ Normal = 'NORMAL',
128
+ }