@kenyaemr/esm-bed-management-app 1.0.1-pre.4 → 1.0.1-pre.43
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/26.js +1 -1
- package/dist/26.js.map +1 -1
- package/dist/294.js +1 -1
- package/dist/294.js.map +1 -1
- package/dist/360.js +1 -0
- package/dist/360.js.map +1 -0
- package/dist/452.js +1 -0
- package/dist/{884.js.map → 452.js.map} +1 -1
- package/dist/482.js +2 -0
- package/dist/482.js.LICENSE.txt +19 -0
- package/dist/482.js.map +1 -0
- package/dist/532.js +1 -0
- package/dist/532.js.map +1 -0
- package/dist/558.js +1 -1
- package/dist/558.js.map +1 -1
- package/dist/574.js +1 -1
- package/dist/663.js +2 -0
- package/dist/663.js.LICENSE.txt +44 -0
- package/dist/663.js.map +1 -0
- package/dist/666.js +1 -0
- package/dist/666.js.map +1 -0
- package/dist/708.js +2 -0
- package/dist/{330.js.LICENSE.txt → 708.js.LICENSE.txt} +0 -20
- package/dist/708.js.map +1 -0
- package/dist/763.js +2 -0
- package/dist/763.js.map +1 -0
- package/dist/774.js +1 -0
- package/dist/774.js.map +1 -0
- package/dist/815.js +1 -0
- package/dist/815.js.map +1 -0
- package/dist/847.js +1 -0
- package/dist/847.js.map +1 -0
- package/dist/898.js +1 -0
- package/dist/898.js.map +1 -0
- package/dist/931.js +1 -0
- package/dist/931.js.map +1 -0
- package/dist/935.js +1 -0
- package/dist/935.js.map +1 -0
- package/dist/esm-kenyaemr-bed-management-app.js +1 -1
- package/dist/esm-kenyaemr-bed-management-app.js.buildmanifest.json +207 -135
- package/dist/esm-kenyaemr-bed-management-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 +4 -1
- package/src/bed-administration/bed-administration-table.scss +3 -0
- package/src/bed-administration/bed-administration-types.ts +8 -0
- package/src/bed-admission/active-patients/active-patients-table.component.tsx +13 -20
- package/src/bed-admission/active-patients/active-visits.resource.ts +1 -3
- package/src/bed-admission/active-patients/eligible-admissions.resource.ts +43 -0
- package/src/bed-admission/admitted-patients/active-admissions.resource.ts +5 -1
- package/src/bed-admission/admitted-patients/admitted-patients-table.component.tsx +3 -3
- package/src/bed-admission/bed-admission-tabs.component.tsx +0 -1
- package/src/bed-admission/bed-admission.resource.ts +1 -1
- package/src/bed-admission/bed-layout/bed-layout-list.component.tsx +2 -2
- package/src/bed-admission/bed-tag/bed-tag-administration-table.component.tsx +240 -0
- package/src/bed-admission/bed-tag/bed-tags-admin-form.component.tsx +146 -0
- package/src/bed-admission/bed-tag/delete-bed-tag.component.tsx +69 -0
- package/src/bed-admission/bed-tag/delete-bedForm.component.tsx +108 -0
- package/src/bed-admission/bed-tag/edit-tag-form.component.tsx +80 -0
- package/src/bed-admission/bed-tag/new-tag-form.component.tsx +83 -0
- package/src/bed-admission/bed-type/bed-type-admin-form.component.tsx +203 -0
- package/src/bed-admission/bed-type/bed-type-administration-table.component.tsx +246 -0
- package/src/bed-admission/bed-type/delete-bed-type.component.tsx +69 -0
- package/src/bed-admission/bed-type/deleteBedtypeForm.component.tsx +108 -0
- package/src/bed-admission/bed-type/edit-bed-type.component.tsx +80 -0
- package/src/bed-admission/bed-type/new-bed-type-form.component.tsx +87 -0
- package/src/bed-admission/types.ts +1 -3
- package/src/bed-admission/ward/new-ward-form.component.tsx +81 -0
- package/src/bed-admission/ward/ward-admin-form.component.tsx +193 -0
- package/src/bed-admission/ward/ward-administration-table.component.tsx +173 -0
- package/src/config-schema.ts +7 -1
- package/src/index.ts +21 -0
- package/src/root.component.tsx +6 -0
- package/src/routes.json +16 -1
- package/src/summary/summary.resource.ts +257 -1
- package/src/types.ts +23 -0
- package/src/workspace/allocate-bed-workspace.component.tsx +51 -18
- package/src/workspace/allocate-bed.scss +7 -0
- package/tsconfig.json +2 -1
- package/dist/187.js +0 -1
- package/dist/187.js.map +0 -1
- package/dist/207.js +0 -1
- package/dist/207.js.map +0 -1
- package/dist/283.js +0 -1
- package/dist/283.js.map +0 -1
- package/dist/330.js +0 -2
- package/dist/330.js.map +0 -1
- package/dist/352.js +0 -1
- package/dist/352.js.map +0 -1
- package/dist/404.js +0 -1
- package/dist/404.js.map +0 -1
- package/dist/455.js +0 -2
- package/dist/455.js.map +0 -1
- package/dist/629.js +0 -1
- package/dist/629.js.map +0 -1
- package/dist/707.js +0 -1
- package/dist/707.js.map +0 -1
- package/dist/800.js +0 -2
- package/dist/800.js.LICENSE.txt +0 -3
- package/dist/800.js.map +0 -1
- package/dist/884.js +0 -1
- package/dist/933.js +0 -1
- package/dist/933.js.map +0 -1
- package/dist/959.js +0 -1
- package/dist/959.js.map +0 -1
- /package/.yarn/versions/{6816f0d4.yml → 739e37b3.yml} +0 -0
- /package/dist/{455.js.LICENSE.txt → 763.js.LICENSE.txt} +0 -0
|
@@ -10,3 +10,11 @@ export interface BedAdministrationData {
|
|
|
10
10
|
occupancyStatus: string;
|
|
11
11
|
bedType: string;
|
|
12
12
|
}
|
|
13
|
+
export interface BedTypeDataAdministration {
|
|
14
|
+
name: string;
|
|
15
|
+
displayName: string;
|
|
16
|
+
description: string;
|
|
17
|
+
}
|
|
18
|
+
export interface BedTagDataAdministration {
|
|
19
|
+
name: string;
|
|
20
|
+
}
|
|
@@ -29,21 +29,13 @@ import {
|
|
|
29
29
|
} from "@openmrs/esm-framework";
|
|
30
30
|
import React, { useCallback, useMemo, useState } from "react";
|
|
31
31
|
import { useTranslation } from "react-i18next";
|
|
32
|
-
import {
|
|
33
|
-
formatWaitTime,
|
|
34
|
-
getOriginFromPathName,
|
|
35
|
-
getTagColor,
|
|
36
|
-
getTagType,
|
|
37
|
-
trimVisitNumber,
|
|
38
|
-
} from "../helpers/functions";
|
|
32
|
+
import { getOriginFromPathName } from "../helpers/functions";
|
|
39
33
|
import styles from "./styles.scss";
|
|
40
|
-
import { usePatientQueuesList } from "./patient-queues.resource";
|
|
41
|
-
import { useActiveVisits } from "./active-visits.resource";
|
|
42
34
|
import EmptyState from "../../empty-state/empty-state.component";
|
|
43
35
|
import AssignBedWorkSpace from "../../workspace/allocate-bed-workspace.component";
|
|
44
36
|
import AdmissionActionButton from "./admission-action-button.component";
|
|
45
37
|
import { patientDetailsProps } from "../types";
|
|
46
|
-
import
|
|
38
|
+
import { useEligibleAdmissions } from "./eligible-admissions.resource";
|
|
47
39
|
|
|
48
40
|
interface ActiveVisitsTableProps {
|
|
49
41
|
status: string;
|
|
@@ -66,15 +58,15 @@ const ActivePatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
66
58
|
|
|
67
59
|
const layout = useLayoutType();
|
|
68
60
|
|
|
69
|
-
const { patientQueueEntries, isLoading } = useActiveVisits();
|
|
70
61
|
const { restrictWardAdministrationToLoginLocation } = useConfig();
|
|
71
62
|
|
|
63
|
+
const { patientEntries, isLoading } = useEligibleAdmissions();
|
|
72
64
|
const handleBedAssigmentModal = useCallback(
|
|
73
65
|
(entry) => {
|
|
74
66
|
setSelectedPatientDetails({
|
|
75
67
|
name: entry.name,
|
|
76
68
|
patientUuid: entry.patientUuid,
|
|
77
|
-
encounter: entry.
|
|
69
|
+
encounter: entry.admissionEncounterUuid,
|
|
78
70
|
locationUuid: session?.sessionLocation?.uuid,
|
|
79
71
|
locationTo: entry.locationTo,
|
|
80
72
|
locationFrom: entry.locationFrom,
|
|
@@ -108,7 +100,7 @@ const ActivePatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
108
100
|
goTo,
|
|
109
101
|
results: paginatedQueueEntries,
|
|
110
102
|
currentPage,
|
|
111
|
-
} = usePagination(
|
|
103
|
+
} = usePagination(patientEntries, currentPageSize);
|
|
112
104
|
|
|
113
105
|
const tableHeaders = useMemo(
|
|
114
106
|
() => [
|
|
@@ -119,7 +111,7 @@ const ActivePatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
119
111
|
},
|
|
120
112
|
{
|
|
121
113
|
id: 1,
|
|
122
|
-
header: t("idNumber", "
|
|
114
|
+
header: t("idNumber", "Identifier"),
|
|
123
115
|
key: "idNumber",
|
|
124
116
|
},
|
|
125
117
|
{
|
|
@@ -153,6 +145,7 @@ const ActivePatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
153
145
|
|
|
154
146
|
const tableRows = useMemo(() => {
|
|
155
147
|
return paginatedQueueEntries?.map((entry) => ({
|
|
148
|
+
id: `${entry.idNumber}`,
|
|
156
149
|
...entry,
|
|
157
150
|
actions: {
|
|
158
151
|
content: (
|
|
@@ -160,21 +153,21 @@ const ActivePatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
160
153
|
),
|
|
161
154
|
},
|
|
162
155
|
}));
|
|
163
|
-
}, [paginatedQueueEntries,
|
|
156
|
+
}, [paginatedQueueEntries, renderActionButton]);
|
|
164
157
|
|
|
165
158
|
if (isLoading) {
|
|
166
159
|
return <DataTableSkeleton role="progressbar" />;
|
|
167
160
|
}
|
|
168
161
|
|
|
169
162
|
if (
|
|
170
|
-
(!isLoading &&
|
|
163
|
+
(!isLoading && patientEntries && status === "pending") ||
|
|
171
164
|
status === "completed" ||
|
|
172
165
|
status === ""
|
|
173
166
|
) {
|
|
174
|
-
setPatientCount(
|
|
167
|
+
setPatientCount(patientEntries.length);
|
|
175
168
|
}
|
|
176
169
|
|
|
177
|
-
if (
|
|
170
|
+
if (patientEntries?.length) {
|
|
178
171
|
return (
|
|
179
172
|
<div className={styles.container}>
|
|
180
173
|
<div className={styles.headerBtnContainer}></div>
|
|
@@ -258,7 +251,7 @@ const ActivePatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
258
251
|
page={currentPage}
|
|
259
252
|
pageSize={currentPageSize}
|
|
260
253
|
pageSizes={pageSizes}
|
|
261
|
-
totalItems={
|
|
254
|
+
totalItems={patientEntries?.length}
|
|
262
255
|
className={styles.pagination}
|
|
263
256
|
onChange={({ pageSize, page }) => {
|
|
264
257
|
if (pageSize !== currentPageSize) {
|
|
@@ -291,7 +284,7 @@ const ActivePatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
291
284
|
|
|
292
285
|
return (
|
|
293
286
|
<EmptyState
|
|
294
|
-
msg={t("
|
|
287
|
+
msg={t("noPatientForAdmission", "There are no patients for admission")}
|
|
295
288
|
helper=""
|
|
296
289
|
/>
|
|
297
290
|
);
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
dayjs.extend(isToday);
|
|
17
17
|
|
|
18
18
|
export interface ActiveVisit {
|
|
19
|
-
age: string;
|
|
20
19
|
id: string;
|
|
21
20
|
idNumber: string;
|
|
22
21
|
gender: string;
|
|
@@ -91,12 +90,11 @@ export function useActiveVisits() {
|
|
|
91
90
|
) {
|
|
92
91
|
setSize((currentSize) => currentSize + 1);
|
|
93
92
|
}
|
|
94
|
-
}, [data, pageNumber]);
|
|
93
|
+
}, [data, pageNumber, setSize]);
|
|
95
94
|
|
|
96
95
|
const mapVisitProperties = (visit: Visit): ActiveVisit => {
|
|
97
96
|
// create base object
|
|
98
97
|
const activeVisits: ActiveVisit = {
|
|
99
|
-
age: visit?.patient?.person?.age,
|
|
100
98
|
id: visit.uuid,
|
|
101
99
|
idNumber: null,
|
|
102
100
|
gender: visit?.patient?.person?.gender,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import useSWR from "swr";
|
|
3
|
+
import { openmrsFetch, useConfig } from "@openmrs/esm-framework";
|
|
4
|
+
|
|
5
|
+
interface PatientAdmissionListResponse {
|
|
6
|
+
idNumber: string;
|
|
7
|
+
name: string;
|
|
8
|
+
age: number;
|
|
9
|
+
gender: string;
|
|
10
|
+
visitType: string;
|
|
11
|
+
visitStartTime: string;
|
|
12
|
+
admissionEncounterUuid: string;
|
|
13
|
+
patientUuid: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function useEligibleAdmissions() {
|
|
17
|
+
const { patientListForAdmissionUrl } = useConfig();
|
|
18
|
+
const { data, error, isLoading } = useSWR<
|
|
19
|
+
{ data: Array<PatientAdmissionListResponse> },
|
|
20
|
+
Error
|
|
21
|
+
>(patientListForAdmissionUrl ?? null, openmrsFetch);
|
|
22
|
+
|
|
23
|
+
const patientQueueEntries = useMemo(() => {
|
|
24
|
+
const rawData = data?.data ?? [];
|
|
25
|
+
|
|
26
|
+
return rawData.map((el) => ({
|
|
27
|
+
...el,
|
|
28
|
+
visitStartTime: new Date(
|
|
29
|
+
parseInt(el.visitStartTime[0]),
|
|
30
|
+
parseInt(el.visitStartTime[1]),
|
|
31
|
+
parseInt(el.visitStartTime[2]),
|
|
32
|
+
parseInt(el.visitStartTime[3]),
|
|
33
|
+
parseInt(el.visitStartTime[4])
|
|
34
|
+
).toUTCString(),
|
|
35
|
+
}));
|
|
36
|
+
}, [data?.data]);
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
patientEntries: patientQueueEntries ? patientQueueEntries : [],
|
|
40
|
+
isLoading,
|
|
41
|
+
error,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -18,6 +18,10 @@ interface VisitResponse {
|
|
|
18
18
|
totalCount: number;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// interface SQLBedAssignmentResponse {
|
|
22
|
+
|
|
23
|
+
// }
|
|
24
|
+
|
|
21
25
|
export interface BedPatientAssignment {
|
|
22
26
|
patientUuid: string;
|
|
23
27
|
age: number;
|
|
@@ -71,7 +75,7 @@ export function useActiveAdmissions() {
|
|
|
71
75
|
) {
|
|
72
76
|
setSize((currentSize) => currentSize + 1);
|
|
73
77
|
}
|
|
74
|
-
}, [data, pageNumber]);
|
|
78
|
+
}, [data, pageNumber, setSize]);
|
|
75
79
|
|
|
76
80
|
const formattedActiveVisits: any = (data: FetchResponse<VisitResponse>) => {
|
|
77
81
|
const result = data
|
|
@@ -64,7 +64,7 @@ const AdmittedPatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
64
64
|
setSelectedPatientDetails({
|
|
65
65
|
name: entry.name,
|
|
66
66
|
patientUuid: entry.patientUuid,
|
|
67
|
-
encounter: entry.
|
|
67
|
+
encounter: entry.admissionEncounterUuid,
|
|
68
68
|
locationUuid: session?.sessionLocation?.uuid,
|
|
69
69
|
locationTo: entry.locationTo,
|
|
70
70
|
locationFrom: entry.locationFrom,
|
|
@@ -91,7 +91,7 @@ const AdmittedPatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
91
91
|
// />
|
|
92
92
|
// );
|
|
93
93
|
},
|
|
94
|
-
[
|
|
94
|
+
[status]
|
|
95
95
|
);
|
|
96
96
|
|
|
97
97
|
const {
|
|
@@ -148,7 +148,7 @@ const AdmittedPatientsTable: React.FC<ActiveVisitsTableProps> = ({
|
|
|
148
148
|
),
|
|
149
149
|
},
|
|
150
150
|
}));
|
|
151
|
-
}, [paginatedQueueEntries
|
|
151
|
+
}, [paginatedQueueEntries]);
|
|
152
152
|
|
|
153
153
|
if (isLoading) {
|
|
154
154
|
return <DataTableSkeleton role="progressbar" />;
|
|
@@ -4,7 +4,6 @@ import styles from "./bed-admission-tabs-styles.scss";
|
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
import ActivePatientsTable from "./active-patients/active-patients-table.component";
|
|
6
6
|
import AdmittedPatientsList from "./admitted-patients/admitted-patients.component";
|
|
7
|
-
import DischargedPatientsList from "./discharged-patients/discharged-patients.componet";
|
|
8
7
|
import WardCard from "../ward-card/ward-card.component";
|
|
9
8
|
|
|
10
9
|
const BedAdmissionTabs: React.FC = () => {
|
|
@@ -53,7 +53,7 @@ const BedLayoutList: React.FC<BedLayoutListProps> = React.memo(
|
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
if (locationUuid ===
|
|
56
|
+
if (locationUuid === "") {
|
|
57
57
|
return (
|
|
58
58
|
<div className={styles.errorContainer}>
|
|
59
59
|
<EmptyState
|
|
@@ -63,7 +63,7 @@ const BedLayoutList: React.FC<BedLayoutListProps> = React.memo(
|
|
|
63
63
|
</div>
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
|
-
if (locationUuid !==
|
|
66
|
+
if (locationUuid !== "" && !bedData?.length) {
|
|
67
67
|
return (
|
|
68
68
|
<div className={styles.errorContainer}>
|
|
69
69
|
<EmptyState
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import React, { useMemo, useState } from "react";
|
|
2
|
+
import { useTranslation } from "react-i18next";
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
DataTable,
|
|
6
|
+
DataTableSkeleton,
|
|
7
|
+
InlineLoading,
|
|
8
|
+
Pagination,
|
|
9
|
+
Table,
|
|
10
|
+
TableBody,
|
|
11
|
+
TableCell,
|
|
12
|
+
TableContainer,
|
|
13
|
+
TableHead,
|
|
14
|
+
TableHeader,
|
|
15
|
+
TableRow,
|
|
16
|
+
Tile,
|
|
17
|
+
} from "@carbon/react";
|
|
18
|
+
import { Add, Edit, Delete } from "@carbon/react/icons";
|
|
19
|
+
import {
|
|
20
|
+
isDesktop as desktopLayout,
|
|
21
|
+
showNotification,
|
|
22
|
+
showToast,
|
|
23
|
+
useLayoutType,
|
|
24
|
+
} from "@openmrs/esm-framework";
|
|
25
|
+
import { CardHeader, ErrorState } from "@openmrs/esm-patient-common-lib";
|
|
26
|
+
import type { BedTagData } from "../../types";
|
|
27
|
+
import { deleteBedTag, useBedTag } from "../../summary/summary.resource";
|
|
28
|
+
import Header from "../../header/header.component";
|
|
29
|
+
import styles from "../../bed-administration/bed-administration-table.scss";
|
|
30
|
+
import BedTagForm from "./new-tag-form.component";
|
|
31
|
+
import EditBedTagForm from "./edit-tag-form.component";
|
|
32
|
+
import DeleteBedTag from "./delete-bed-tag.component";
|
|
33
|
+
|
|
34
|
+
const BedTagAdministrationTable: React.FC = () => {
|
|
35
|
+
const { t } = useTranslation();
|
|
36
|
+
const headerTitle = t("bedTag", "Bed Tag");
|
|
37
|
+
const layout = useLayoutType();
|
|
38
|
+
const isTablet = layout === "tablet";
|
|
39
|
+
const responsiveSize = isTablet ? "lg" : "sm";
|
|
40
|
+
const isDesktop = desktopLayout(layout);
|
|
41
|
+
const [isBedDataLoading] = useState(false);
|
|
42
|
+
const [showBedTagsModal, setAddBedTagsModal] = useState(false);
|
|
43
|
+
const [showDeleteBedTagsModal, setDeleteBedTagsModal] = useState(false);
|
|
44
|
+
const [showEditBedModal, setShowEditBedModal] = useState(false);
|
|
45
|
+
const [editData, setEditData] = useState<BedTagData>();
|
|
46
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
47
|
+
const [pageSize] = useState(10);
|
|
48
|
+
const { bedTypeData, isError, loading, validate, mutate } = useBedTag();
|
|
49
|
+
const tableHeaders = [
|
|
50
|
+
{
|
|
51
|
+
header: t("ids", "Id"),
|
|
52
|
+
key: "ids",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
header: t("name", "Name"),
|
|
56
|
+
key: "name",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
header: t("actions", "Actions"),
|
|
60
|
+
key: "actions",
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
const tableRows = useMemo(() => {
|
|
64
|
+
return bedTypeData?.map((entry) => ({
|
|
65
|
+
id: entry.uuid,
|
|
66
|
+
ids: entry.id,
|
|
67
|
+
name: entry?.name,
|
|
68
|
+
actions: (
|
|
69
|
+
<>
|
|
70
|
+
<Button
|
|
71
|
+
enterDelayMs={300}
|
|
72
|
+
renderIcon={Edit}
|
|
73
|
+
onClick={(e) => {
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
setEditData(entry);
|
|
76
|
+
setShowEditBedModal(true);
|
|
77
|
+
setAddBedTagsModal(false);
|
|
78
|
+
setDeleteBedTagsModal(false);
|
|
79
|
+
}}
|
|
80
|
+
kind={"ghost"}
|
|
81
|
+
iconDescription={t("editBedTag", "Edit Bed Tag")}
|
|
82
|
+
hasIconOnly
|
|
83
|
+
size={responsiveSize}
|
|
84
|
+
tooltipAlignment="start"
|
|
85
|
+
/>
|
|
86
|
+
<Button
|
|
87
|
+
enterDelayMs={300}
|
|
88
|
+
renderIcon={Delete}
|
|
89
|
+
onClick={(e) => {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
setEditData(entry);
|
|
92
|
+
setShowEditBedModal(false);
|
|
93
|
+
setAddBedTagsModal(false);
|
|
94
|
+
setDeleteBedTagsModal(true);
|
|
95
|
+
}}
|
|
96
|
+
kind={"ghost"}
|
|
97
|
+
iconDescription={t("deleteBedTag", "Delete Bed Tag")}
|
|
98
|
+
hasIconOnly
|
|
99
|
+
size={responsiveSize}
|
|
100
|
+
tooltipAlignment="start"
|
|
101
|
+
/>
|
|
102
|
+
</>
|
|
103
|
+
),
|
|
104
|
+
}));
|
|
105
|
+
}, [responsiveSize, bedTypeData, t]);
|
|
106
|
+
|
|
107
|
+
if (isBedDataLoading || loading) {
|
|
108
|
+
return (
|
|
109
|
+
<>
|
|
110
|
+
<Header route="Bed Tag" />
|
|
111
|
+
<div className={styles.widgetCard}>
|
|
112
|
+
<DataTableSkeleton role="progressbar" compact={isDesktop} zebra />
|
|
113
|
+
</div>
|
|
114
|
+
</>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (isError) {
|
|
118
|
+
return (
|
|
119
|
+
<>
|
|
120
|
+
<Header route="Bed Tag" />
|
|
121
|
+
<div className={styles.widgetCard}>
|
|
122
|
+
<ErrorState error={isError} headerTitle={headerTitle} />
|
|
123
|
+
</div>
|
|
124
|
+
</>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return (
|
|
128
|
+
<>
|
|
129
|
+
<Header route="Bed Tag" />
|
|
130
|
+
|
|
131
|
+
<div className={styles.widgetCard}>
|
|
132
|
+
{showBedTagsModal ? (
|
|
133
|
+
<BedTagForm
|
|
134
|
+
onModalChange={setAddBedTagsModal}
|
|
135
|
+
showModal={showBedTagsModal}
|
|
136
|
+
mutate={mutate}
|
|
137
|
+
/>
|
|
138
|
+
) : null}
|
|
139
|
+
{showEditBedModal ? (
|
|
140
|
+
<EditBedTagForm
|
|
141
|
+
onModalChange={setShowEditBedModal}
|
|
142
|
+
showModal={showEditBedModal}
|
|
143
|
+
editData={editData}
|
|
144
|
+
mutate={mutate}
|
|
145
|
+
/>
|
|
146
|
+
) : null}
|
|
147
|
+
{showDeleteBedTagsModal ? (
|
|
148
|
+
<DeleteBedTag
|
|
149
|
+
onModalChange={setDeleteBedTagsModal}
|
|
150
|
+
showModal={showDeleteBedTagsModal}
|
|
151
|
+
editData={editData}
|
|
152
|
+
mutate={mutate}
|
|
153
|
+
/>
|
|
154
|
+
) : null}
|
|
155
|
+
<CardHeader title={headerTitle}>
|
|
156
|
+
<span className={styles.backgroundDataFetchingIndicator}>
|
|
157
|
+
<span>{validate ? <InlineLoading /> : null}</span>
|
|
158
|
+
</span>
|
|
159
|
+
{bedTypeData?.length ? (
|
|
160
|
+
<Button
|
|
161
|
+
kind="ghost"
|
|
162
|
+
renderIcon={(props) => <Add size={16} {...props} />}
|
|
163
|
+
onClick={() => setAddBedTagsModal(true)}
|
|
164
|
+
>
|
|
165
|
+
{t("addBedTag", "Add Bed Tag")}
|
|
166
|
+
</Button>
|
|
167
|
+
) : null}
|
|
168
|
+
</CardHeader>
|
|
169
|
+
<DataTable
|
|
170
|
+
rows={tableRows}
|
|
171
|
+
headers={tableHeaders}
|
|
172
|
+
isSortable
|
|
173
|
+
size={isTablet ? "lg" : "sm"}
|
|
174
|
+
useZebraStyles
|
|
175
|
+
>
|
|
176
|
+
{({ rows, headers, getTableProps }) => (
|
|
177
|
+
<TableContainer>
|
|
178
|
+
<Table {...getTableProps()}>
|
|
179
|
+
<TableHead>
|
|
180
|
+
<TableRow>
|
|
181
|
+
{headers.map((header) => (
|
|
182
|
+
<TableHeader>
|
|
183
|
+
{header.header?.content ?? header.header}
|
|
184
|
+
</TableHeader>
|
|
185
|
+
))}
|
|
186
|
+
</TableRow>
|
|
187
|
+
</TableHead>
|
|
188
|
+
<TableBody>
|
|
189
|
+
{rows.map((row) => (
|
|
190
|
+
<TableRow key={row.id}>
|
|
191
|
+
{row.cells.map((cell) => (
|
|
192
|
+
<TableCell key={cell.id}>
|
|
193
|
+
{cell.value?.content ?? cell.value}
|
|
194
|
+
</TableCell>
|
|
195
|
+
))}
|
|
196
|
+
</TableRow>
|
|
197
|
+
))}
|
|
198
|
+
</TableBody>
|
|
199
|
+
</Table>
|
|
200
|
+
{rows.length === 0 ? (
|
|
201
|
+
<div className={styles.tileContainer}>
|
|
202
|
+
<Tile className={styles.tile}>
|
|
203
|
+
<div className={styles.tileContent}>
|
|
204
|
+
<p className={styles.content}>
|
|
205
|
+
{t("No data", "No data to display")}
|
|
206
|
+
</p>
|
|
207
|
+
<p className={styles.helper}>
|
|
208
|
+
{t("checkFilters", "Check the filters above")}
|
|
209
|
+
</p>
|
|
210
|
+
</div>
|
|
211
|
+
<p className={styles.separator}>{t("or", "or")}</p>
|
|
212
|
+
<Button
|
|
213
|
+
kind="ghost"
|
|
214
|
+
size="sm"
|
|
215
|
+
renderIcon={(props) => <Add size={16} {...props} />}
|
|
216
|
+
onClick={() => setAddBedTagsModal(true)}
|
|
217
|
+
>
|
|
218
|
+
{t("bedTag", "Add Bed Tag")}
|
|
219
|
+
</Button>
|
|
220
|
+
</Tile>
|
|
221
|
+
</div>
|
|
222
|
+
) : null}
|
|
223
|
+
<Pagination
|
|
224
|
+
page={currentPage}
|
|
225
|
+
pageSize={pageSize}
|
|
226
|
+
pageSizes={[10, 20, 30, 40, 50]}
|
|
227
|
+
totalItems={bedTypeData.length}
|
|
228
|
+
onChange={({ page, pageSize }) => {
|
|
229
|
+
setCurrentPage(page);
|
|
230
|
+
pageSize(pageSize);
|
|
231
|
+
}}
|
|
232
|
+
/>
|
|
233
|
+
</TableContainer>
|
|
234
|
+
)}
|
|
235
|
+
</DataTable>
|
|
236
|
+
</div>
|
|
237
|
+
</>
|
|
238
|
+
);
|
|
239
|
+
};
|
|
240
|
+
export default BedTagAdministrationTable;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { useForm, Controller } from "react-hook-form";
|
|
4
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
5
|
+
import {
|
|
6
|
+
Button,
|
|
7
|
+
ComposedModal,
|
|
8
|
+
Form,
|
|
9
|
+
FormGroup,
|
|
10
|
+
ModalBody,
|
|
11
|
+
ModalFooter,
|
|
12
|
+
ModalHeader,
|
|
13
|
+
Stack,
|
|
14
|
+
TextInput,
|
|
15
|
+
InlineNotification,
|
|
16
|
+
} from "@carbon/react";
|
|
17
|
+
import { useTranslation } from "react-i18next";
|
|
18
|
+
import { Location } from "@openmrs/esm-framework";
|
|
19
|
+
import type { BedTagData } from "../../types";
|
|
20
|
+
|
|
21
|
+
const BedTagAdministrationSchema = z.object({
|
|
22
|
+
name: z
|
|
23
|
+
.string()
|
|
24
|
+
.max(255)
|
|
25
|
+
.refine(
|
|
26
|
+
(value) => {
|
|
27
|
+
return (
|
|
28
|
+
typeof value === "string" &&
|
|
29
|
+
value.trim().length > 0 &&
|
|
30
|
+
!/\d/.test(value)
|
|
31
|
+
);
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
message: "Bed tag must not contain numbers",
|
|
35
|
+
}
|
|
36
|
+
),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
interface BedTagAdministrationFormProps {
|
|
40
|
+
showModal: boolean;
|
|
41
|
+
onModalChange: (showModal: boolean) => void;
|
|
42
|
+
availableBedTypes: Array<BedTagData>;
|
|
43
|
+
allLocations: Location[];
|
|
44
|
+
handleCreateQuestion?: (formData: BedTagData) => void;
|
|
45
|
+
handleDeleteBedTag?: () => void;
|
|
46
|
+
headerTitle: string;
|
|
47
|
+
initialData: BedTagData;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface ErrorType {
|
|
51
|
+
message: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const BedTagsAdministrationForm: React.FC<BedTagAdministrationFormProps> = ({
|
|
55
|
+
showModal,
|
|
56
|
+
onModalChange,
|
|
57
|
+
handleCreateQuestion,
|
|
58
|
+
headerTitle,
|
|
59
|
+
initialData,
|
|
60
|
+
}) => {
|
|
61
|
+
const { t } = useTranslation();
|
|
62
|
+
|
|
63
|
+
const [showErrorNotification, setShowErrorNotification] = useState(false);
|
|
64
|
+
const [formStateError, setFormStateError] = useState("");
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
handleSubmit,
|
|
68
|
+
control,
|
|
69
|
+
formState: { isDirty },
|
|
70
|
+
} = useForm<BedTagData>({
|
|
71
|
+
mode: "all",
|
|
72
|
+
resolver: zodResolver(BedTagAdministrationSchema),
|
|
73
|
+
defaultValues: {
|
|
74
|
+
name: initialData.name || "",
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const onSubmit = (formData: BedTagData) => {
|
|
79
|
+
const result = BedTagAdministrationSchema.safeParse(formData);
|
|
80
|
+
if (result.success) {
|
|
81
|
+
setShowErrorNotification(false);
|
|
82
|
+
handleCreateQuestion(formData);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const onError = (error: { [key: string]: ErrorType }) => {
|
|
87
|
+
setFormStateError(Object.entries(error)[0][1].message);
|
|
88
|
+
setShowErrorNotification(true);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<ComposedModal
|
|
93
|
+
open={showModal}
|
|
94
|
+
onClose={() => onModalChange(false)}
|
|
95
|
+
preventCloseOnClickOutside
|
|
96
|
+
>
|
|
97
|
+
<ModalHeader title={headerTitle} />
|
|
98
|
+
<Form onSubmit={handleSubmit(onSubmit, onError)}>
|
|
99
|
+
<ModalBody hasScrollingContent>
|
|
100
|
+
<Stack gap={3}>
|
|
101
|
+
<FormGroup legendText={""}>
|
|
102
|
+
<Controller
|
|
103
|
+
name="name"
|
|
104
|
+
control={control}
|
|
105
|
+
rules={{ required: true }}
|
|
106
|
+
render={({ field, fieldState }) => (
|
|
107
|
+
<>
|
|
108
|
+
<TextInput
|
|
109
|
+
id="bedTag"
|
|
110
|
+
labelText={t("bedTag", "Bed Tag Name")}
|
|
111
|
+
placeholder={t("bedTagPlaceholder", "")}
|
|
112
|
+
invalidText={fieldState.error?.message}
|
|
113
|
+
{...field}
|
|
114
|
+
/>
|
|
115
|
+
</>
|
|
116
|
+
)}
|
|
117
|
+
/>
|
|
118
|
+
</FormGroup>
|
|
119
|
+
|
|
120
|
+
{showErrorNotification && (
|
|
121
|
+
<InlineNotification
|
|
122
|
+
lowContrast
|
|
123
|
+
title={t("error", "Error")}
|
|
124
|
+
style={{ minWidth: "100%", margin: "0rem", padding: "0rem" }}
|
|
125
|
+
role="alert"
|
|
126
|
+
kind="error"
|
|
127
|
+
subtitle={t("pleaseFillField", formStateError) + "."}
|
|
128
|
+
onClose={() => setShowErrorNotification(false)}
|
|
129
|
+
/>
|
|
130
|
+
)}
|
|
131
|
+
</Stack>
|
|
132
|
+
</ModalBody>
|
|
133
|
+
<ModalFooter>
|
|
134
|
+
<Button onClick={() => onModalChange(false)} kind="secondary">
|
|
135
|
+
{t("cancel", "Cancel")}
|
|
136
|
+
</Button>
|
|
137
|
+
<Button disabled={!isDirty} type="submit">
|
|
138
|
+
<span>{t("save", "Save")}</span>
|
|
139
|
+
</Button>
|
|
140
|
+
</ModalFooter>
|
|
141
|
+
</Form>
|
|
142
|
+
</ComposedModal>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export default BedTagsAdministrationForm;
|