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

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 (57) hide show
  1. package/dist/15.js +1 -1
  2. package/dist/15.js.map +1 -1
  3. package/dist/339.js +1 -1
  4. package/dist/339.js.map +1 -1
  5. package/dist/5.js +1 -0
  6. package/dist/5.js.map +1 -0
  7. package/dist/635.js +1 -1
  8. package/dist/635.js.map +1 -1
  9. package/dist/710.js +1 -1
  10. package/dist/729.js +1 -0
  11. package/dist/729.js.map +1 -0
  12. package/dist/{844.js → 752.js} +1 -1
  13. package/dist/752.js.map +1 -0
  14. package/dist/833.js +1 -0
  15. package/dist/833.js.map +1 -0
  16. package/dist/91.js +1 -1
  17. package/dist/91.js.map +1 -1
  18. package/dist/93.js +1 -1
  19. package/dist/972.js +2 -0
  20. package/dist/972.js.map +1 -0
  21. package/dist/esm-dha-workflow-app.js +1 -1
  22. package/dist/esm-dha-workflow-app.js.buildmanifest.json +103 -104
  23. package/dist/esm-dha-workflow-app.js.map +1 -1
  24. package/dist/main.js +1 -1
  25. package/dist/main.js.map +1 -1
  26. package/dist/routes.json +1 -1
  27. package/package.json +1 -1
  28. package/src/dashboard/dashboard.component.scss +7 -0
  29. package/src/dashboard/dashboard.component.tsx +63 -0
  30. package/src/dashboard/overview/overview.component.scss +32 -0
  31. package/src/dashboard/overview/overview.component.tsx +103 -0
  32. package/src/dashboard/patient-list/patient-list.component.tsx +41 -0
  33. package/src/index.ts +8 -2
  34. package/src/root.component.tsx +2 -1
  35. package/src/routes.json +12 -0
  36. package/src/service-queues/consultation/consultation.component.tsx +2 -0
  37. package/src/service-queues/metrics/metrics-cards/attended-patients.extension.tsx +21 -4
  38. package/src/service-queues/metrics/metrics-cards/waiting-patients.extension.tsx +20 -4
  39. package/src/service-queues/queue-list/queue-list.component.tsx +1 -0
  40. package/src/triage/metrics/attended-patients.extension.tsx +42 -0
  41. package/src/triage/metrics/metrics.scss +36 -0
  42. package/src/triage/metrics/triage-metrics.component.tsx +14 -0
  43. package/src/triage/metrics/waiting-patients.extension.tsx +39 -0
  44. package/src/triage/triage.component.tsx +6 -1
  45. package/src/triage/types.ts +13 -19
  46. package/dist/321.js +0 -1
  47. package/dist/321.js.map +0 -1
  48. package/dist/468.js +0 -2
  49. package/dist/468.js.map +0 -1
  50. package/dist/602.js +0 -1
  51. package/dist/602.js.map +0 -1
  52. package/dist/733.js +0 -1
  53. package/dist/733.js.map +0 -1
  54. package/dist/844.js.map +0 -1
  55. package/src/triage/room/room.component.tsx +0 -39
  56. package/src/triage/triage.module.scss +0 -19
  57. /package/dist/{468.js.LICENSE.txt → 972.js.LICENSE.txt} +0 -0
package/dist/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{},"pages":[{"component":"root","route":"home","online":true,"offline":true}],"extensions":[{"component":"workflowRegistryLink","name":"workflow-registry-link","slot":"app-menu-slot","online":true,"offline":true},{"component":"navLinks","name":"side-nav-workflow-links","slot":"dha-workflow-slot","online":true,"offline":true},{"name":"metrics-card-patients-in-waiting","component":"waitingPatientsExtension","slot":"clinic-metrics-slot","order":1},{"name":"metrics-card-patients-attended-to","component":"attendedToPatientsExtension","slot":"clinic-metrics-slot","order":2}],"modals":[{"name":"sign-off-queue-entry-modal","component":"signOffModal"}],"version":"4.0.0-next.20"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{},"pages":[{"component":"root","route":"home","online":true,"offline":true}],"extensions":[{"component":"workflowRegistryLink","name":"workflow-registry-link","slot":"app-menu-slot","online":true,"offline":true},{"component":"navLinks","name":"side-nav-workflow-links","slot":"dha-workflow-slot","online":true,"offline":true},{"name":"metrics-card-patients-in-waiting","component":"waitingPatientsExtension","slot":"clinic-metrics-slot","order":1},{"name":"metrics-card-patients-attended-to","component":"attendedToPatientsExtension","slot":"clinic-metrics-slot","order":2},{"name":"metrics-card-patients-in-waiting","component":"triageWaitingPatientsExtension","slot":"triage-metrics-slot","order":1},{"name":"metrics-card-patients-attended-to","component":"triageAttendedToPatientsExtension","slot":"triage-metrics-slot","order":2}],"modals":[{"name":"sign-off-queue-entry-modal","component":"signOffModal"}],"version":"4.0.0-next.21"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ampath/esm-dha-workflow-app",
3
- "version": "4.0.0-next.20",
3
+ "version": "4.0.0-next.21",
4
4
  "license": "MPL-2.0",
