@ampath/esm-dha-workflow-app 4.0.0-next.4 → 4.0.0-next.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/104.js +2 -0
- package/dist/104.js.LICENSE.txt +9 -0
- package/dist/104.js.map +1 -0
- package/dist/15.js +1 -0
- package/dist/15.js.map +1 -0
- package/dist/246.js +2 -0
- package/dist/246.js.LICENSE.txt +54 -0
- package/dist/246.js.map +1 -0
- package/dist/327.js +1 -0
- package/dist/327.js.map +1 -0
- package/dist/339.js +1 -0
- package/dist/339.js.map +1 -0
- package/dist/701.js +1 -0
- package/dist/701.js.map +1 -0
- package/dist/709.js +1 -0
- package/dist/709.js.map +1 -0
- package/dist/710.js +2 -0
- package/dist/710.js.map +1 -0
- package/dist/729.js +1 -0
- package/dist/729.js.map +1 -0
- package/dist/752.js +1 -0
- package/dist/752.js.map +1 -0
- package/dist/833.js +1 -0
- package/dist/833.js.map +1 -0
- package/dist/91.js +1 -1
- package/dist/91.js.map +1 -1
- package/dist/93.js +1 -0
- package/dist/93.js.map +1 -0
- package/dist/esm-dha-workflow-app.js +1 -0
- package/dist/{openmrs-esm-home-app.js.buildmanifest.json → esm-dha-workflow-app.js.buildmanifest.json} +293 -54
- package/dist/{openmrs-esm-home-app.js.map → esm-dha-workflow-app.js.map} +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +3 -3
- package/src/accounting/accounting.component.tsx +13 -0
- package/src/appointments/appointments.component.tsx +13 -0
- package/src/bookings/daily/daily-bookings.component.scss +38 -0
- package/src/bookings/daily/daily-bookings.component.tsx +138 -0
- package/src/bookings/daily/daily-bookings.resource.ts +27 -0
- package/src/bookings/daily/filters/daily-bookings-filter.component.scss +15 -0
- package/src/bookings/daily/filters/daily-bookings-filter.component.tsx +80 -0
- package/src/bookings/daily/patient-list/daily-bookings-patient-list.component.tsx +97 -0
- package/src/bookings/types/index.ts +68 -0
- package/src/config-schema.ts +132 -32
- package/src/dashboard/dashboard.component.scss +7 -0
- package/src/dashboard/dashboard.component.tsx +63 -0
- package/src/dashboard/overview/overview.component.scss +70 -0
- package/src/dashboard/overview/overview.component.tsx +107 -0
- package/src/dashboard/patient-list/patient-list.component.tsx +41 -0
- package/src/hooks/useActions.ts +165 -0
- package/src/index.ts +23 -2
- package/src/laboratory/laboratory.component.tsx +13 -0
- package/src/left-panel/left-panel.component.tsx +20 -0
- package/src/left-panel/left-panel.scss +42 -0
- package/src/mch/queues/consultation/mch-consultation.tsx +18 -0
- package/src/mch/queues/triage/mch-triage.tsx +15 -0
- package/src/modals/sign-off-modal.scss +7 -0
- package/src/modals/sign-off-modal.tsx +52 -0
- package/src/pharmacy/pharmacy.component.tsx +13 -0
- package/src/registry/client-details/client-details.tsx +40 -0
- package/src/registry/modal/client-details-modal/client-details-modal.scss +28 -0
- package/src/registry/modal/client-details-modal/client-details-modal.tsx +81 -0
- package/src/registry/modal/otp-verification-modal/otp-verification-modal.scss +31 -0
- package/src/registry/modal/otp-verification-modal/otp-verification-modal.tsx +186 -0
- package/src/registry/modal/send-to-triage/send-to-triage.modal.scss +34 -0
- package/src/registry/modal/send-to-triage/send-to-triage.modal.tsx +302 -0
- package/src/registry/payment-details/payment-options/payment-options.tsx +21 -0
- package/src/registry/registry.component.scss +83 -0
- package/src/registry/registry.component.tsx +397 -2
- package/src/registry/registry.resource.ts +60 -0
- package/src/registry/types/index.ts +309 -0
- package/src/registry/utils/error-handler.ts +37 -0
- package/src/registry/utils/format-dependant-display-data.ts +8 -0
- package/src/registry/utils/hie-adapter.ts +56 -0
- package/src/registry/utils/hie-client-adapter.ts +309 -0
- package/src/registry/utils/mask-data.ts +21 -0
- package/src/resources/hie-amrs-automatic-registration.service.ts +16 -0
- package/src/resources/identifier-types.ts +27 -0
- package/src/resources/patient-resource.ts +62 -0
- package/src/resources/patient-search.resource.ts +22 -0
- package/src/resources/queue.resource.ts +60 -0
- package/src/resources/visit.resource.ts +38 -0
- package/src/root.component.tsx +40 -30
- package/src/root.scss +5 -9
- package/src/routes.json +43 -4
- package/src/service-queues/action-button.component.tsx +34 -0
- package/src/service-queues/action-overflow-menu-item.component.tsx +34 -0
- package/src/service-queues/consultation/consultation.component.scss +7 -0
- package/src/service-queues/consultation/consultation.component.tsx +15 -0
- package/src/service-queues/metrics/metrics-cards/attended-patients.extension.tsx +38 -0
- package/src/service-queues/metrics/metrics-cards/metrics-card.component.tsx +86 -0
- package/src/service-queues/metrics/metrics-cards/metrics-card.scss +106 -0
- package/src/service-queues/metrics/metrics-cards/waiting-patients.extension.tsx +34 -0
- package/src/service-queues/metrics/metrics-container.component.tsx +23 -0
- package/src/service-queues/metrics/metrics-container.scss +36 -0
- package/src/service-queues/metrics/metrics.resource.ts +65 -0
- package/src/service-queues/modals/move/move-patient.component.scss +35 -0
- package/src/service-queues/modals/move/move-patient.component.tsx +138 -0
- package/src/service-queues/modals/serve/serve-patient.comppnent.scss +0 -0
- package/src/service-queues/modals/serve/serve-patient.comppnent.tsx +80 -0
- package/src/service-queues/modals/sign-off/sign-off.modal.scss +0 -0
- package/src/service-queues/modals/sign-off/sign-off.modal.tsx +79 -0
- package/src/service-queues/modals/transition/transition-patient.component.scss +0 -0
- package/src/service-queues/modals/transition/transition-patient.component.tsx +122 -0
- package/src/service-queues/queue-list/queue-list.component.scss +19 -0
- package/src/service-queues/queue-list/queue-list.component.tsx +169 -0
- package/src/service-queues/queue-room.component.tsx +39 -0
- package/src/service-queues/room/room.component.tsx +58 -0
- package/src/service-queues/service-queue/service-queue.component.scss +14 -0
- package/src/service-queues/service-queue/service-queue.component.tsx +245 -0
- package/src/service-queues/service-queue/stats/stat-card/stat-card.component.scss +10 -0
- package/src/service-queues/service-queue/stats/stat-card/stat-card.component.tsx +23 -0
- package/src/service-queues/service-queue/stats/stat-details/stat-details.component.scss +7 -0
- package/src/service-queues/service-queue/stats/stat-details/stat-details.component.tsx +34 -0
- package/src/service-queues/service-queue.scss +27 -0
- package/src/service-queues/service-queue.tsx +31 -0
- package/src/service-queues/service-queues.resource.ts +177 -0
- package/src/service-queues/service.resource.ts +28 -0
- package/src/shared/constants/civil-status.ts +29 -0
- package/src/shared/constants/concepts.ts +30 -0
- package/src/shared/constants/index.ts +1 -0
- package/src/shared/constants/person-attributes.ts +33 -0
- package/src/shared/services/location.resource.ts +9 -0
- package/src/shared/ui/otp-input/otp-input.component.scss +14 -0
- package/src/shared/ui/otp-input/otp-input.component.tsx +90 -0
- package/src/shared/ui/timer/timer.component.scss +5 -0
- package/src/shared/ui/timer/timer.component.tsx +40 -0
- package/src/shared/utils/get-base-url.ts +17 -0
- package/src/side-nav-menu/nav-link-config.ts +82 -0
- package/src/side-nav-menu/nav-links.tsx +31 -11
- package/src/triage/metrics/attended-patients.extension.tsx +42 -0
- package/src/triage/metrics/metrics.scss +36 -0
- package/src/triage/metrics/triage-metrics.component.tsx +21 -0
- package/src/triage/metrics/waiting-patients.extension.tsx +39 -0
- package/src/triage/room/room.scss +29 -0
- package/src/triage/triage.component.tsx +15 -0
- package/src/triage/triage.resource.ts +19 -0
- package/src/triage/types.ts +16 -0
- package/src/types/types.ts +128 -0
- package/dist/561.js +0 -2
- package/dist/561.js.map +0 -1
- package/dist/70.js +0 -1
- package/dist/70.js.map +0 -1
- package/dist/731.js +0 -2
- package/dist/731.js.LICENSE.txt +0 -39
- package/dist/731.js.map +0 -1
- package/dist/819.js +0 -1
- package/dist/819.js.map +0 -1
- package/dist/openmrs-esm-home-app.js +0 -1
- package/src/boxes/extensions/blue-box.component.tsx +0 -15
- package/src/boxes/extensions/box.scss +0 -23
- package/src/boxes/extensions/brand-box.component.tsx +0 -15
- package/src/boxes/extensions/red-box.component.tsx +0 -15
- package/src/boxes/slot/boxes.component.tsx +0 -25
- package/src/boxes/slot/boxes.scss +0 -29
- package/src/greeter/greeter.component.tsx +0 -42
- package/src/greeter/greeter.scss +0 -20
- package/src/greeter/greeter.test.tsx +0 -28
- package/src/patient-getter/patient-getter.component.tsx +0 -40
- package/src/patient-getter/patient-getter.resource.ts +0 -39
- package/src/patient-getter/patient-getter.scss +0 -16
- package/src/patient-getter/patient-getter.test.tsx +0 -40
- package/src/resources/resources.component.tsx +0 -56
- package/src/resources/resources.scss +0 -68
- /package/dist/{561.js.LICENSE.txt → 710.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type BookingFilter = {
|
|
2
|
+
startDate: string;
|
|
3
|
+
department: string;
|
|
4
|
+
locationUuids: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type BookingDto = BookingFilter & {
|
|
8
|
+
startIndex: string;
|
|
9
|
+
limit: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type DailyBookingsResult = {
|
|
13
|
+
ccc_number: string;
|
|
14
|
+
ovcid_id: string;
|
|
15
|
+
upi_number: string;
|
|
16
|
+
program: string;
|
|
17
|
+
rtc_date: string;
|
|
18
|
+
med_pick_up_date: string;
|
|
19
|
+
arv_first_regimen_start_date: string;
|
|
20
|
+
hiv_disclosure_status: string;
|
|
21
|
+
height: number;
|
|
22
|
+
weight: number;
|
|
23
|
+
stage: number;
|
|
24
|
+
patient_categorization: string;
|
|
25
|
+
service_delivery_model: string;
|
|
26
|
+
dsd_model: string;
|
|
27
|
+
cd4_date: string;
|
|
28
|
+
cd4_results: number;
|
|
29
|
+
patient_uuid: string;
|
|
30
|
+
gender: string;
|
|
31
|
+
birthdate: string;
|
|
32
|
+
age: number;
|
|
33
|
+
person_name: string;
|
|
34
|
+
identifiers: string;
|
|
35
|
+
phone_number: string;
|
|
36
|
+
latest_rtc_date: string;
|
|
37
|
+
latest_vl: number;
|
|
38
|
+
vl_category: string;
|
|
39
|
+
latest_vl_date: string;
|
|
40
|
+
last_appointment: string;
|
|
41
|
+
visit_type: string;
|
|
42
|
+
cur_meds: string;
|
|
43
|
+
previous_vl: number;
|
|
44
|
+
previous_vl_date: string;
|
|
45
|
+
nearest_center: string;
|
|
46
|
+
covid_19_vaccination_status: string;
|
|
47
|
+
sms_consent_provided: string;
|
|
48
|
+
sms_receive_time: string;
|
|
49
|
+
sms_delivery_status: string;
|
|
50
|
+
tb_screening_date: string;
|
|
51
|
+
patient_category: string;
|
|
52
|
+
tb_screening_result: string;
|
|
53
|
+
cervical_screening_date: string;
|
|
54
|
+
cervical_screening_method: string;
|
|
55
|
+
cervical_screening_result: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type DailyBookingsReponse = {
|
|
59
|
+
schemas: any;
|
|
60
|
+
sqlQuery: string;
|
|
61
|
+
result: DailyBookingsResult[];
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export enum DailyBookingType {
|
|
65
|
+
Appointments = 'daily-appointments',
|
|
66
|
+
Visits = 'daily-visits',
|
|
67
|
+
HasNotReturned = 'daily-has-not-returned',
|
|
68
|
+
}
|
package/src/config-schema.ts
CHANGED
|
@@ -1,39 +1,96 @@
|
|
|
1
1
|
import { Type, validator } from '@openmrs/esm-framework';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* This is the config schema. It expects a configuration object which
|
|
5
|
-
* looks like this:
|
|
6
|
-
*
|
|
7
|
-
* ```json
|
|
8
|
-
* { "casualGreeting": true, "whoToGreet": ["Mom"] }
|
|
9
|
-
* ```
|
|
10
|
-
*
|
|
11
|
-
* In OpenMRS Microfrontends, all config parameters are optional. Thus,
|
|
12
|
-
* all elements must have a reasonable default. A good default is one
|
|
13
|
-
* that works well with the reference application.
|
|
14
|
-
*
|
|
15
|
-
* To understand the schema below, please read the configuration system
|
|
16
|
-
* documentation:
|
|
17
|
-
* https://openmrs.github.io/openmrs-esm-core/#/main/config
|
|
18
|
-
* Note especially the section "How do I make my module configurable?"
|
|
19
|
-
* https://openmrs.github.io/openmrs-esm-core/#/main/config?id=im-developing-an-esm-module-how-do-i-make-it-configurable
|
|
20
|
-
* and the Schema Reference
|
|
21
|
-
* https://openmrs.github.io/openmrs-esm-core/#/main/config?id=schema-reference
|
|
22
|
-
*/
|
|
23
3
|
export const configSchema = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
4
|
+
concepts: {
|
|
5
|
+
defaultPriorityConceptUuid: {
|
|
6
|
+
_type: Type.ConceptUuid,
|
|
7
|
+
_default: false,
|
|
8
|
+
_description: 'The UUID of the default priority for the queues eg Not urgent.',
|
|
9
|
+
},
|
|
10
|
+
defaultStatusConceptUuid: {
|
|
11
|
+
_type: Type.ConceptUuid,
|
|
12
|
+
_default: '51ae5e4d-b72b-4912-bf31-a17efb690aeb',
|
|
13
|
+
_description: 'The UUID of the default status for the queues eg Waiting.',
|
|
14
|
+
},
|
|
15
|
+
defaultTransitionStatus: {
|
|
16
|
+
_type: Type.ConceptUuid,
|
|
17
|
+
_default: 'ca7494ae-437f-4fd0-8aae-b88b9a2ba47d',
|
|
18
|
+
_description: 'The UUID of the default status for attending a service in the queues eg In Service.',
|
|
19
|
+
},
|
|
20
|
+
systolicBloodPressureUuid: {
|
|
21
|
+
_type: Type.ConceptUuid,
|
|
22
|
+
_default: '5085AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
23
|
+
},
|
|
24
|
+
diastolicBloodPressureUuid: {
|
|
25
|
+
_type: Type.ConceptUuid,
|
|
26
|
+
_default: '5086AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
27
|
+
},
|
|
28
|
+
emergencyPriorityConceptUuid: {
|
|
29
|
+
_type: Type.ConceptUuid,
|
|
30
|
+
_default: false,
|
|
31
|
+
_description: 'The UUID of the priority with the highest sort weight for the queues eg Emergency.',
|
|
32
|
+
},
|
|
33
|
+
generalPatientNoteConceptUuid: {
|
|
34
|
+
_type: Type.ConceptUuid,
|
|
35
|
+
_default: '162169AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
36
|
+
_description:
|
|
37
|
+
'The UUID of the free text note field intended to capture unstructured description of the patient encounter',
|
|
38
|
+
},
|
|
39
|
+
heightUuid: {
|
|
40
|
+
_type: Type.ConceptUuid,
|
|
41
|
+
_default: '5090AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
42
|
+
},
|
|
43
|
+
historicalObsConceptUuid: {
|
|
44
|
+
_type: Type.Array,
|
|
45
|
+
_default: ['161643AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'],
|
|
46
|
+
_description: 'The Uuids of the obs that are displayed on the previous visit modal',
|
|
47
|
+
_elements: {
|
|
48
|
+
_type: Type.ConceptUuid,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
oxygenSaturationUuid: {
|
|
52
|
+
_type: Type.ConceptUuid,
|
|
53
|
+
_default: '5092AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
54
|
+
},
|
|
55
|
+
pulseUuid: {
|
|
56
|
+
_type: Type.ConceptUuid,
|
|
57
|
+
_default: '5087AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
58
|
+
},
|
|
59
|
+
problemListConceptUuid: {
|
|
60
|
+
_type: Type.ConceptUuid,
|
|
61
|
+
_default: '1284AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
62
|
+
},
|
|
63
|
+
respiratoryRateUuid: {
|
|
64
|
+
_type: Type.ConceptUuid,
|
|
65
|
+
_default: '5242AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
66
|
+
},
|
|
67
|
+
temperatureUuid: {
|
|
68
|
+
_type: Type.ConceptUuid,
|
|
69
|
+
_default: '5088AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
70
|
+
},
|
|
71
|
+
visitDiagnosesConceptUuid: {
|
|
72
|
+
_type: Type.ConceptUuid,
|
|
73
|
+
_default: '159947AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
74
|
+
},
|
|
75
|
+
weightUuid: {
|
|
76
|
+
_type: Type.ConceptUuid,
|
|
77
|
+
_default: '5089AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
subDomainUrl: {
|
|
81
|
+
_type: Type.String,
|
|
82
|
+
_description: 'Subdomain e.g training,staging',
|
|
83
|
+
_default: '',
|
|
84
|
+
},
|
|
85
|
+
etlBaseUrl: {
|
|
86
|
+
_type: Type.String,
|
|
87
|
+
_description: 'ETL Endpoint',
|
|
88
|
+
_default: '',
|
|
28
89
|
},
|
|
29
|
-
|
|
30
|
-
_type: Type.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
_elements: {
|
|
34
|
-
_type: Type.String,
|
|
35
|
-
},
|
|
36
|
-
_validators: [validator((v) => v.length > 0, 'At least one person must be greeted.')],
|
|
90
|
+
hieBaseUrl: {
|
|
91
|
+
_type: Type.String,
|
|
92
|
+
_description: 'HIE Endpoint',
|
|
93
|
+
_default: '',
|
|
37
94
|
},
|
|
38
95
|
};
|
|
39
96
|
|
|
@@ -41,3 +98,46 @@ export type Config = {
|
|
|
41
98
|
casualGreeting: boolean;
|
|
42
99
|
whoToGreet: Array<string>;
|
|
43
100
|
};
|
|
101
|
+
|
|
102
|
+
export interface ConfigObject {
|
|
103
|
+
// priorityConfigs: Array<PriorityConfig>;
|
|
104
|
+
appointmentStatuses: Array<string>;
|
|
105
|
+
// biometrics: BiometricsConfigObject;
|
|
106
|
+
concepts: {
|
|
107
|
+
defaultPriorityConceptUuid: string;
|
|
108
|
+
defaultStatusConceptUuid: string;
|
|
109
|
+
defaultTransitionStatus: string;
|
|
110
|
+
diastolicBloodPressureUuid: string;
|
|
111
|
+
emergencyPriorityConceptUuid: string;
|
|
112
|
+
generalPatientNoteConceptUuid: string;
|
|
113
|
+
heightUuid: string;
|
|
114
|
+
historicalObsConceptUuid: Array<string>;
|
|
115
|
+
oxygenSaturationUuid: string;
|
|
116
|
+
pulseUuid: string;
|
|
117
|
+
problemListConceptUuid: string;
|
|
118
|
+
respiratoryRateUuid: string;
|
|
119
|
+
systolicBloodPressureUuid: string;
|
|
120
|
+
temperatureUuid: string;
|
|
121
|
+
visitDiagnosesConceptUuid: string;
|
|
122
|
+
weightUuid: string;
|
|
123
|
+
};
|
|
124
|
+
defaultInitialServiceQueue: string;
|
|
125
|
+
contactAttributeType: string;
|
|
126
|
+
customPatientChartUrl: string;
|
|
127
|
+
defaultIdentifierTypes: Array<string>;
|
|
128
|
+
dashboardTitle: {
|
|
129
|
+
key: string;
|
|
130
|
+
value: string;
|
|
131
|
+
};
|
|
132
|
+
// queueTables: TablesConfig;
|
|
133
|
+
showRecommendedVisitTypeTab: boolean;
|
|
134
|
+
visitQueueNumberAttributeUuid: string | null;
|
|
135
|
+
visitTypeResourceUrl: string;
|
|
136
|
+
subDomainUrl: string;
|
|
137
|
+
etlBaseUrl: string;
|
|
138
|
+
hieBaseUrl: string;
|
|
139
|
+
// vitals: VitalsConfigObject;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const queueEntryActions = ['move', 'call', 'edit', 'transition', 'signOff', 'remove', 'delete', 'undo'] as const;
|
|
143
|
+
export type QueueEntryAction = (typeof queueEntryActions)[number];
|
|
@@ -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 scrollDebounceWait={200}>
|
|
37
|
+
<Tab>
|
|
38
|
+
<span className={styles.tabText}>Overview</span>
|
|
39
|
+
</Tab>
|
|
40
|
+
<Tab>
|
|
41
|
+
<span className={styles.tabText}>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,70 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
display: flex;
|
|
3
|
+
width: 100%;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
flex-wrap: wrap;
|
|
6
|
+
gap: 1rem;
|
|
7
|
+
|
|
8
|
+
.card {
|
|
9
|
+
border: 1px solid grey;
|
|
10
|
+
border-radius: 5px;
|
|
11
|
+
background-color: white;
|
|
12
|
+
font-weight: bold;
|
|
13
|
+
flex: 1 1 calc(33.33% - 1rem);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@media (max-width: 1024px) {
|
|
18
|
+
.container .card {
|
|
19
|
+
flex: 1 1 calc(50% - 1rem);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@media (max-width: 600px) {
|
|
24
|
+
.container .card {
|
|
25
|
+
flex: 1 1 100%;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
h4 {
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.dropdownItem {
|
|
35
|
+
display: flex;
|
|
36
|
+
justify-self: flex-end;
|
|
37
|
+
width: 25%;
|
|
38
|
+
min-width: 180px;
|
|
39
|
+
max-width: 280px;
|
|
40
|
+
margin-top: 5rem;
|
|
41
|
+
margin-bottom: 5rem;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.dropdownContainer {
|
|
45
|
+
.cds--list-box__menu-item__option {
|
|
46
|
+
font-weight: 600;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.cds--list-box__field {
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.queue {
|
|
55
|
+
color: palevioletred
|
|
56
|
+
}
|
|
57
|
+
.total {
|
|
58
|
+
color: gray;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.triage {
|
|
62
|
+
color: yelllow;
|
|
63
|
+
}
|
|
64
|
+
.consultation {
|
|
65
|
+
color: green;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.emergency {
|
|
69
|
+
color: red;
|
|
70
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
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 totalPatients: QueueEntryResult[] = [...triageCount, ...consultationCount];
|
|
15
|
+
const patientsInQueue = totalPatients.filter(
|
|
16
|
+
(patient) => patient.status === 'WAITING' || patient.status === 'IN SERVICE',
|
|
17
|
+
).length;
|
|
18
|
+
const [selected, setSelected] = useState<string | null>(null);
|
|
19
|
+
const triagePatients = triageCount?.length ?? 0;
|
|
20
|
+
const consultationPatients = consultationCount?.length ?? 0;
|
|
21
|
+
const dropDownItems = [
|
|
22
|
+
'Total Patients',
|
|
23
|
+
'Triage Patients',
|
|
24
|
+
'Consultation Patients',
|
|
25
|
+
'Walk-In Patients',
|
|
26
|
+
'Emergency Patients',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const handleDropdownChange = (data: { selectedItem: string }) => {
|
|
30
|
+
const value = data.selectedItem;
|
|
31
|
+
setSelected(value);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let selectedPatients: QueueEntryResult[] = [];
|
|
35
|
+
|
|
36
|
+
switch (selected) {
|
|
37
|
+
case 'Triage Patients':
|
|
38
|
+
selectedPatients = triageCount ?? [];
|
|
39
|
+
break;
|
|
40
|
+
|
|
41
|
+
case 'Consultation Patients':
|
|
42
|
+
selectedPatients = consultationCount ?? [];
|
|
43
|
+
break;
|
|
44
|
+
case 'Walk-In Patients':
|
|
45
|
+
selectedPatients = [];
|
|
46
|
+
break;
|
|
47
|
+
case 'Emergency Patients':
|
|
48
|
+
selectedPatients = [];
|
|
49
|
+
break;
|
|
50
|
+
|
|
51
|
+
case 'Total Patients':
|
|
52
|
+
selectedPatients = [...(triageCount ?? []), ...(consultationCount ?? [])];
|
|
53
|
+
break;
|
|
54
|
+
|
|
55
|
+
default:
|
|
56
|
+
selectedPatients = [...(triageCount ?? []), ...(consultationCount ?? [])];
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
<div className={styles.container}>
|
|
63
|
+
<Tile className={styles.card}>
|
|
64
|
+
<h4>Total Patients Today</h4>
|
|
65
|
+
<h5>Patients</h5>
|
|
66
|
+
<h4 className={styles.total}>{triagePatients + consultationPatients}</h4>
|
|
67
|
+
</Tile>
|
|
68
|
+
<Tile className={styles.card}>
|
|
69
|
+
<h4>Patients in Queue Today</h4>
|
|
70
|
+
<h5>Patients</h5>
|
|
71
|
+
<h4 className={styles.queue}>{patientsInQueue}</h4>
|
|
72
|
+
</Tile>
|
|
73
|
+
<Tile className={styles.card}>
|
|
74
|
+
<h4>Patients in Triage </h4>
|
|
75
|
+
<h5>Patients</h5>
|
|
76
|
+
<h4 className={styles.triage}>{triagePatients}</h4>
|
|
77
|
+
</Tile>
|
|
78
|
+
<Tile className={styles.card}>
|
|
79
|
+
<h4>Patients in Consultation </h4>
|
|
80
|
+
<h5>Patients</h5>
|
|
81
|
+
<h4 className={styles.consultation}>{consultationPatients}</h4>
|
|
82
|
+
</Tile>
|
|
83
|
+
<Tile className={styles.card}>
|
|
84
|
+
<h4>Walk-ins Today </h4>
|
|
85
|
+
<h5>Patients</h5>
|
|
86
|
+
<h4>0</h4>
|
|
87
|
+
</Tile>
|
|
88
|
+
<Tile className={styles.card}>
|
|
89
|
+
<h4>Emergencies Today </h4>
|
|
90
|
+
<h5>Patients</h5>
|
|
91
|
+
<h4 className={styles.emergency}>0</h4>
|
|
92
|
+
</Tile>
|
|
93
|
+
</div>
|
|
94
|
+
<FluidDropdown
|
|
95
|
+
className={styles.dropdownItem}
|
|
96
|
+
id={''}
|
|
97
|
+
items={dropDownItems}
|
|
98
|
+
label={'Total Patients'}
|
|
99
|
+
titleText={''}
|
|
100
|
+
onChange={handleDropdownChange}
|
|
101
|
+
></FluidDropdown>
|
|
102
|
+
<PatientList patients={selectedPatients} />
|
|
103
|
+
</>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
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;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { restBaseUrl, showModal, useConfig } from '@openmrs/esm-framework';
|
|
2
|
+
import { type ConfigObject, type QueueEntryAction } from '../config-schema';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { useSWRConfig } from 'swr';
|
|
5
|
+
import { type QueueEntry } from '../types/types';
|
|
6
|
+
import { mapVisitQueueEntryProperties, serveQueueEntry } from '../service-queues/service-queues.resource';
|
|
7
|
+
|
|
8
|
+
type ActionProps = {
|
|
9
|
+
label: string;
|
|
10
|
+
text: string;
|
|
11
|
+
onClick: (queueEntry: QueueEntry) => void;
|
|
12
|
+
showIf?: (queueEntry: QueueEntry) => boolean;
|
|
13
|
+
isDelete?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function useMutateQueueEntries() {
|
|
17
|
+
const { mutate } = useSWRConfig();
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
mutateQueueEntries: () => {
|
|
21
|
+
return mutate((key) => {
|
|
22
|
+
return (
|
|
23
|
+
typeof key === 'string' &&
|
|
24
|
+
(key.includes(`${restBaseUrl}/queue-entry`) || key.includes(`${restBaseUrl}/visit-queue-entry`))
|
|
25
|
+
);
|
|
26
|
+
}).then(() => {
|
|
27
|
+
window.dispatchEvent(new CustomEvent('queue-entry-updated'));
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function useActionPropsByKey() {
|
|
34
|
+
const {
|
|
35
|
+
concepts: { defaultStatusConceptUuid },
|
|
36
|
+
visitQueueNumberAttributeUuid,
|
|
37
|
+
} = useConfig<ConfigObject>();
|
|
38
|
+
const { mutateQueueEntries } = useMutateQueueEntries();
|
|
39
|
+
|
|
40
|
+
// Map action strings to component props
|
|
41
|
+
const actionPropsByKey: Record<QueueEntryAction, ActionProps> = useMemo(() => {
|
|
42
|
+
return {
|
|
43
|
+
call: {
|
|
44
|
+
// t('call', 'Call'),
|
|
45
|
+
label: 'call',
|
|
46
|
+
text: 'Call',
|
|
47
|
+
onClick: async (queueEntry: QueueEntry) => {
|
|
48
|
+
const mappedQueueEntry = mapVisitQueueEntryProperties(queueEntry, visitQueueNumberAttributeUuid);
|
|
49
|
+
const callingQueueResponse = await serveQueueEntry(
|
|
50
|
+
mappedQueueEntry.queue.name,
|
|
51
|
+
mappedQueueEntry.visitQueueNumber,
|
|
52
|
+
'calling',
|
|
53
|
+
);
|
|
54
|
+
if (callingQueueResponse.ok) {
|
|
55
|
+
await mutateQueueEntries();
|
|
56
|
+
const dispose = showModal('call-queue-entry-modal', {
|
|
57
|
+
closeModal: () => dispose(),
|
|
58
|
+
queueEntry,
|
|
59
|
+
size: 'sm',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
showIf: (queueEntry: QueueEntry) => {
|
|
64
|
+
return queueEntry.status.uuid === defaultStatusConceptUuid;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
move: {
|
|
68
|
+
// t('move', 'Move'),
|
|
69
|
+
label: 'move',
|
|
70
|
+
text: 'Move',
|
|
71
|
+
onClick: (queueEntry: QueueEntry) => {
|
|
72
|
+
const dispose = showModal('move-queue-entry-modal', {
|
|
73
|
+
closeModal: () => dispose(),
|
|
74
|
+
queueEntry,
|
|
75
|
+
size: 'sm',
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
transition: {
|
|
80
|
+
// t('transition', 'Transition'),
|
|
81
|
+
label: 'transition',
|
|
82
|
+
text: 'Transition',
|
|
83
|
+
onClick: (queueEntry: QueueEntry) => {
|
|
84
|
+
const dispose = showModal('transition-queue-entry-modal', {
|
|
85
|
+
closeModal: () => dispose(),
|
|
86
|
+
queueEntry,
|
|
87
|
+
size: 'sm',
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
edit: {
|
|
92
|
+
// t('edit', 'Edit'),
|
|
93
|
+
label: 'edit',
|
|
94
|
+
text: 'Edit',
|
|
95
|
+
onClick: (queueEntry: QueueEntry) => {
|
|
96
|
+
const dispose = showModal('edit-queue-entry-modal', {
|
|
97
|
+
closeModal: () => dispose(),
|
|
98
|
+
queueEntry,
|
|
99
|
+
size: 'sm',
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
remove: {
|
|
104
|
+
// t('removePatient', 'Remove patient'),
|
|
105
|
+
label: 'removePatient',
|
|
106
|
+
text: 'Remove patient',
|
|
107
|
+
onClick: (queueEntry: QueueEntry) => {
|
|
108
|
+
const dispose = showModal('remove-queue-entry-modal', {
|
|
109
|
+
closeModal: () => dispose(),
|
|
110
|
+
queueEntry,
|
|
111
|
+
size: 'sm',
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
delete: {
|
|
116
|
+
// t('deleteEntry', 'Delete entry'),
|
|
117
|
+
label: 'deleteEntry',
|
|
118
|
+
text: 'Delete entry',
|
|
119
|
+
onClick: (queueEntry: QueueEntry) => {
|
|
120
|
+
const dispose = showModal('delete-queue-entry-modal', {
|
|
121
|
+
closeModal: () => dispose(),
|
|
122
|
+
queueEntry,
|
|
123
|
+
size: 'sm',
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
isDelete: true,
|
|
127
|
+
showIf: (queueEntry: QueueEntry) => {
|
|
128
|
+
return queueEntry.previousQueueEntry === null;
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
undo: {
|
|
132
|
+
// t('undoTransition', 'Undo transition'),
|
|
133
|
+
label: 'undoTransition',
|
|
134
|
+
text: 'Undo transition',
|
|
135
|
+
onClick: (queueEntry: QueueEntry) => {
|
|
136
|
+
const dispose = showModal('undo-transition-queue-entry-modal', {
|
|
137
|
+
closeModal: () => dispose(),
|
|
138
|
+
queueEntry,
|
|
139
|
+
size: 'sm',
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
isDelete: true,
|
|
143
|
+
showIf: (queueEntry: QueueEntry) => {
|
|
144
|
+
return queueEntry.previousQueueEntry !== null;
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
signOff: {
|
|
148
|
+
// t('signOff', 'Sign off'),
|
|
149
|
+
label: 'signOff',
|
|
150
|
+
text: 'Sign off',
|
|
151
|
+
onClick: (queueEntry: QueueEntry) => {
|
|
152
|
+
const dispose = showModal('sign-off-queue-entry-modal', {
|
|
153
|
+
closeModal: () => dispose(),
|
|
154
|
+
queueEntry,
|
|
155
|
+
size: 'sm',
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
showIf: (queueEntry: QueueEntry) => {
|
|
159
|
+
return queueEntry.previousQueueEntry !== null;
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}, [defaultStatusConceptUuid, visitQueueNumberAttributeUuid, mutateQueueEntries]);
|
|
164
|
+
return actionPropsByKey;
|
|
165
|
+
}
|