@kenyaemr/esm-bed-management-app 1.0.1-pre.11

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 (137) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc +37 -0
  4. package/.husky/pre-commit +4 -0
  5. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  6. package/.idea/modules.xml +8 -0
  7. package/.idea/vcs.xml +6 -0
  8. package/.prettierignore +14 -0
  9. package/.turbo.json +18 -0
  10. package/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs +541 -0
  11. package/.yarn/plugins/@yarnpkg/plugin-version.cjs +550 -0
  12. package/.yarn/versions/3d353a50.yml +0 -0
  13. package/LICENSE +373 -0
  14. package/README.md +40 -0
  15. package/dist/207.js +1 -0
  16. package/dist/207.js.map +1 -0
  17. package/dist/26.js +2 -0
  18. package/dist/26.js.LICENSE.txt +32 -0
  19. package/dist/26.js.map +1 -0
  20. package/dist/283.js +1 -0
  21. package/dist/283.js.map +1 -0
  22. package/dist/294.js +2 -0
  23. package/dist/294.js.LICENSE.txt +9 -0
  24. package/dist/294.js.map +1 -0
  25. package/dist/330.js +2 -0
  26. package/dist/330.js.LICENSE.txt +44 -0
  27. package/dist/330.js.map +1 -0
  28. package/dist/404.js +1 -0
  29. package/dist/404.js.map +1 -0
  30. package/dist/455.js +2 -0
  31. package/dist/455.js.LICENSE.txt +9 -0
  32. package/dist/455.js.map +1 -0
  33. package/dist/558.js +2 -0
  34. package/dist/558.js.LICENSE.txt +14 -0
  35. package/dist/558.js.map +1 -0
  36. package/dist/574.js +1 -0
  37. package/dist/629.js +1 -0
  38. package/dist/629.js.map +1 -0
  39. package/dist/637.js +1 -0
  40. package/dist/637.js.map +1 -0
  41. package/dist/707.js +1 -0
  42. package/dist/707.js.map +1 -0
  43. package/dist/800.js +2 -0
  44. package/dist/800.js.LICENSE.txt +3 -0
  45. package/dist/800.js.map +1 -0
  46. package/dist/850.js +1 -0
  47. package/dist/850.js.map +1 -0
  48. package/dist/884.js +1 -0
  49. package/dist/884.js.map +1 -0
  50. package/dist/933.js +1 -0
  51. package/dist/933.js.map +1 -0
  52. package/dist/esm-kenyaemr-bed-management-app.js +1 -0
  53. package/dist/esm-kenyaemr-bed-management-app.js.buildmanifest.json +506 -0
  54. package/dist/esm-kenyaemr-bed-management-app.js.map +1 -0
  55. package/dist/main.js +1 -0
  56. package/dist/main.js.map +1 -0
  57. package/dist/routes.json +1 -0
  58. package/i18next-parser.config.js +89 -0
  59. package/jest.config.js +0 -0
  60. package/package.json +112 -0
  61. package/src/__mocks__/react-i18next.js +55 -0
  62. package/src/admin-card-link.component.tsx +27 -0
  63. package/src/assets/landing-page.png +0 -0
  64. package/src/assets/logo.svg +1 -0
  65. package/src/bed-administration/bed-administration-form.component.tsx +326 -0
  66. package/src/bed-administration/bed-administration-form.scss +0 -0
  67. package/src/bed-administration/bed-administration-table.component.tsx +317 -0
  68. package/src/bed-administration/bed-administration-table.scss +112 -0
  69. package/src/bed-administration/bed-administration-types.ts +20 -0
  70. package/src/bed-administration/bed-administration.resource.ts +59 -0
  71. package/src/bed-administration/edit-bed-form.component.tsx +100 -0
  72. package/src/bed-administration/new-bed-form.component.tsx +112 -0
  73. package/src/bed-admission/active-patients/active-patients-table.component.tsx +299 -0
  74. package/src/bed-admission/active-patients/active-visits.resource.ts +171 -0
  75. package/src/bed-admission/active-patients/admission-action-button-styles.scss +0 -0
  76. package/src/bed-admission/active-patients/admission-action-button.component.tsx +26 -0
  77. package/src/bed-admission/active-patients/index.tsx +15 -0
  78. package/src/bed-admission/active-patients/patient-queues.resource.ts +136 -0
  79. package/src/bed-admission/active-patients/styles.scss +284 -0
  80. package/src/bed-admission/active-patients/view-action-menu.component.tsx +33 -0
  81. package/src/bed-admission/admitted-patients/active-admissions.resource.ts +125 -0
  82. package/src/bed-admission/admitted-patients/admitted-patients-table.component.tsx +280 -0
  83. package/src/bed-admission/admitted-patients/admitted-patients.component.tsx +22 -0
  84. package/src/bed-admission/admitted-patients/location-combo-box.component.tsx +55 -0
  85. package/src/bed-admission/admitted-patients/styles.scss +284 -0
  86. package/src/bed-admission/bed-admission-tabs-styles.scss +30 -0
  87. package/src/bed-admission/bed-admission-tabs.component.tsx +69 -0
  88. package/src/bed-admission/bed-admission.component.tsx +15 -0
  89. package/src/bed-admission/bed-admission.resource.ts +52 -0
  90. package/src/bed-admission/bed-layout/bed-layout-list.component.tsx +101 -0
  91. package/src/bed-admission/bed-layout/bed-layout.component.tsx +64 -0
  92. package/src/bed-admission/bed-layout/bed-layout.scss +118 -0
  93. package/src/bed-admission/bed-layout/min-bed-layout.component.tsx +26 -0
  94. package/src/bed-admission/bed-tag/bed-tag-administration-table.component.tsx +217 -0
  95. package/src/bed-admission/bed-tag/bed-tags-admin-form.component.tsx +131 -0
  96. package/src/bed-admission/bed-tag/edit-tag-form.component.tsx +80 -0
  97. package/src/bed-admission/bed-tag/new-tag-form.component.tsx +83 -0
  98. package/src/bed-admission/bed-type/bed-type-admin-form.component.tsx +173 -0
  99. package/src/bed-admission/bed-type/bed-type-administration-table.component.tsx +222 -0
  100. package/src/bed-admission/bed-type/edit-bed-type.component.tsx +80 -0
  101. package/src/bed-admission/bed-type/new-bed-type-form.component.tsx +87 -0
  102. package/src/bed-admission/createDashboardLink.tsx +47 -0
  103. package/src/bed-admission/discharged-patients/discharged-patients.componet.tsx +19 -0
  104. package/src/bed-admission/helpers/functions.ts +102 -0
  105. package/src/bed-admission/types.ts +133 -0
  106. package/src/config-schema.ts +31 -0
  107. package/src/declarations.d.ts +7 -0
  108. package/src/empty-state/empty-state.component.tsx +69 -0
  109. package/src/empty-state/empty-state.scss +62 -0
  110. package/src/header/header.component.tsx +51 -0
  111. package/src/header/header.scss +72 -0
  112. package/src/header/illustration.component.tsx +13 -0
  113. package/src/home.component.tsx +15 -0
  114. package/src/home.scss +5 -0
  115. package/src/index.ts +78 -0
  116. package/src/left-panel/left-panel.component.tsx +33 -0
  117. package/src/left-panel/left-panel.scss +41 -0
  118. package/src/left-panel-link.component.tsx +49 -0
  119. package/src/root.component.tsx +39 -0
  120. package/src/root.scss +11 -0
  121. package/src/routes.json +56 -0
  122. package/src/setup-tests.ts +1 -0
  123. package/src/summary/summary.component.tsx +74 -0
  124. package/src/summary/summary.resource.ts +211 -0
  125. package/src/summary/summary.scss +72 -0
  126. package/src/types.ts +163 -0
  127. package/src/ward-card/ward-card.component.tsx +41 -0
  128. package/src/ward-card/ward-card.scss +51 -0
  129. package/src/ward-with-beds/ward-with-beds.component.tsx +186 -0
  130. package/src/ward-with-beds/ward-with-beds.scss +27 -0
  131. package/src/workspace/allocate-bed-workspace.component.tsx +188 -0
  132. package/src/workspace/allocate-bed.scss +124 -0
  133. package/src/workspace/overlay.component.tsx +55 -0
  134. package/src/workspace/overlay.scss +96 -0
  135. package/translations/en.json +7 -0
  136. package/tsconfig.json +23 -0
  137. package/webpack.config.js +1 -0