5
5
  "description": "An OpenMRS seed application for building microfrontends",
6
6
  "browser": "dist/esm-dha-workflow-app.js",
@@ -0,0 +1,7 @@
1
+ .container {
2
+ margin: 3rem;
3
+ }
4
+ .tabText {
5
+ font-size: 25px;
6
+ }
7
+
@@ -0,0 +1,63 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
3
+
4
+ import styles from './dashboard.component.scss';
5
+ import Overview from './overview/overview.component';
6
+ import { getServiceQueueByLocationUuid } from '../service-queues/service-queues.resource';
7
+ import { type QueueEntryResult } from '../registry/types';
8
+ import { useSession } from '@openmrs/esm-framework';
9
+ import { QUEUE_SERVICE_UUIDS } from '../shared/constants/concepts';
10
+
11
+ interface DashboardProps {}
12
+
13
+ const Dashboard: React.FC<DashboardProps> = () => {
14
+ const [triageQueueEntries, setTriageQueueEntries] = useState<QueueEntryResult[]>([]);
15
+ const [consultationQueueEntries, setConsultationQueueEntries] = useState<QueueEntryResult[]>([]);
16
+ const session = useSession();
17
+ const locationUuid = session.sessionLocation.uuid;
18
+ const triageServiceUuid = QUEUE_SERVICE_UUIDS.TRIAGE_SERVICE_UUID;
19
+ const consultationServiceUuid = QUEUE_SERVICE_UUIDS.CLINICAL_CONSULTATION_SERVICE_UUID;
20
+ useEffect(() => {
21
+ getTriageEntryQueues();
22
+ getConsultationEntryQueues();
23
+ }, []);
24
+
25
+ const getTriageEntryQueues = async () => {
26
+ const res = await getServiceQueueByLocationUuid(triageServiceUuid, locationUuid);
27
+ setTriageQueueEntries(res);
28
+ };
29
+ const getConsultationEntryQueues = async () => {
30
+ const res = await getServiceQueueByLocationUuid(consultationServiceUuid, locationUuid);
31
+ setConsultationQueueEntries(res);
32
+ };
33
+ return (
34
+ <div className={styles.container}>
35
+ <Tabs>
36
+ <TabList contained fullWidth scrollDebounceWait={200}>
37
+ <Tab>
38
+ <span className={styles.tabText}>Overview</span>
39
+ </Tab>
40
+ <Tab>
41
+ <span>Pharmacy</span>
42
+ </Tab>
43
+ <Tab>
44
+ <span className={styles.tabText}>Labs</span>
45
+ </Tab>
46
+ <Tab>
47
+ <span className={styles.tabText}>Programs</span>
48
+ </Tab>
49
+ </TabList>
50
+ <TabPanels>
51
+ <TabPanel>
52
+ <Overview triageCount={triageQueueEntries} consultationCount={consultationQueueEntries} />
53
+ </TabPanel>
54
+ <TabPanel></TabPanel>
55
+ <TabPanel></TabPanel>
56
+ <TabPanel></TabPanel>
57
+ </TabPanels>
58
+ </Tabs>
59
+ </div>
60
+ );
61
+ };
62
+
63
+ export default Dashboard;
@@ -0,0 +1,32 @@
1
+ .container {
2
+ display: flex;
3
+ width: 100%;
4
+ justify-content: space-evenly;
5
+ }
6
+
7
+ .card {
8
+ border: 1px solid grey;
9
+ border-radius: 5px;
10
+ background-color: white;
11
+ font-weight: bold;
12
+ }
13
+
14
+ .dropdownItem {
15
+ display: flex;
16
+ justify-self: flex-end;
17
+ width: 25%;
18
+ min-width: 180px;
19
+ max-width: 280px;
20
+ margin-top: 5rem;
21
+ margin-bottom: 5rem;
22
+ }
23
+
24
+ .dropdownContainer {
25
+ .cds--list-box__menu-item__option {
26
+ font-weight: 600; // bold-ish
27
+ }
28
+
29
+ .cds--list-box__field {
30
+ font-weight: 600; // selected item label also bold
31
+ }
32
+ }
@@ -0,0 +1,103 @@
1
+ import { FluidDropdown, Tile } from '@carbon/react';
2
+ import React, { useState } from 'react';
3
+
4
+ import styles from './overview.component.scss';
5
+ import { type QueueEntryResult } from '../../registry/types';
6
+ import PatientList from '../patient-list/patient-list.component';
7
+
8
+ interface OverviewProps {
9
+ triageCount?: QueueEntryResult[];
10
+ consultationCount?: QueueEntryResult[];
11
+ }
12
+
13
+ const Overview: React.FC<OverviewProps> = ({ triageCount, consultationCount }) => {
14
+ const [selected, setSelected] = useState<string | null>(null);
15
+ const triagePatients = triageCount?.length ?? 0;
16
+ const consultationPatients = consultationCount?.length ?? 0;
17
+ const dropDownItems = [
18
+ 'Total Patients',
19
+ 'Triage Patients',
20
+ 'Consultation Patients',
21
+ 'Walk-In Patients',
22
+ 'Emergency Patients',
23
+ ];
24
+
25
+ const handleDropdownChange = (data: { selectedItem: string }) => {
26
+ const value = data.selectedItem;
27
+ setSelected(value);
28
+ };
29
+
30
+ let selectedPatients: QueueEntryResult[] = [];
31
+
32
+ switch (selected) {
33
+ case 'Triage Patients':
34
+ selectedPatients = triageCount ?? [];
35
+ break;
36
+
37
+ case 'Consultation Patients':
38
+ selectedPatients = consultationCount ?? [];
39
+ break;
40
+ case 'Walk-In Patients':
41
+ selectedPatients = [];
42
+ break;
43
+ case 'Emergency Patients':
44
+ selectedPatients = [];
45
+ break;
46
+
47
+ case 'Total Patients':
48
+ selectedPatients = [...(triageCount ?? []), ...(consultationCount ?? [])];
49
+ break;
50
+
51
+ default:
52
+ selectedPatients = [...(triageCount ?? []), ...(consultationCount ?? [])];
53
+ break;
54
+ }
55
+
56
+ return (
57
+ <>
58
+ <div className={styles.container}>
59
+ <Tile className={styles.card}>
60
+ <h3>Total Patients Today</h3>
61
+ <h4>Patients</h4>
62
+ <h4>{triagePatients + consultationPatients}</h4>
63
+ </Tile>
64
+ <Tile className={styles.card}>
65
+ <h3>Patients in Queue Today</h3>
66
+ <h4>Patients</h4>
67
+ <h4>{triagePatients + consultationPatients}</h4>
68
+ </Tile>
69
+ <Tile className={styles.card}>
70
+ <h3>Patients in Triage </h3>
71
+ <h4>Patients</h4>
72
+ <h4>{triagePatients}</h4>
73
+ </Tile>
74
+ <Tile className={styles.card}>
75
+ <h3>Patients in Cosultation </h3>
76
+ <h4>Patients</h4>
77
+ <h4>{consultationPatients}</h4>
78
+ </Tile>
79
+ <Tile className={styles.card}>
80
+ <h3>Walk-ins Today </h3>
81
+ <h4>Patients</h4>
82
+ <h4>0</h4>
83
+ </Tile>
84
+ <Tile className={styles.card}>
85
+ <h3>Emergencies Today </h3>
86
+ <h4>Patients</h4>
87
+ <h4>0</h4>
88
+ </Tile>
89
+ </div>
90
+ <FluidDropdown
91
+ className={styles.dropdownItem}
92
+ id={''}
93
+ items={dropDownItems}
94
+ label={'Total Patients'}
95
+ titleText={''}
96
+ onChange={handleDropdownChange}
97
+ ></FluidDropdown>
98
+ <PatientList patients={selectedPatients} />
99
+ </>
100
+ );
101
+ };
102
+
103
+ export default Overview;
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { type QueueEntryResult } from '../../registry/types';
3
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@carbon/react';
4
+ import { isDesktop, useLayoutType } from '@openmrs/esm-framework';
5
+
6
+ interface PatientListProps {
7
+ patients?: QueueEntryResult[];
8
+ }
9
+
10
+ const PatientList: React.FC<PatientListProps> = ({ patients }) => {
11
+ const layout = useLayoutType();
12
+ const desktop = isDesktop(layout);
13
+ return (
14
+ <Table size={desktop ? 'sm' : 'lg'}>
15
+ <TableHead>
16
+ <TableRow>
17
+ <TableHeader>No</TableHeader>
18
+ <TableHeader>Name</TableHeader>
19
+ <TableHeader>Ticket</TableHeader>
20
+ <TableHeader>Status</TableHeader>
21
+ <TableHeader>Priority</TableHeader>
22
+ </TableRow>
23
+ </TableHead>
24
+ <TableBody>
25
+ {patients?.map((patient, index) => {
26
+ return (
27
+ <TableRow>
28
+ <TableCell>{index + 1}</TableCell>
29
+ <TableCell>{`${patient.given_name} ${patient.middle_name} ${patient.family_name}`}</TableCell>
30
+ <TableCell>{patient.queue_id}</TableCell>
31
+ <TableCell>{patient.status}</TableCell>
32
+ <TableCell>{patient.priority}</TableCell>
33
+ </TableRow>
34
+ );
35
+ })}
36
+ </TableBody>
37
+ </Table>
38
+ );
39
+ };
40
+
41
+ export default PatientList;
package/src/index.ts CHANGED
@@ -52,10 +52,16 @@ export const attendedToPatientsExtension = getAsyncLifecycle(
52
52
  () => import('./service-queues/metrics/metrics-cards/attended-patients.extension'),
53
53
  options,
54
54
  );
