@ampath/esm-dha-workflow-app 4.0.0-next.4 → 4.0.0-next.41

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 (167) hide show
  1. package/dist/104.js +2 -0
  2. package/dist/104.js.LICENSE.txt +9 -0
  3. package/dist/104.js.map +1 -0
  4. package/dist/15.js +1 -0
  5. package/dist/15.js.map +1 -0
  6. package/dist/246.js +2 -0
  7. package/dist/246.js.LICENSE.txt +54 -0
  8. package/dist/246.js.map +1 -0
  9. package/dist/327.js +1 -0
  10. package/dist/327.js.map +1 -0
  11. package/dist/339.js +1 -0
  12. package/dist/339.js.map +1 -0
  13. package/dist/709.js +1 -0
  14. package/dist/709.js.map +1 -0
  15. package/dist/710.js +2 -0
  16. package/dist/710.js.map +1 -0
  17. package/dist/729.js +1 -0
  18. package/dist/729.js.map +1 -0
  19. package/dist/752.js +1 -0
  20. package/dist/752.js.map +1 -0
  21. package/dist/833.js +1 -0
  22. package/dist/833.js.map +1 -0
  23. package/dist/91.js +1 -1
  24. package/dist/91.js.map +1 -1
  25. package/dist/93.js +1 -0
  26. package/dist/93.js.map +1 -0
  27. package/dist/938.js +1 -0
  28. package/dist/938.js.map +1 -0
  29. package/dist/esm-dha-workflow-app.js +1 -0
  30. package/dist/{openmrs-esm-home-app.js.buildmanifest.json → esm-dha-workflow-app.js.buildmanifest.json} +294 -55
  31. package/dist/{openmrs-esm-home-app.js.map → esm-dha-workflow-app.js.map} +1 -1
  32. package/dist/main.js +1 -1
  33. package/dist/main.js.map +1 -1
  34. package/dist/routes.json +1 -1
  35. package/package.json +3 -3
  36. package/src/accounting/accounting.component.tsx +13 -0
  37. package/src/appointments/appointments.component.tsx +13 -0
  38. package/src/bookings/daily/daily-bookings.component.scss +38 -0
  39. package/src/bookings/daily/daily-bookings.component.tsx +138 -0
  40. package/src/bookings/daily/daily-bookings.resource.ts +27 -0
  41. package/src/bookings/daily/filters/daily-bookings-filter.component.scss +15 -0
  42. package/src/bookings/daily/filters/daily-bookings-filter.component.tsx +80 -0
  43. package/src/bookings/daily/patient-list/daily-bookings-patient-list.component.tsx +97 -0
  44. package/src/bookings/types/index.ts +68 -0
  45. package/src/config-schema.ts +132 -32
  46. package/src/dashboard/dashboard.component.scss +7 -0
  47. package/src/dashboard/dashboard.component.tsx +63 -0
  48. package/src/dashboard/overview/overview.component.scss +70 -0
  49. package/src/dashboard/overview/overview.component.tsx +107 -0
  50. package/src/dashboard/patient-list/patient-list.component.tsx +41 -0
  51. package/src/hooks/useActions.ts +165 -0
  52. package/src/index.ts +23 -2
  53. package/src/laboratory/laboratory.component.tsx +13 -0
  54. package/src/left-panel/left-panel.component.tsx +20 -0
  55. package/src/left-panel/left-panel.scss +42 -0
  56. package/src/mch/queues/consultation/mch-consultation.tsx +18 -0
  57. package/src/mch/queues/triage/mch-triage.tsx +15 -0
  58. package/src/modals/sign-off-modal.scss +7 -0
  59. package/src/modals/sign-off-modal.tsx +52 -0
  60. package/src/mortuary/mortuary.component.tsx +13 -0
  61. package/src/pharmacy/pharmacy.component.tsx +13 -0
  62. package/src/registry/client-details/client-details.tsx +40 -0
  63. package/src/registry/modal/client-details-modal/client-details-modal.scss +28 -0
  64. package/src/registry/modal/client-details-modal/client-details-modal.tsx +81 -0
  65. package/src/registry/modal/otp-verification-modal/otp-verification-modal.scss +31 -0
  66. package/src/registry/modal/otp-verification-modal/otp-verification-modal.tsx +186 -0
  67. package/src/registry/modal/send-to-triage/send-to-triage.modal.scss +34 -0
  68. package/src/registry/modal/send-to-triage/send-to-triage.modal.tsx +302 -0
  69. package/src/registry/payment-details/payment-options/payment-options.tsx +21 -0
  70. package/src/registry/registry.component.scss +83 -0
  71. package/src/registry/registry.component.tsx +397 -2
  72. package/src/registry/registry.resource.ts +60 -0
  73. package/src/registry/types/index.ts +309 -0
  74. package/src/registry/utils/error-handler.ts +37 -0
  75. package/src/registry/utils/format-dependant-display-data.ts +8 -0
  76. package/src/registry/utils/hie-adapter.ts +56 -0
  77. package/src/registry/utils/hie-client-adapter.ts +309 -0
  78. package/src/registry/utils/mask-data.ts +21 -0
  79. package/src/resources/hie-amrs-automatic-registration.service.ts +16 -0
  80. package/src/resources/identifier-types.ts +27 -0
  81. package/src/resources/patient-resource.ts +62 -0
  82. package/src/resources/patient-search.resource.ts +22 -0
  83. package/src/resources/queue.resource.ts +60 -0
  84. package/src/resources/visit.resource.ts +38 -0
  85. package/src/root.component.tsx +42 -30
  86. package/src/root.scss +5 -9
  87. package/src/routes.json +43 -4
  88. package/src/service-queues/action-button.component.tsx +34 -0
  89. package/src/service-queues/action-overflow-menu-item.component.tsx +34 -0
  90. package/src/service-queues/consultation/consultation.component.scss +7 -0
  91. package/src/service-queues/consultation/consultation.component.tsx +15 -0
  92. package/src/service-queues/metrics/metrics-cards/attended-patients.extension.tsx +38 -0
  93. package/src/service-queues/metrics/metrics-cards/metrics-card.component.tsx +86 -0
  94. package/src/service-queues/metrics/metrics-cards/metrics-card.scss +106 -0
  95. package/src/service-queues/metrics/metrics-cards/waiting-patients.extension.tsx +34 -0
  96. package/src/service-queues/metrics/metrics-container.component.tsx +23 -0
  97. package/src/service-queues/metrics/metrics-container.scss +36 -0
  98. package/src/service-queues/metrics/metrics.resource.ts +65 -0
  99. package/src/service-queues/modals/move/move-patient.component.scss +35 -0
  100. package/src/service-queues/modals/move/move-patient.component.tsx +138 -0
  101. package/src/service-queues/modals/serve/serve-patient.comppnent.scss +0 -0
  102. package/src/service-queues/modals/serve/serve-patient.comppnent.tsx +80 -0
  103. package/src/service-queues/modals/sign-off/sign-off.modal.scss +0 -0
  104. package/src/service-queues/modals/sign-off/sign-off.modal.tsx +79 -0
  105. package/src/service-queues/modals/transition/transition-patient.component.scss +0 -0
  106. package/src/service-queues/modals/transition/transition-patient.component.tsx +122 -0
  107. package/src/service-queues/queue-list/queue-list.component.scss +19 -0
  108. package/src/service-queues/queue-list/queue-list.component.tsx +169 -0
  109. package/src/service-queues/queue-room.component.tsx +39 -0
  110. package/src/service-queues/room/room.component.tsx +58 -0
  111. package/src/service-queues/service-queue/service-queue.component.scss +14 -0
  112. package/src/service-queues/service-queue/service-queue.component.tsx +245 -0
  113. package/src/service-queues/service-queue/stats/stat-card/stat-card.component.scss +10 -0
  114. package/src/service-queues/service-queue/stats/stat-card/stat-card.component.tsx +23 -0
  115. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.scss +7 -0
  116. package/src/service-queues/service-queue/stats/stat-details/stat-details.component.tsx +34 -0
  117. package/src/service-queues/service-queue.scss +27 -0
  118. package/src/service-queues/service-queue.tsx +31 -0
  119. package/src/service-queues/service-queues.resource.ts +177 -0
  120. package/src/service-queues/service.resource.ts +28 -0
  121. package/src/shared/constants/civil-status.ts +29 -0
  122. package/src/shared/constants/concepts.ts +30 -0
  123. package/src/shared/constants/index.ts +1 -0
  124. package/src/shared/constants/person-attributes.ts +33 -0
  125. package/src/shared/services/location.resource.ts +9 -0
  126. package/src/shared/ui/otp-input/otp-input.component.scss +14 -0
  127. package/src/shared/ui/otp-input/otp-input.component.tsx +90 -0
  128. package/src/shared/ui/timer/timer.component.scss +5 -0
  129. package/src/shared/ui/timer/timer.component.tsx +40 -0
  130. package/src/shared/utils/get-base-url.ts +17 -0
  131. package/src/side-nav-menu/nav-link-config.ts +82 -0
  132. package/src/side-nav-menu/nav-links.tsx +31 -11
  133. package/src/triage/metrics/attended-patients.extension.tsx +42 -0
  134. package/src/triage/metrics/metrics.scss +36 -0
  135. package/src/triage/metrics/triage-metrics.component.tsx +21 -0
  136. package/src/triage/metrics/waiting-patients.extension.tsx +39 -0
  137. package/src/triage/room/room.scss +29 -0
  138. package/src/triage/triage.component.tsx +15 -0
  139. package/src/triage/triage.resource.ts +19 -0
  140. package/src/triage/types.ts +16 -0
  141. package/src/types/types.ts +128 -0
  142. package/dist/561.js +0 -2
  143. package/dist/561.js.map +0 -1
  144. package/dist/70.js +0 -1
  145. package/dist/70.js.map +0 -1
  146. package/dist/731.js +0 -2
  147. package/dist/731.js.LICENSE.txt +0 -39
  148. package/dist/731.js.map +0 -1
  149. package/dist/819.js +0 -1
  150. package/dist/819.js.map +0 -1
  151. package/dist/openmrs-esm-home-app.js +0 -1
  152. package/src/boxes/extensions/blue-box.component.tsx +0 -15
  153. package/src/boxes/extensions/box.scss +0 -23
  154. package/src/boxes/extensions/brand-box.component.tsx +0 -15
  155. package/src/boxes/extensions/red-box.component.tsx +0 -15
  156. package/src/boxes/slot/boxes.component.tsx +0 -25
  157. package/src/boxes/slot/boxes.scss +0 -29
  158. package/src/greeter/greeter.component.tsx +0 -42
  159. package/src/greeter/greeter.scss +0 -20
  160. package/src/greeter/greeter.test.tsx +0 -28
  161. package/src/patient-getter/patient-getter.component.tsx +0 -40
  162. package/src/patient-getter/patient-getter.resource.ts +0 -39
  163. package/src/patient-getter/patient-getter.scss +0 -16
  164. package/src/patient-getter/patient-getter.test.tsx +0 -40
  165. package/src/resources/resources.component.tsx +0 -56
  166. package/src/resources/resources.scss +0 -68
  167. /package/dist/{561.js.LICENSE.txt → 710.js.LICENSE.txt} +0 -0