@@ -0,0 +1,317 @@
1
+ import React, { useEffect, useMemo, useState } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import {
4
+ Button,
5
+ DataTable,
6
+ DataTableSkeleton,
7
+ Dropdown,
8
+ InlineLoading,
9
+ Pagination,
10
+ Table,
11
+ TableBody,
12
+ TableCell,
13
+ TableContainer,
14
+ TableHead,
15
+ TableHeader,
16
+ TableRow,
17
+ Tag,
18
+ Tile,
19
+ } from "@carbon/react";
20
+ import { Add, Edit } from "@carbon/react/icons";
21
+ import {
22
+ isDesktop as desktopLayout,
23
+ useConfig,
24
+ useLayoutType,
25
+ usePagination,
26
+ } from "@openmrs/esm-framework";
27
+ import { CardHeader, ErrorState } from "@openmrs/esm-patient-common-lib";
28
+ import type { InitialData, Location } from "../types";
29
+ import { findBedByLocation, useWards } from "../summary/summary.resource";
30
+ import EditBedForm from "./edit-bed-form.component";
31
+ import Header from "../header/header.component";
32
+ import NewBedForm from "./new-bed-form.component";
33
+ import styles from "./bed-administration-table.scss";
34
+
35
+ const BedAdministrationTable: React.FC = () => {
36
+ const { t } = useTranslation();
37
+ const headerTitle = t("wardAllocation", "Ward Allocation");
38
+ const layout = useLayoutType();
39
+ const isTablet = layout === "tablet";
40
+ const responsiveSize = isTablet ? "lg" : "sm";
41
+ const isDesktop = desktopLayout(layout);
42
+ const { admissionLocationTagUuid } = useConfig();
43
+
44
+ const [wardsGroupedByLocations, setWardsGroupedByLocation] = useState<
45
+ Array<Location>
46
+ >([]);
47
+ const [isBedDataLoading, setIsBedDataLoading] = useState(false);
48
+ const [showAddBedModal, setShowAddBedModal] = useState(false);
49
+ const [showEditBedModal, setShowEditBedModal] = useState(false);
50
+ const [editData, setEditData] = useState<InitialData>();
51
+ const [filterOption, setFilterOption] = useState("ALL");
52
+
53
+ function CustomTag({ condition }: { condition: boolean }) {
54
+ const { t } = useTranslation();
55
+
56
+ if (condition) {
57
+ return (
58
+ <Tag type="green" size="md">
59
+ {t("yes", "Yes")}
60
+ </Tag>
61
+ );
62
+ }
63
+
64
+ return (
65
+ <Tag type="red" size="md">
66
+ {t("no", "No")}
67
+ </Tag>
68
+ );
69
+ }
70
+
71
+ const handleBedStatusChange = ({ selectedItem }: { selectedItem: string }) =>
72
+ setFilterOption(selectedItem.trim().toUpperCase());
73
+
74
+ const bedsMappedToLocation = wardsGroupedByLocations?.length
75
+ ? [].concat(...wardsGroupedByLocations)
76
+ : [];
77
+
78
+ const { data, isLoading, error, isValidating, mutate } = useWards(
79
+ admissionLocationTagUuid
80
+ );
81
+
82
+ const [currentPageSize, setPageSize] = useState(10);
83
+ const pageSizes = [10, 20, 30, 40, 50];
84
+ const { results, currentPage, totalPages, goTo } = usePagination(
85
+ filterOption === "ALL"
86
+ ? bedsMappedToLocation
87
+ : bedsMappedToLocation.filter((bed) => bed.status === filterOption) ?? [],
88
+ currentPageSize
89
+ );
90
+
91
+ useEffect(() => {
92
+ if (!isLoading && data) {
93
+ setIsBedDataLoading(true);
94
+ const fetchData = async () => {
95
+ const promises = data.data.results.map(async (ward) => {
96
+ const bedLocations = await findBedByLocation(ward.uuid);
97
+ if (bedLocations.data.results.length) {
98
+ return bedLocations.data.results.map((bed) => ({
99
+ ...bed,
100
+ location: ward,
101
+ }));
102
+ }
103
+ return null;
104
+ });
105
+
106
+ const updatedWards = (await Promise.all(promises)).filter(Boolean);
107
+ setWardsGroupedByLocation(updatedWards);
108
+ setIsBedDataLoading(false);
109
+ };
110
+ fetchData().finally(() => setIsBedDataLoading(false));
111
+ }
112
+ }, [data, isLoading, wardsGroupedByLocations.length]);
113
+
114
+ const tableHeaders = [
115
+ {
116
+ key: "bedNumber",
117
+ header: t("bedId", "Bed ID"),
118
+ },
119
+ {
120
+ key: "location",
121
+ header: t("location", "Location"),
122
+ },
123
+ {
124
+ key: "occupancyStatus",
125
+ header: t("occupancyStatus", "Occupied"),
126
+ },
127
+ {
128
+ key: "allocationStatus",
129
+ header: t("allocationStatus", "Allocated"),
130
+ },
131
+ {
132
+ key: "actions",
133
+ header: t("actions", "Actions"),
134
+ },
135
+ ];
136
+
137
+ const tableRows = useMemo(() => {
138
+ return results.map((ward) => ({
139
+ id: ward.uuid,
140
+ bedNumber: ward.bedNumber,
141
+ location: ward.location.display,
142
+ occupancyStatus: <CustomTag condition={ward?.status === "OCCUPIED"} />,
143
+ allocationStatus: <CustomTag condition={ward.location?.uuid} />,
144
+ actions: (
145
+ <>
146
+ <Button
147
+ enterDelayMs={300}
148
+ renderIcon={Edit}
149
+ onClick={(e) => {
150
+ e.preventDefault();
151
+ setEditData(ward);
152
+ setShowEditBedModal(true);
153
+ setShowAddBedModal(false);
154
+ }}
155
+ kind={"ghost"}
156
+ iconDescription={t("editBed", "Edit Bed")}
157
+ hasIconOnly
158
+ size={responsiveSize}
159
+ tooltipAlignment="start"
160
+ />
161
+ </>
162
+ ),
163
+ }));
164
+ }, [responsiveSize, results, t]);
165
+
166
+ if ((isBedDataLoading || isLoading) && !wardsGroupedByLocations.length) {
167
+ return (
168
+ <>
169
+ <Header route="Ward Allocation" />
170
+ <div className={styles.widgetCard}>
171
+ <DataTableSkeleton role="progressbar" compact={isDesktop} zebra />
172
+ </div>
173
+ </>
174
+ );
175
+ }
176
+
177
+ if (error) {
178
+ return (
179
+ <>
180
+ <Header route="Ward Allocation" />
181
+ <div className={styles.widgetCard}>
182
+ <ErrorState error={error} headerTitle={headerTitle} />
183
+ </div>
184
+ </>
185
+ );
186
+ }
187
+
188
+ return (
189
+ <>
190
+ <Header route="Ward Allocation" />
191
+ <div className={styles.flexContainer}>
192
+ {results?.length ? (
193
+ <div className={styles.filterContainer}>
194
+ <Dropdown
195
+ id="occupancyStatus"
196
+ initialSelectedItem={"All"}
197
+ label=""
198
+ titleText={
199
+ t("filterByOccupancyStatus", "Filter by occupancy status") + ":"
200
+ }
201
+ type="inline"
202
+ items={["All", "Available", "Occupied"]}
203
+ onChange={handleBedStatusChange}
204
+ />
205
+ </div>
206
+ ) : null}
207
+ </div>
208
+ <div className={styles.widgetCard}>
209
+ {showAddBedModal ? (
210
+ <NewBedForm
211
+ onModalChange={setShowAddBedModal}
212
+ showModal={showAddBedModal}
213
+ mutate={mutate}
214
+ />
215
+ ) : null}
216
+ {showEditBedModal ? (
217
+ <EditBedForm
218
+ onModalChange={setShowEditBedModal}
219
+ showModal={showEditBedModal}
220
+ editData={editData}
221
+ mutate={mutate}
222
+ />
223
+ ) : null}
224
+ <CardHeader title={headerTitle}>
225
+ <span className={styles.backgroundDataFetchingIndicator}>
226
+ <span>{isValidating ? <InlineLoading /> : null}</span>
227
+ </span>
228
+ {results?.length ? (
229
+ <Button
230
+ kind="ghost"
231
+ renderIcon={(props) => <Add size={16} {...props} />}
232
+ onClick={() => setShowAddBedModal(true)}
233
+ >
234
+ {t("addBed", "Add bed")}
235
+ </Button>
236
+ ) : null}
237
+ </CardHeader>
238
+ <DataTable
239
+ rows={tableRows}
240
+ headers={tableHeaders}
241
+ isSortable
242
+ size={isTablet ? "lg" : "sm"}
243
+ useZebraStyles
244
+ >
245
+ {({ rows, headers, getTableProps }) => (
246
+ <TableContainer>
247
+ <Table {...getTableProps()}>
248
+ <TableHead>
249
+ <TableRow>
250
+ {headers.map((header) => (
251
+ <TableHeader>
252
+ {header.header?.content ?? header.header}
253
+ </TableHeader>
254
+ ))}
255
+ </TableRow>
256
+ </TableHead>
257
+ <TableBody>
258
+ {rows.map((row) => (
259
+ <TableRow key={row.id}>
260
+ {row.cells.map((cell) => (
261
+ <TableCell key={cell.id}>
262
+ {cell.value?.content ?? cell.value}
263
+ </TableCell>
264
+ ))}
265
+ </TableRow>
266
+ ))}
267
+ </TableBody>
268
+ </Table>
269
+ {rows.length === 0 ? (
270
+ <div className={styles.tileContainer}>
271
+ <Tile className={styles.tile}>
272
+ <div className={styles.tileContent}>
273
+ <p className={styles.content}>
274
+ {t("No data", "No data to display")}
275
+ </p>
276
+ <p className={styles.helper}>
277
+ {t("checkFilters", "Check the filters above")}
278
+ </p>
279
+ </div>
280
+ <p className={styles.separator}>{t("or", "or")}</p>
281
+ <Button
282
+ kind="ghost"
283
+ size="sm"
284
+ renderIcon={(props) => <Add size={16} {...props} />}
285
+ onClick={() => setShowAddBedModal(true)}
286
+ >
287
+ {t("addBed", "Add bed")}
288
+ </Button>
289
+ </Tile>
290
+ </div>
291
+ ) : null}
292
+ <Pagination
293
+ backwardText="Previous page"
294
+ forwardText="Next page"
295
+ page={currentPage}
296
+ pageNumberText="Page Number"
297
+ pageSize={totalPages}
298
+ pageSizes={pageSizes?.length > 0 ? pageSizes : [10]}
299
+ totalItems={bedsMappedToLocation.length ?? 0}
300
+ onChange={({ pageSize, page }) => {
301
+ if (pageSize !== currentPageSize) {
302
+ setPageSize(pageSize);
303
+ }
304
+ if (page !== currentPage) {
305
+ goTo(page);
306
+ }
307
+ }}
308
+ />
309
+ </TableContainer>
310
+ )}
311
+ </DataTable>
312
+ </div>
313
+ </>
314
+ );
315
+ };
316
+
317
+ export default BedAdministrationTable;
@@ -0,0 +1,112 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/type';
3
+
4
+ .widgetCard {
5
+ border: 1px solid colors.$gray-20;
6
+ margin: 1.5rem;
7
+
8
+ :global(.cds--modal-content) {
9
+ margin-bottom: unset;
10
+ }
11
+
12
+ @media (min-width: 66rem) {
13
+ :global(.cds--modal-container) {
14
+ max-height: 100%;
15
+ width: 60%;
16
+ }
17
+ }
18
+
19
+ @media (min-width: 42rem) {
20
+ :global(.cds--modal-container) {
21
+ max-height: 100%;
22
+ }
23
+
24
+ }
25
+ }
26
+
27
+ .flexContainer {
28
+ display: flex;
29
+ justify-content: space-between;
30
+ padding: 0 1rem;
31
+ margin-top: 2rem;
32
+ margin-left: 0.5rem;
33
+ }
34
+
35
+ .filterContainer {
36
+ flex: 1;
37
+
38
+ :global(.cds--dropdown__wrapper--inline) {
39
+ gap: 0;
40
+ }
41
+
42
+ :global(.cds--list-box__menu-icon) {
43
+ height: 1rem;
44
+ }
45
+ }
46
+
47
+ .backgroundDataFetchingIndicator {
48
+ align-items: center;
49
+ display: flex;
50
+ justify-content: end;
51
+ }
52
+
53
+ .tileContainer {
54
+ background-color: colors.$white-0;
55
+ border-top: 1px solid colors.$gray-20;
56
+ padding: 3rem 0;
57
+ }
58
+
59
+ .tile {
60
+ margin: auto;
61
+ width: fit-content;
62
+ display: flex;
63
+ flex-direction: column;
64
+ align-items: center;
65
+ }
66
+
67
+ .tileContent {
68
+ display: flex;
69
+ flex-direction: column;
70
+ align-items: center;
71
+ }
72
+
73
+ .content {
74
+ @include type.type-style('heading-compact-02');
75
+ color: colors.$gray-70;
76
+ margin-bottom: 0.5rem;
77
+ }
78
+
79
+ .helper {
80
+ @include type.type-style('body-compact-01');
81
+ color: colors.$gray-70;
82
+ }
83
+
84
+ .separator {
85
+ @include type.type-style('body-compact-02');
86
+ color: colors.$gray-70;
87
+ width: 80%;
88
+ margin: 1.5rem auto;
89
+ overflow: hidden;
90
+ text-align: center;
91
+
92
+ &::before,
93
+ &::after {
94
+ background-color: colors.$gray-40;
95
+ content: '';
96
+ display: inline-block;
97
+ height: 1px;
98
+ position: relative;
99
+ vertical-align: middle;
100
+ width: 50%;
101
+ }
102
+
103
+ &::before {
104
+ right: 0.5rem;
105
+ margin-left: -50%;
106
+ }
107
+
108
+ &::after {
109
+ left: 0.5rem;
110
+ margin-right: -50%;
111
+ }
112
+ }
@@ -0,0 +1,20 @@
1
+ export interface BedAdministrationData {
2
+ bedId: string;
3
+ description: string;
4
+ bedRow: string;
5
+ bedColumn: string;
6
+ location: {
7
+ display: string;
8
+ uuid: string;
9
+ };
10
+ occupancyStatus: string;
11
+ bedType: string;
12
+ }
13
+ export interface BedTypeDataAdministration {
14
+ name: string;
15
+ displayName: string;
16
+ description: string;
17
+ }
18
+ export interface BedTagDataAdministration {
19
+ name: string;
20
+ }
@@ -0,0 +1,59 @@
1
+ import { useMemo } from "react";
2
+ import useSWR from "swr";
3
+ import { FetchResponse, openmrsFetch } from "@openmrs/esm-framework";
4
+
5
+ interface BedForm {
6
+ bedNumber: string;
7
+ bedType: string;
8
+ row: number;
9
+ column: number;
10
+ status: string;
11
+ locationUuid: string;
12
+ }
13
+
14
+ export async function saveBed({ bedPayload }): Promise<FetchResponse<BedForm>> {
15
+ const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bed`, {
16
+ method: "POST",
17
+ headers: { "Content-Type": "application/json" },
18
+ body: bedPayload,
19
+ });
20
+ return response;
21
+ }
22
+
23
+ export function useBedType() {
24
+ const locationsUrl = `/ws/rest/v1/bedtype`;
25
+ const { data, error, isLoading } = useSWR<{ data }>(
26
+ locationsUrl,
27
+ openmrsFetch
28
+ );
29
+
30
+ const bedTypes = useMemo(() => {
31
+ const rawData = data?.data?.results ?? [];
32
+ const uniqueBedTypes = [];
33
+
34
+ rawData.forEach((response) => {
35
+ if (!uniqueBedTypes.some((bedType) => bedType.name === response.name)) {
36
+ uniqueBedTypes.push(response);
37
+ }
38
+ });
39
+
40
+ return uniqueBedTypes;
41
+ }, [data?.data?.results]);
42
+
43
+ return { bedTypes: bedTypes ? bedTypes : [], isLoading, error };
44
+ }
45
+
46
+ export async function editBed({
47
+ bedPayload,
48
+ bedId,
49
+ }): Promise<FetchResponse<BedForm>> {
50
+ const response: FetchResponse = await openmrsFetch(
51
+ `/ws/rest/v1/bed/${bedId}`,
52
+ {
53
+ method: "POST",
54
+ headers: { "Content-Type": "application/json" },
55
+ body: bedPayload,
56
+ }
57
+ );
58
+ return response;
59
+ }
@@ -0,0 +1,100 @@
1
+ import React, { useCallback } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { showToast, showNotification, useConfig } from "@openmrs/esm-framework";
4
+
5
+ import type { InitialData, Mutator } from "../types";
6
+ import { useBedType, editBed } from "./bed-administration.resource";
7
+ import BedAdministrationForm from "./bed-administration-form.component";
8
+ import { BedAdministrationData } from "./bed-administration-types";
9
+ import { useLocationsByTag } from "../summary/summary.resource";
10
+
11
+ interface EditBedFormProps {
12
+ showModal: boolean;
13
+ onModalChange: (showModal: boolean) => void;
14
+ editData: InitialData;
15
+ mutate: Mutator;
16
+ }
17
+
18
+ const EditBedForm: React.FC<EditBedFormProps> = ({
19
+ showModal,
20
+ onModalChange,
21
+ editData,
22
+ mutate,
23
+ }) => {
24
+ const { t } = useTranslation();
25
+ const { admissionLocationTagUuid } = useConfig();
26
+ const { data: admissionLocations } = useLocationsByTag(
27
+ admissionLocationTagUuid
28
+ );
29
+
30
+ const headerTitle = t("editBed", "Edit bed");
31
+ const occupancyStatuses = ["Available", "Occupied"];
32
+ const { bedTypes } = useBedType();
33
+ const availableBedTypes = bedTypes ? bedTypes : [];
34
+ const handleCreateQuestion = useCallback(
35
+ (formData: BedAdministrationData) => {
36
+ const bedUuid = editData.uuid;
37
+ const {
38
+ bedId = editData.bedNumber,
39
+ description = editData.description,
40
+ occupancyStatus = editData.status,
41
+ bedRow = editData.row.toString(),
42
+ bedColumn = editData.column.toString(),
43
+ location: { uuid: bedLocation = editData.location.uuid },
44
+ bedType = editData.bedType.name,
45
+ } = formData;
46
+ const bedPayload = {
47
+ bedNumber: bedId,
48
+ bedType,
49
+ description,
50
+ status: occupancyStatus.toUpperCase(),
51
+ row: parseInt(bedRow),
52
+ column: parseInt(bedColumn),
53
+ locationUuid: bedLocation,
54
+ };
55
+ editBed({ bedPayload, bedId: bedUuid })
56
+ .then(() => {
57
+ showToast({
58
+ title: t("formSaved", "Bed saved"),
59
+ kind: "success",
60
+ critical: true,
61
+ description:
62
+ bedPayload.bedNumber +
63
+ " " +
64
+ t("saveSuccessMessage", "was saved successfully."),
65
+ });
66
+
67
+ mutate();
68
+ onModalChange(false);
69
+ })
70
+ .catch((error) => {
71
+ showNotification({
72
+ title: t("errorCreatingForm", "Error creating bed"),
73
+ kind: "error",
74
+ critical: true,
75
+ description: error?.message,
76
+ });
77
+ onModalChange(false);
78
+ });
79
+ onModalChange(false);
80
+ },
81
+ [onModalChange, mutate, editData, t]
82
+ );
83
+
84
+ return (
85
+ <>
86
+ <BedAdministrationForm
87
+ onModalChange={onModalChange}
88
+ allLocations={admissionLocations}
89
+ availableBedTypes={availableBedTypes}
90
+ showModal={showModal}
91
+ handleCreateQuestion={handleCreateQuestion}
92
+ headerTitle={headerTitle}
93
+ occupancyStatuses={occupancyStatuses}
94
+ initialData={editData}
95
+ />
96
+ </>
97
+ );
98
+ };
99
+
100
+ export default EditBedForm;