55
+ export const triageWaitingPatientsExtension = getAsyncLifecycle(
56
+ () => import('./triage/metrics/waiting-patients.extension'),
57
+ options,
58
+ );
59
+ export const triageAttendedToPatientsExtension = getAsyncLifecycle(
60
+ () => import('./triage/metrics/attended-patients.extension'),
61
+ options,
62
+ );
55
63
 
56
64
  export const workflowRegistryLink = getAsyncLifecycle(() => import('./widgets/workflow-registry-link.extension'), {
57
65
  featureName: 'workflow-registry-link',
58
66
  moduleName,
59
67
  });
60
-
61
- export const triage = getAsyncLifecycle(() => import('./triage/triage.component'), options);
@@ -9,6 +9,7 @@ import LaboratoryComponent from './laboratory/laboratory.component';
9
9
  import AppointmentsComponent from './appointments/appointments.component';
10
10
  import PharmacyComponent from './pharmacy/pharmacy.component';
11
11
  import Consultation from './service-queues/consultation/consultation.component';
12
+ import Dashboard from './dashboard/dashboard.component';
12
13
 
13
14
  const Root: React.FC = () => {
14
15
  const spaBasePath = window.spaBase;
@@ -22,7 +23,7 @@ const Root: React.FC = () => {
22
23
  <LeftPanel />
23
24
  <main className={styles.container}>
24
25
  <Routes>
25
- <Route path="" element={<RegistryComponent />} />
26
+ <Route path="dashboard" element={<Dashboard />} />
26
27
  <Route path="registry" element={<RegistryComponent />} />
27
28
  <Route path="consultation" element={<Consultation />} />
28
29
  <Route path="triage" element={<Triage />} />
package/src/routes.json CHANGED
@@ -35,6 +35,18 @@
35
35
  "component": "attendedToPatientsExtension",
36
36
  "slot": "clinic-metrics-slot",
37
37
  "order": 2
38
+ },
39
+ {
40
+ "name": "metrics-card-patients-in-waiting",
41
+ "component": "triageWaitingPatientsExtension",
42
+ "slot": "triage-metrics-slot",
43
+ "order": 1
44
+ },
45
+ {
46
+ "name": "metrics-card-patients-attended-to",
47
+ "component": "triageAttendedToPatientsExtension",
48
+ "slot": "triage-metrics-slot",
49
+ "order": 2
38
50
  }
39
51
  ],