@@ -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;
@@ -0,0 +1,27 @@
1
+ @use '@carbon/layout';
2
+ @use '@openmrs/esm-styleguide/src/vars' as *;
3
+
4
+ .menuItem {
5
+ max-width: none;
6
+ }
7
+
8
+ .cardContainer {
9
+ background-color: $ui-02;
10
+ display: flex;
11
+ padding: layout.$spacing-05;
12
+ flex-flow: row wrap;
13
+ gap: layout.$spacing-05;
14
+ align-items: stretch;
15
+ }
16
+
17
+ .cardContainer > * {
18
+ flex: 1 0 0%;
19
+ min-width: 25rem;
20
+ max-width: 35rem;
21
+ }
22
+
23
+ .cardHeaderStack {
24
+ width: 100%;
25
+ justify-content: space-between;
26
+ align-items: center;
27
+ }
@@ -0,0 +1,31 @@
1
+ /* eslint-disable no-console */
2
+ import React, { useMemo } from 'react';
3
+ import MetricsContainer from './metrics/metrics-container.component';
4
+ import QueueRoom from './queue-room.component';
5
+ import { type QueueEntryAction } from '../config-schema';
6
+
7
+ interface ServiceQueueProps {
8
+ isTriage: boolean;
9
+ }
10
+ const ServiceQueue: React.FC<ServiceQueueProps> = ({ isTriage }) => {
11
+ const roomParams = useMemo(() => {
12
+ return isTriage ? {
13
+ serviceUuid: 'triage-service-uuid',
14
+ overflowMenuKeys: ['call', 'transition', 'edit', 'remove', 'undo'] as QueueEntryAction[],
15
+ defaultMenuKey: 'call' as QueueEntryAction
16
+ } : {
17
+ serviceUuid: '7f7ec7ad-cdd7-4ed9-bc2e-5c5bd9f065b2',
18
+ overflowMenuKeys: ['move', 'transition', 'signOff', 'edit', 'remove', 'undo'] as QueueEntryAction[],
19
+ defaultMenuKey: 'move' as QueueEntryAction
20
+ };
21
+ }
22
+ , [isTriage]);
23
+
24
+ return (<>
25
+ <MetricsContainer />
26
+ <QueueRoom serviceUuid={roomParams.serviceUuid} overflowMenuKeys={roomParams.overflowMenuKeys} defaultMenuKey={roomParams.defaultMenuKey}/>
27
+ </>
28
+ );
29
+ };
30
+
31
+ export default ServiceQueue;
@@ -0,0 +1,177 @@
1
+ import { type Encounter, formatDate, openmrsFetch, parseDate, restBaseUrl, useSession } from '@openmrs/esm-framework';
2
+ import {
3
+ type QueueEntryResponse,
4
+ type Identifer,
5
+ type MappedEncounter,
6
+ type MappedVisitQueueEntry,
7
+ type QueueEntry,
8
+ } from '../types/types';
9
+ import dayjs from 'dayjs';
10
+ import useSWR from 'swr';
11
+ import { useMemo } from 'react';
12
+ import { type QueueEntryResult } from '../registry/types';
13
+ import { getEtlBaseUrl } from '../shared/utils/get-base-url';
14
+
15
+ export function serveQueueEntry(servicePointName: string, ticketNumber: string, status: string) {
16
+ const abortController = new AbortController();
17
+
18
+ return openmrsFetch(`${restBaseUrl}/queueutil/assignticket`, {
19
+ method: 'POST',
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ },
23
+ signal: abortController.signal,
24
+ body: {
25
+ servicePointName,
26
+ ticketNumber,
27
+ status,
28
+ },
29
+ });
30
+ }
31
+
32
+ const mapEncounterProperties = (encounter: Encounter): MappedEncounter => ({
33
+ diagnoses: encounter.diagnoses,
34
+ encounterDatetime: encounter.encounterDatetime,
35
+ encounterType: encounter.encounterType.display,
36
+ obs: encounter.obs,
37
+ provider: encounter.encounterProviders[0]?.provider?.person?.display,
38
+ uuid: encounter.uuid,
39
+ voided: encounter.voided,
40
+ });
41
+
42
+ export const mapVisitQueueEntryProperties = (
43
+ queueEntry: QueueEntry,
44
+ visitQueueNumberAttributeUuid: string,
45
+ ): MappedVisitQueueEntry => ({
46
+ id: queueEntry.uuid,
47
+ encounters: queueEntry.visit?.encounters?.map(mapEncounterProperties),
48
+ name: queueEntry.display,
49
+ patientUuid: queueEntry.patient.uuid,
50
+ patientAge: queueEntry.patient.person?.age + '',
51
+ patientDob: queueEntry?.patient?.person?.birthdate
52
+ ? formatDate(parseDate(queueEntry.patient.person.birthdate), { time: false })
53
+ : '--',
54
+ patientGender: queueEntry.patient.person.gender,
55
+ queue: queueEntry.queue,
56
+ priority: queueEntry.priority,
57
+ priorityComment: queueEntry.priorityComment,
58
+ status: queueEntry.status,
59
+ startedAt: dayjs(queueEntry.startedAt).toDate(),
60
+ endedAt: queueEntry.endedAt ? dayjs(queueEntry.endedAt).toDate() : null,
61
+ visitType: queueEntry.visit?.visitType?.display,
62
+ queueLocation: (queueEntry?.queue as any)?.location?.uuid,
63
+ visitTypeUuid: queueEntry.visit?.visitType?.uuid,
64
+ visitUuid: queueEntry.visit?.uuid,
65
+ queueUuid: queueEntry.queue.uuid,
66
+ queueEntryUuid: queueEntry.uuid,
67
+ sortWeight: queueEntry.sortWeight,
68
+ visitQueueNumber: queueEntry.visit?.attributes?.find((e) => e?.attributeType?.uuid === visitQueueNumberAttributeUuid)
69
+ ?.value,
70
+ identifiers: queueEntry.patient?.identifiers as Identifer[],
71
+ queueComingFrom: queueEntry?.queueComingFrom?.name,
72
+ });
73
+
74
+ export function useQueueEntries(queue: string) {
75
+ // const queueEntryBaseUrl = `${restBaseUrl}/queue-entry?` +
76
+ // `isEnded=false&service=7f7ec7ad-cdd7-4ed9-bc2e-5c5bd9f065b2&location=18c343eb-b353-462a-9139-b16606e6b6c2`;
77
+ const queueEntryBaseUrl = `${restBaseUrl}/queue-entry?` + `isEnded=false&queue=${queue}`;
78
+ const {
79
+ data,
80
+ isValidating,
81
+ isLoading,
82
+ error: pageError,
83
+ } = useSWR<QueueEntryResponse, Error>(queueEntryBaseUrl, openmrsFetch);
84
+
85
+ const queueEntries = useMemo(() => data, [data]);
86
+
87
+ return {
88
+ queueEntries,
89
+ isLoading,
90
+ };
91
+ }
92
+
93
+ export function useQueues(service: string = '7f7ec7ad-cdd7-4ed9-bc2e-5c5bd9f065b2') {
94
+ const currentUserSession = useSession();
95
+ const location = currentUserSession?.sessionLocation?.uuid;
96
+
97
+ const customRepresentation = 'custom:(uuid,display,name)';
98
+
99
+ const apiUrl =
100
+ `${restBaseUrl}/queue?&service=${service}` +
101
+ (location ? `&location=${location}` : '') +
102
+ `&v=${customRepresentation}`;
103
+
104
+ const { data, isLoading } = useSWR<
105
+ {
106
+ data: {
107
+ results: Array<{
108
+ uuid: string;
109
+ display: string;
110
+ name: string;
111
+ }>;
112
+ };
113
+ },
114
+ Error
115
+ >(service ? apiUrl : null, openmrsFetch);
116
+
117
+ return { data, isLoading };
118
+ }
119
+
120
+ export function useQueue(service: string = '7f7ec7ad-cdd7-4ed9-bc2e-5c5bd9f065b2') {
121
+ const currentUserSession = useSession();
122
+ const location = currentUserSession?.sessionLocation?.uuid;
123
+
124
+ const customRepresentation = 'custom:(uuid,display,name)';
125
+
126
+ const apiUrl =
127
+ `${restBaseUrl}/queue?&service=${service}` +
128
+ (location ? `&location=${location}` : '') +
129
+ `&v=${customRepresentation}`;
130
+
131
+ const { data, isLoading } = useSWR<
132
+ {
133
+ data: {
134
+ results: Array<{
135
+ uuid: string;
136
+ display: string;
137
+ name: string;
138
+ }>;
139
+ };
140
+ },
141
+ Error
142
+ >(service ? apiUrl : null, openmrsFetch);
143
+
144
+ return { data, isLoading };
145
+ }
146
+
147
+ export async function getServiceQueueByLocationUuid(
148
+ serviceUuid: string,
149
+ locationUuid: string,
150
+ ): Promise<QueueEntryResult[]> {
151
+ const etlBaseUrl = await getEtlBaseUrl();
152
+ const queueEntryUrl = `${etlBaseUrl}/queue-entry`;
153
+ const params = {
154
+ locationUuid: locationUuid,
155
+ serviceUuid: serviceUuid,
156
+ };
157
+ const queryString = new URLSearchParams(params).toString();
158
+ const response = await openmrsFetch(`${queueEntryUrl}?${queryString}`);
159
+ const result = await response.json();
160
+ return result.data;
161
+ }
162
+
163
+ export async function closeQueueEntry(entryQueueUuid: string): Promise<QueueEntryResult[]> {
164
+ const queueEntryUrl = `${restBaseUrl}/queue-entry/${entryQueueUuid}`;
165
+ const params = {
166
+ endedAt: new Date().toISOString(),
167
+ };
168
+ const response = await openmrsFetch(queueEntryUrl, {
169
+ method: 'POST',
170
+ headers: {
171
+ 'content-type': 'application/json',
172
+ },
173
+ body: JSON.stringify(params),
174
+ });
175
+ const result = await response.json();
176
+ return result.data;
177
+ }
@@ -0,0 +1,28 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { type ServiceQueue } from '../registry/types';
3
+ import { type TransitionQueueEntryDto } from '../types/types';
4
+
5
+ export async function getServiceQueueByLocation(locationUuid: string): Promise<ServiceQueue[]> {
6
+ const params = {
7
+ v: 'custom:(uuid,name)',
8
+ location: locationUuid,
9
+ };
10
+ const queryString = new URLSearchParams(params).toString();
11
+ const queueEntryUrl = `${restBaseUrl}/queue`;
12
+ const response = await openmrsFetch(`${queueEntryUrl}?${queryString}`);
13
+ const result = await response.json();
14
+ return result.results;
15
+ }
16
+
17
+ export async function transitionQueueEntry(transitionQueueEntryDto: TransitionQueueEntryDto) {
18
+ const url = `${restBaseUrl}/queue-entry/transition`;
19
+ const resp = await openmrsFetch(url, {
20
+ method: 'POST',
21
+ headers: {
22
+ 'content-type': 'application/json',
23
+ },
24
+ body: JSON.stringify(transitionQueueEntryDto),
25
+ });
26
+ const res = await resp.json();
27
+ return res;
28
+ }
@@ -0,0 +1,29 @@
1
+ const SEPARATED_UUID = 'a899aba0-1350-11df-a1f1-0026b9348838';
2
+ const NEVER_MARRIED_UUID = 'a899ac7c-1350-11df-a1f1-0026b9348838';
3
+ const DIVORCED_UUID = 'a899ad58-1350-11df-a1f1-0026b9348838';
4
+ const WIDOWED_UUID = 'a899ae34-1350-11df-a1f1-0026b9348838';
5
+ const MARRIED_UUID = 'a8aa76b0-1350-11df-a1f1-0026b9348838';
6
+ const LIVING_WITH_PARTNER_UUID = 'a899af10-1350-11df-a1f1-0026b9348838';
7
+ const FRIEND_UUID = 'a8aaf07c-1350-11df-a1f1-0026b9348838';
8
+ const NOT_APPLICABLE_UUID = 'a89ad3a4-1350-11df-a1f1-0026b9348838';
9
+ const POLYGAMOUS_UUID = 'a8b03712-1350-11df-a1f1-0026b9348838';
10
+ const PARTNER_UUID = 'a89ebd3e-1350-11df-a1f1-0026b9348838';
11
+ const CASUAL_SEX_PARTNER_UUID = '7831f002-331d-4f07-bf91-6bb65cd31050';
12
+ const OTHER_UUID = 'a8aaf3e2-1350-11df-a1f1-0026b9348838';
13
+ const SINGLE_UUID = 'a899ac7c-1350-11df-a1f1-0026b9348838';
14
+
15
+ export const CivilStatusUids = {
16
+ SEPARATED_UUID,
17
+ NEVER_MARRIED_UUID,
18
+ DIVORCED_UUID,
19
+ WIDOWED_UUID,
20
+ MARRIED_UUID,
21
+ LIVING_WITH_PARTNER_UUID,
22
+ FRIEND_UUID,
23
+ NOT_APPLICABLE_UUID,
24
+ POLYGAMOUS_UUID,
25
+ PARTNER_UUID,
26
+ CASUAL_SEX_PARTNER_UUID,
27
+ SINGLE_UUID,
28
+ OTHER_UUID,
29
+ };
@@ -0,0 +1,30 @@
1
+ const NORMAL_PRIORITY_UUID = 'bbd99c12-67e9-4381-8b4c-1f231e86f8e2';
2
+ const EMERGENCY_PRIORITY_UUID = '8e86ff12-ec83-41e8-a534-bb410739d880';
3
+
4
+ const WAITING_UUID = '89d01aa5-0ab0-4626-934b-37766b4cd779';
5
+ const IN_SERVICE_UUID = 'f9cf5768-508f-45de-8d40-eaf6ea3f3b02';
6
+ const COMPLETED_UUID = 'a89c1ef8-1350-11df-a1f1-0026b9348838';
7
+
8
+ const TRIAGE_SERVICE_UUID = '2d4472e2-d7ab-4430-8e0e-a9ffcd809bf4';
9
+ const CLINICAL_CONSULTATION_SERVICE_UUID = '7f7ec7ad-cdd7-4ed9-bc2e-5c5bd9f065b2';
10
+
11
+ const MCH_TRIAGE_SERVICE_UUID = '7e4452bf-f9b7-4977-a21f-1c8b94831bac';
12
+ const MCH_CLINICAL_CONSULTATION_SERVICE_UUID = '0026e273-5f8c-46b5-8bb4-0d8301d50321';
13
+
14
+ export const QUEUE_PRIORITIES_UUIDS = {
15
+ NORMAL_PRIORITY_UUID,
16
+ EMERGENCY_PRIORITY_UUID,
17
+ };
18
+
19
+ export const QUEUE_STATUS_UUIDS = {
20
+ WAITING_UUID,
21
+ IN_SERVICE_UUID,
22
+ COMPLETED_UUID,
23
+ };
24
+
25
+ export const QUEUE_SERVICE_UUIDS = {
26
+ TRIAGE_SERVICE_UUID,
27
+ CLINICAL_CONSULTATION_SERVICE_UUID,
28
+ MCH_TRIAGE_SERVICE_UUID,
29
+ MCH_CLINICAL_CONSULTATION_SERVICE_UUID,
30
+ };
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,33 @@
1
+ const CONTACT_PHONE_NUMBER_UUID = '72a759a8-1359-11df-a1f1-0026b9348838';
2
+ const CITIZENSHIP_UUID = '8d871afc-c2cc-11de-8d13-0010c6dffd0f';
3
+ const CONTACT_EMAIL_ADDRESS_UUID = '2f65dbcb-3e58-45a3-8be7-fd1dc9aa0faa';
4
+ const ALTERNATIVE_CONTACT_PHONE_NUMBER_UUID = 'c725f524-c14a-4468-ac19-4a0e6661c930';
5
+ const KRA_PIN_UUID = 'ae683747-b3fc-4e5c-bad3-c3be743b248f';
6
+ const CIVIL_STATUS_UUID = '8d871f2a-c2cc-11de-8d13-0010c6dffd0f';
7
+ const CLIENT_REGISTRY_ID_UUID = 'e068e02b-faac-4baf-bd58-fe6e0c29a81f';
8
+ const PLACE_OF_BIRTH_UUID = '8d8718c2-c2cc-11de-8d13-0010c6dffd0f';
9
+ const EMAIL_UUID = '2f65dbcb-3e58-45a3-8be7-fd1dc9aa0faa';
10
+ const HIGHEST_LEVEL_OF_EDUCATION_UUID = '352b0d51-63c6-47d0-a295-156bebee4fd5';
11
+ const RELIGION_UUID = '4ae16101-cfba-4c08-9c9c-d848e6f609aa';
12
+ const OCCUPATION_UUID = '9e86409f-9c20-42d0-aeb3-f29a4ca0a7a0';
13
+ const NEXT_OF_KIN_CONTACT_PHONE_NUMBER_UUID = 'a657a4f1-9c0f-444b-a1fd-445bb91dd12d';
14
+ const NEXT_OF_KIN_NAME_UUID = '72a75bec-1359-11df-a1f1-0026b9348838';
15
+ const NEXT_OF_KIN_RELATIONSHIP_UUID = '5730994e-c267-426b-87b6-c152b606973d';
16
+
17
+ export const PersonAttributeTypeUuids = {
18
+ CONTACT_PHONE_NUMBER_UUID,
19
+ CITIZENSHIP_UUID,
20
+ CONTACT_EMAIL_ADDRESS_UUID,
21
+ ALTERNATIVE_CONTACT_PHONE_NUMBER_UUID,
22
+ KRA_PIN_UUID,
23
+ CIVIL_STATUS_UUID,
24
+ CLIENT_REGISTRY_ID_UUID,
25
+ PLACE_OF_BIRTH_UUID,
26
+ EMAIL_UUID,
27
+ HIGHEST_LEVEL_OF_EDUCATION_UUID,
28
+ RELIGION_UUID,
29
+ OCCUPATION_UUID,
30
+ NEXT_OF_KIN_CONTACT_PHONE_NUMBER_UUID,
31
+ NEXT_OF_KIN_NAME_UUID,
32
+ NEXT_OF_KIN_RELATIONSHIP_UUID,
33
+ };
@@ -0,0 +1,9 @@
1
+ import { type Location, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+
3
+ export async function getLocationByUuid(locationUuid: string): Promise<Location> {
4
+ const locationBaseUrl = `${restBaseUrl}/location`;
5
+ const locationUrl = `${locationBaseUrl}/${locationUuid}`;
6
+ const resp = await openmrsFetch(locationUrl);
7
+ const data = await resp.json();
8
+ return data ?? null;
9
+ }
@@ -0,0 +1,14 @@
1
+ .otpDataInput{
2
+ width: 3rem;
3
+ height: 3rem;
4
+ text-align: center;
5
+ }
6
+ .otpInputContainer{
7
+ display: flex;
8
+ flex-direction: row;
9
+ column-gap: 5px;
10
+ }
11
+ .otpDataInputContainer{
12
+ width: 4rem;
13
+ height: 4rem;
14
+ }
@@ -0,0 +1,90 @@
1
+ import React, { useRef, useState } from 'react';
2
+ import { TextInput } from '@carbon/react';
3
+ import styles from './otp-input.component.scss';
4
+
5
+ interface OTPInputProps {
6
+ onChange: (otp: string) => void;
7
+ otpLength: number;
8
+ }
9
+
10
+ const OTPInput: React.FC<OTPInputProps> = ({ onChange, otpLength }) => {
11
+ const [otp, setOtp] = useState(Array(otpLength).fill(''));
12
+ const inputsRef = useRef([]);
13
+
14
+ if (!otpLength) {
15
+ return <>OTP Length not defined</>;
16
+ }
17
+
18
+ const focusInput = (index) => {
19
+ if (inputsRef.current[index]) {
20
+ inputsRef.current[index].focus();
21
+ }
22
+ };
23
+
24
+ const handleChange = (value, index) => {
25
+ if (!/^\d?$/.test(value)) return;
26
+
27
+ const newOtp = [...otp];
28
+ newOtp[index] = value;
29
+ setOtp(newOtp);
30
+
31
+ if (value && index < otpLength - 1) {
32
+ focusInput(index + 1);
33
+ }
34
+
35
+ onChange?.(newOtp.join(''));
36
+ };
37
+
38
+ const handleKeyDown = (e, index) => {
39
+ if (e.key === 'Backspace' && !otp[index] && index > 0) {
40
+ focusInput(index - 1);
41
+ }
42
+ };
43
+
44
+ const handlePaste = (e) => {
45
+ e.preventDefault();
46
+ const pasted = e.clipboardData.getData('text').replace(/\D/g, '').slice(0, otpLength);
47
+
48
+ if (!pasted) return;
49
+
50
+ const newOtp = [...otp];
51
+ pasted.split('').forEach((digit, i) => {
52
+ newOtp[i] = digit;
53
+ });
54
+
55
+ setOtp(newOtp);
56
+ onChange?.(newOtp.join(''));
57
+ focusInput(pasted.length - 1);
58
+ };
59
+
60
+ return (
61
+ <div className={styles.otpInputContainer} onPaste={handlePaste}>
62
+ {otp.map((digit, index) => (
63
+ <div className={styles.otpDataInputContainer}>
64
+ <TextInput
65
+ className={styles.otpDataInput}
66
+ key={index}
67
+ id={`otp-${index}`}
68
+ value={digit}
69
+ labelText=""
70
+ hideLabel
71
+ maxLength={1}
72
+ inputMode="numeric"
73
+ pattern="[0-9]*"
74
+ ref={(el) => (inputsRef.current[index] = el)}
75
+ onChange={(e) => handleChange(e.target.value, index)}
76
+ onKeyDown={(e) => handleKeyDown(e, index)}
77
+ style={{
78
+ height: '4rem',
79
+ width: '4rem',
80
+ borderStyle: 'solid grey',
81
+ backgroundColor: '#e5ebf7',
82
+ }}
83
+ />
84
+ </div>
85
+ ))}
86
+ </div>
87
+ );
88
+ };
89
+
90
+ export default OTPInput;
@@ -0,0 +1,5 @@
1
+ .timerData{
2
+ height: 3rem;
3
+ font-size: 30px;
4
+ color: #0055a5;
5
+ }
@@ -0,0 +1,40 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import styles from './timer.component.scss';
3
+
4
+ interface TimerProps {
5
+ durationInSeconds: number;
6
+ resetTimer: () => void;
7
+ onTimeUp: () => void;
8
+ }
9
+ const Timer: React.FC<TimerProps> = ({ durationInSeconds, resetTimer, onTimeUp }) => {
10
+ const [timeLeft, setTimeLeft] = useState(durationInSeconds);
11
+
12
+ useEffect(() => {
13
+ if (timeLeft <= 0) {
14
+ onTimeUp?.();
15
+ return;
16
+ }
17
+
18
+ const intervalId = setInterval(() => {
19
+ setTimeLeft((prev) => prev - 1);
20
+ }, 1000);
21
+
22
+ return () => clearInterval(intervalId);
23
+ }, [timeLeft]);
24
+
25
+ const convertToMinsAndSeconds = (timeInSeconds: number) => {
26
+ const min = Math.floor(timeInSeconds / 60);
27
+ const seconds = timeInSeconds % 60;
28
+ const formatedMin = min > 9 ? min : `0${min}`;
29
+ const formattedSec = seconds > 9 ? seconds : `0${seconds}`;
30
+ return `${formatedMin}:${formattedSec}`;
31
+ };
32
+ return (
33
+ <>
34
+ <div className={styles.timerData}>
35
+ <b>{convertToMinsAndSeconds(timeLeft)}</b>
36
+ </div>
37
+ </>
38
+ );
39
+ };
40
+ export default Timer;
@@ -0,0 +1,17 @@
1
+ import { getConfig } from '@openmrs/esm-framework';
2
+ import { moduleName } from '../..';
3
+
4
+ export async function getSubDomainUrl() {
5
+ const { subDomainUrl } = await getConfig(moduleName);
6
+ return subDomainUrl ?? null;
7
+ }
8
+
9
+ export async function getEtlBaseUrl() {
10
+ const { etlBaseUrl } = await getConfig(moduleName);
11
+ return etlBaseUrl ?? null;
12
+ }
13
+
14
+ export async function getHieBaseUrl() {
15
+ const { hieBaseUrl } = await getConfig(moduleName);
16
+ return hieBaseUrl ?? null;
17
+ }