40
52
  "modals": [
@@ -1,9 +1,11 @@
1
1
  import React from 'react';
2
2
  import { QUEUE_SERVICE_UUIDS } from '../../shared/constants/concepts';
3
3
  import ServiceQueueComponent from '../service-queue/service-queue.component';
4
+ import MetricsContainer from '../metrics/metrics-container.component';
4
5
  const Consultation: React.FC = () => {
5
6
  return (
6
7
  <>
8
+ <MetricsContainer />
7
9
  <ServiceQueueComponent
8
10
  serviceTypeUuid={QUEUE_SERVICE_UUIDS.CLINICAL_CONSULTATION_SERVICE_UUID}
9
11
  title="Clinical Consultation"
@@ -1,17 +1,34 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { MetricsCard, MetricsCardHeader, MetricsCardBody, MetricsCardItem } from './metrics-card.component';
4
- import { useServiceMetricsCount } from '../metrics.resource';
4
+ import { useSession } from '@openmrs/esm-framework';
5
+ import { QUEUE_SERVICE_UUIDS } from '../../../shared/constants/concepts';
6
+ import { getServiceQueueByLocationUuid } from '../../service-queues.resource';
7
+ import { type QueueEntryResult } from '../../../registry/types';
5
8
 
6
9
  export default function AttendedToPatientsExtension() {
7
10
  const { t } = useTranslation();
8
- const { serviceCount, isLoading } = useServiceMetricsCount("COMPLETED");
11
+
12
+ const [consultationQueueEntries, setConsultationQueueEntries] = useState<QueueEntryResult[]>([]);
13
+ const session = useSession();
14
+ const locationUuid = session.sessionLocation.uuid;
15
+ const consultationServiceUuid = QUEUE_SERVICE_UUIDS.CLINICAL_CONSULTATION_SERVICE_UUID;
16
+ useEffect(() => {
17
+ getConsultationEntryQueues();
18
+ }, []);
19
+
20
+ const getConsultationEntryQueues = async () => {
21
+ const res = await getServiceQueueByLocationUuid(consultationServiceUuid, locationUuid);
22
+ setConsultationQueueEntries(res);
23
+ };
24
+
25
+ const attendedToPatientsCount = consultationQueueEntries?.filter((p) => p.status === 'COMPLETED').length ?? 0;
9
26
 
10
27
  return (
11
28
  <MetricsCard>
12
29
  <MetricsCardHeader title={t('patientsAttendedTo', 'Patients attended to')} />
13
30
  <MetricsCardBody>
14
- <MetricsCardItem label={t('patients', 'Patients')} value={isLoading ? '--' : serviceCount ?? 0} />
31
+ <MetricsCardItem label={t('patients', 'Patients')} value={attendedToPatientsCount} />
15
32
  </MetricsCardBody>
16
33
  </MetricsCard>
17
34
  );
@@ -1,17 +1,33 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { MetricsCard, MetricsCardHeader, MetricsCardBody, MetricsCardItem } from './metrics-card.component';
4
- import { useServiceMetricsCount } from '../metrics.resource';
4
+ import { getServiceQueueByLocationUuid } from '../../service-queues.resource';
5
+ import { QUEUE_SERVICE_UUIDS } from '../../../shared/constants/concepts';
6
+ import { useSession } from '@openmrs/esm-framework';
7
+ import { type QueueEntryResult } from '../../../registry/types';
5
8
 
6
9
  export default function WaitingPatientsExtension() {
7
10
  const { t } = useTranslation();
8
- const { serviceCount, isLoading } = useServiceMetricsCount("WAITING");
11
+ const [consultationQueueEntries, setConsultationQueueEntries] = useState<QueueEntryResult[]>([]);
12
+ const session = useSession();
13
+ const locationUuid = session.sessionLocation.uuid;
14
+ const consultationServiceUuid = QUEUE_SERVICE_UUIDS.CLINICAL_CONSULTATION_SERVICE_UUID;
15
+ useEffect(() => {
16
+ getConsultationEntryQueues();
17
+ }, []);
18
+
19
+ const getConsultationEntryQueues = async () => {
20
+ const res = await getServiceQueueByLocationUuid(consultationServiceUuid, locationUuid);
21
+ setConsultationQueueEntries(res);
22
+ };
23
+
24
+ const waitingPatientsCount = consultationQueueEntries?.filter((p) => p.status === 'WAITING').length ?? 0;
9
25
 
10
26
  return (
11
27
  <MetricsCard>
12
28
  <MetricsCardHeader title={t('patientsInWaiting', 'Patients in waiting')} />
13
29
  <MetricsCardBody>
14
- <MetricsCardItem label={t('patients', 'Patients')} value={isLoading ? '--' : serviceCount ?? 0} />
30
+ <MetricsCardItem label={t('patients', 'Patients')} value={waitingPatientsCount ? waitingPatientsCount : '--'} />
15
31
  </MetricsCardBody>
16
32
  </MetricsCard>
17
33
  );
@@ -95,6 +95,7 @@ const QueueList: React.FC<QueueListProps> = ({
95
95
  <OverflowMenu aria-label="overflow-menu">
96
96
  <OverflowMenuItem itemText="Move" onClick={() => handleMovePatient(val)} />
97
97
  <OverflowMenuItem itemText="Transition" onClick={() => handleTransitionPatient(val)} />
98
+ <OverflowMenuItem itemText="Sign off" onClick={handleCheckin} />
98
99
  <OverflowMenuItem itemText="Remove Patient" />
99
100
  </OverflowMenu>
100
101
  </>
@@ -0,0 +1,42 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import {
4
+ MetricsCard,
5
+ MetricsCardHeader,
6
+ MetricsCardBody,
7
+ MetricsCardItem,
8
+ } from '../../service-queues/metrics/metrics-cards/metrics-card.component';
9
+ import { useSession } from '@openmrs/esm-framework';
10
+ import { QUEUE_SERVICE_UUIDS } from '../../shared/constants/concepts';
11
+ import { getServiceQueueByLocationUuid } from '../../service-queues/service-queues.resource';
12
+ import { type QueueEntryResult } from '../../registry/types';
13
+
14
+ export default function TriageAttendedToPatientsExtension() {
15
+ const { t } = useTranslation();
16
+ const [triageQueueEntries, setTriageQueueEntries] = useState<QueueEntryResult[]>([]);
17
+ const session = useSession();
18
+ const locationUuid = session.sessionLocation.uuid;
19
+ const triageServiceUuid = QUEUE_SERVICE_UUIDS.TRIAGE_SERVICE_UUID;
20
+ useEffect(() => {
21
+ getTriageEntryQueues();
22
+ }, []);
23
+
24
+ const getTriageEntryQueues = async () => {
25
+ const res = await getServiceQueueByLocationUuid(triageServiceUuid, locationUuid);
26
+ setTriageQueueEntries(res);
27
+ };
28
+
29
+ const attendedToPatientsCount = triageQueueEntries?.filter((p) => p.status === 'COMPLETED').length ?? 0;
30
+
31
+ return (
32
+ <MetricsCard>
33
+ <MetricsCardHeader title={t('patientsAttendedTo', 'Patients attended to')} />
34
+ <MetricsCardBody>
35
+ <MetricsCardItem
36
+ label={t('patients', 'Patients')}
37
+ value={attendedToPatientsCount ? attendedToPatientsCount : '--'}
38
+ />
39
+ </MetricsCardBody>
40
+ </MetricsCard>
41
+ );
42
+ }
@@ -0,0 +1,36 @@
1
+ @use '@carbon/layout';
2
+ @use '@openmrs/esm-styleguide/src/vars' as *;
3
+
4
+ .cardContainer {
5
+ background-color: $ui-02;
6
+ display: flex;
7
+ padding: layout.$spacing-05;
8
+ flex-flow: row wrap;
9
+ gap: layout.$spacing-05;
10
+ align-items: stretch;
11
+ }
12
+
13
+ .cardContainer > * {
14
+ flex: 1 0 0%;
15
+ min-width: 16rem;
16
+ }
17
+
18
+ // If we're on tablet and the screen is too small for 3 cards across
19
+ // @TODO: This will do nonsense things if there are not exactly 3 cards
20
+ @media (max-width: calc(layout.$spacing-05 * 4 + 18.75rem * 3)) {
21
+ :global(.omrs-breakpoint-lt-desktop) {
22
+ .cardContainer > *:has(:global(.cardWithChildren)) {
23
+ order: 999;
24
+ }
25
+ }
26
+ }
27
+
28
+ // If we're on desktop and the screen is too small for the left nav bar
29
+ // plus 3 cards across
30
+ @media (max-width: calc(16rem + layout.$spacing-05 * 4 + 18.75rem * 3)) {
31
+ :global(.omrs-breakpoint-gt-tablet) {
32
+ .cardContainer > *:has(:global(.cardWithChildren)) {
33
+ order: 999;
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { ExtensionSlot } from '@openmrs/esm-framework';
3
+ import styles from './metrics.scss';
4
+
5
+ export interface Service {
6
+ display: string;
7
+ uuid?: string;
8
+ }
9
+
10
+ function TriageMetricsContainer() {
11
+ return <ExtensionSlot name="triage-metrics-slot" className={styles.cardContainer} data-testid="clinic-metrics" />;
12
+ }
13
+
14
+ export default TriageMetricsContainer;
@@ -0,0 +1,39 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import {
4
+ MetricsCard,
5
+ MetricsCardHeader,
6
+ MetricsCardBody,
7
+ MetricsCardItem,
8
+ } from '../../service-queues/metrics/metrics-cards/metrics-card.component';
9
+ import { useSession } from '@openmrs/esm-framework';
10
+ import { QUEUE_SERVICE_UUIDS } from '../../shared/constants/concepts';
11
+ import { getServiceQueueByLocationUuid } from '../../service-queues/service-queues.resource';
12
+ import { type QueueEntryResult } from '../../registry/types';
13
+
14
+ export default function TriageWaitingPatientsExtension() {
15
+ const { t } = useTranslation();
16
+ const [triageQueueEntries, setTriageQueueEntries] = useState<QueueEntryResult[]>([]);
17
+ const session = useSession();
18
+ const locationUuid = session.sessionLocation.uuid;
19
+ const triageServiceUuid = QUEUE_SERVICE_UUIDS.TRIAGE_SERVICE_UUID;
20
+ useEffect(() => {
21
+ getTriageEntryQueues();
22
+ }, []);
23
+
24
+ const getTriageEntryQueues = async () => {
25
+ const res = await getServiceQueueByLocationUuid(triageServiceUuid, locationUuid);
26
+ setTriageQueueEntries(res);
27
+ };
28
+
29
+ const waitingPatientsCount = triageQueueEntries?.filter((p) => p.status === 'WAITING').length ?? 0;
30
+
31
+ return (
32
+ <MetricsCard>
33
+ <MetricsCardHeader title={t('patientsInWaiting', 'Patients in waiting')} />
34
+ <MetricsCardBody>
35
+ <MetricsCardItem label={t('patients', 'Patients')} value={waitingPatientsCount ? waitingPatientsCount : '--'} />
36
+ </MetricsCardBody>
37
+ </MetricsCard>
38
+ );
39
+ }
@@ -1,4 +1,6 @@
1
1
  import React from 'react';
2
+
3
+ import TriageMetricsContainer from './metrics/triage-metrics.component';
2
4
  import ServiceQueueComponent from '../service-queues/service-queue/service-queue.component';
3
5
  import { QUEUE_SERVICE_UUIDS } from '../shared/constants/concepts';
4
6
 
@@ -6,7 +8,10 @@ interface TriageProps {}
6
8
  const Triage: React.FC<TriageProps> = () => {
7
9
  return (
8
10
  <>
9
- <ServiceQueueComponent serviceTypeUuid={QUEUE_SERVICE_UUIDS.TRIAGE_SERVICE_UUID} title="Triage" />
11
+ <TriageMetricsContainer />
12
+ <div>
13
+ <ServiceQueueComponent serviceTypeUuid={QUEUE_SERVICE_UUIDS.TRIAGE_SERVICE_UUID} title="Triage" />
14
+ </div>
10
15
  </>
11
16
  );
12
17
  };
@@ -1,22 +1,16 @@
1
1
  export interface Patient {
2
2
  uuid: string;
3
- display: string;
4
- queue: {
5
- display: string;
6
- uuid: string;
7
- location: {
8
- display: string;
9
- uuid: string;
10
- };
11
- };
12
- status: {
13
- display: string;
14
- };
15
- patient: {
16
- uuid: string;
17
- person: {
18
- gender: string;
19
- age: number;
20
- };
21
- };
3
+ middle_name: string;
4
+ given_name: string;
5
+ family_name: string;
6
+ queue_room: string;
7
+ status: string | number;
8
+ patient_name: string;
9
+ patient_uuid: string;
10
+ priority: string | number;
11
+ }
12
+
13
+ export interface Room {
14
+ name: string;
15
+ patients: Patient[];
22
16
  }