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

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.
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useMemo, useState } from "react";
1
+ import React, { useMemo, useState } from "react";
2
2
  import { useTranslation } from "react-i18next";
3
3
  import {
4
4
  Button,
@@ -15,10 +15,9 @@ import {
15
15
  TableRow,
16
16
  Tile,
17
17
  } from "@carbon/react";
18
- import { Add, Edit } from "@carbon/react/icons";
18
+ import { Add, Edit, Delete } from "@carbon/react/icons";
19
19
  import {
20
20
  isDesktop as desktopLayout,
21
- useConfig,
22
21
  useLayoutType,
23
22
  } from "@openmrs/esm-framework";
24
23
  import { CardHeader, ErrorState } from "@openmrs/esm-patient-common-lib";
@@ -28,6 +27,7 @@ import Header from "../../header/header.component";
28
27
  import BedTypeForm from "./new-bed-type-form.component";
29
28
  import styles from "../../bed-administration/bed-administration-table.scss";
30
29
  import EditBedTypeForm from "./edit-bed-type.component";
30
+ import DeleteBedType from "./delete-bed-type.component";
31
31
 
32
32
  const BedTypeAdministrationTable: React.FC = () => {
33
33
  const { t } = useTranslation();
@@ -37,14 +37,13 @@ const BedTypeAdministrationTable: React.FC = () => {
37
37
  const responsiveSize = isTablet ? "lg" : "sm";
38
38
  const isDesktop = desktopLayout(layout);
39
39
  const [showEditBedModal, setShowEditBedModal] = useState(false);
40
- const [isBedDataLoading, setIsBedDataLoading] = useState(false);
40
+ const [isBedDataLoading] = useState(false);
41
41
  const [showBedTypeModal, setAddBedTypeModal] = useState(false);
42
42
  const [currentPage, setCurrentPage] = useState(1);
43
43
  const [editData, setEditData] = useState<BedTypeData>();
44
+ const [showDeleteBedTypeModal, setDeleteBedTypeModal] = useState(false);
44
45
  const [pageSize] = useState(10);
45
46
  const { bedTypeData, isError, loading, validate, mutate } = useBedType();
46
- const [currentPageSize, setPageSize] = useState(10);
47
- const pageSizes = [10, 20, 30, 40, 50];
48
47
  const tableHeaders = [
49
48
  {
50
49
  header: t("name", "Name"),
@@ -80,6 +79,7 @@ const BedTypeAdministrationTable: React.FC = () => {
80
79
  setEditData(entry);
81
80
  setShowEditBedModal(true);
82
81
  setAddBedTypeModal(false);
82
+ setDeleteBedTypeModal(false);
83
83
  }}
84
84
  kind={"ghost"}
85
85
  iconDescription={t("editBedType", "Edit Bed Type")}
@@ -87,6 +87,22 @@ const BedTypeAdministrationTable: React.FC = () => {
87
87
  size={responsiveSize}
88
88
  tooltipAlignment="start"
89
89
  />
90
+ <Button
91
+ enterDelayMs={300}
92
+ renderIcon={Delete}
93
+ onClick={(e) => {
94
+ e.preventDefault();
95
+ setEditData(entry);
96
+ setShowEditBedModal(false);
97
+ setAddBedTypeModal(false);
98
+ setDeleteBedTypeModal(true);
99
+ }}
100
+ kind={"ghost"}
101
+ iconDescription={t("deleteBedTag", "Delete Bed Tag")}
102
+ hasIconOnly
103
+ size={responsiveSize}
104
+ tooltipAlignment="start"
105
+ />
90
106
  </>
91
107
  ),
92
108
  }));
@@ -134,6 +150,14 @@ const BedTypeAdministrationTable: React.FC = () => {
134
150
  mutate={mutate}
135
151
  />
136
152
  ) : null}
153
+ {showDeleteBedTypeModal ? (
154
+ <DeleteBedType
155
+ onModalChange={setDeleteBedTypeModal}
156
+ showModal={showDeleteBedTypeModal}
157
+ editData={editData}
158
+ mutate={mutate}
159
+ />
160
+ ) : null}
137
161
  <CardHeader title={headerTitle}>
138
162
  <span className={styles.backgroundDataFetchingIndicator}>
139
163
  <span>{validate ? <InlineLoading /> : null}</span>
@@ -209,7 +233,7 @@ const BedTypeAdministrationTable: React.FC = () => {
209
233
  totalItems={bedTypeData.length}
210
234
  onChange={({ page, pageSize }) => {
211
235
  setCurrentPage(page);
212
- setPageSize(pageSize);
236
+ pageSize(pageSize);
213
237
  }}
214
238
  />
215
239
  </TableContainer>
@@ -0,0 +1,69 @@
1
+ import React, { useCallback } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { showToast, showNotification } from "@openmrs/esm-framework";
4
+ import { deleteBedType } from "../../summary/summary.resource";
5
+ import { BedTagDataAdministration } from "../../bed-administration/bed-administration-types";
6
+ import { BedTagData, Mutator } from "../../types";
7
+ import DeleteBedTypesForm from "./deleteBedtypeForm.component";
8
+
9
+ interface DeleteBedTypeFormProps {
10
+ showModal: boolean;
11
+ onModalChange: (showModal: boolean) => void;
12
+ editData: BedTagData;
13
+ mutate: Mutator;
14
+ }
15
+
16
+ const DeleteBedType: React.FC<DeleteBedTypeFormProps> = ({
17
+ showModal,
18
+ onModalChange,
19
+ editData,
20
+ mutate,
21
+ }) => {
22
+ const { t } = useTranslation();
23
+ const headerTitle = t("deleteBedType", "Delete bed Type");
24
+ const handleDeleteQuestion = useCallback(
25
+ (formData: BedTagDataAdministration) => {
26
+ const bedUuid = editData.uuid;
27
+ const { name } = formData;
28
+ deleteBedType(bedUuid)
29
+ .then(() => {
30
+ showToast({
31
+ title: t("bedTypeDeleted", "Bed Type Deleted"),
32
+ kind: "success",
33
+ critical: true,
34
+ description:
35
+ name +
36
+ " " +
37
+ t("bedTypeDeleteSuccessMessage", "was deleted successfully."),
38
+ });
39
+
40
+ mutate();
41
+ onModalChange(false);
42
+ })
43
+ .catch((error) => {
44
+ showNotification({
45
+ title: t("errorDeletingBedType", "Error deleting bed type"),
46
+ kind: "error",
47
+ critical: true,
48
+ description: error?.message,
49
+ });
50
+ onModalChange(false);
51
+ });
52
+ onModalChange(false);
53
+ },
54
+ [onModalChange, mutate, editData, t]
55
+ );
56
+ return (
57
+ <>
58
+ <DeleteBedTypesForm
59
+ onModalChange={onModalChange}
60
+ showModal={showModal}
61
+ handleDeleteBedTag={handleDeleteQuestion}
62
+ headerTitle={headerTitle}
63
+ initialData={editData}
64
+ />
65
+ </>
66
+ );
67
+ };
68
+
69
+ export default DeleteBedType;
@@ -0,0 +1,108 @@
1
+ import React, { useState } from "react";
2
+ import { z } from "zod";
3
+ import { useForm } from "react-hook-form";
4
+ import { zodResolver } from "@hookform/resolvers/zod";
5
+ import {
6
+ Button,
7
+ ComposedModal,
8
+ ModalBody,
9
+ ModalFooter,
10
+ ModalHeader,
11
+ Stack,
12
+ InlineNotification,
13
+ } from "@carbon/react";
14
+ import { useTranslation } from "react-i18next";
15
+ import styles from "../../bed-administration/bed-administration-table.scss";
16
+ interface BedTagData {
17
+ name: string;
18
+ }
19
+
20
+ const BedTagAdministrationSchema = z.object({
21
+ name: z.string().max(255),
22
+ });
23
+
24
+ interface BedTagAdministrationFormProps {
25
+ showModal: boolean;
26
+ onModalChange: (showModal: boolean) => void;
27
+ handleDeleteBedTag?: (formData: BedTagData) => void;
28
+ headerTitle: string;
29
+ initialData: BedTagData;
30
+ }
31
+
32
+ interface ErrorType {
33
+ message: string;
34
+ }
35
+
36
+ const DeleteBedTypesForm: React.FC<BedTagAdministrationFormProps> = ({
37
+ showModal,
38
+ onModalChange,
39
+ handleDeleteBedTag,
40
+ headerTitle,
41
+ initialData,
42
+ }) => {
43
+ const { t } = useTranslation();
44
+
45
+ const [showErrorNotification, setShowErrorNotification] = useState(false);
46
+ const [formStateError, setFormStateError] = useState("");
47
+
48
+ const { handleSubmit } = useForm<BedTagData>({
49
+ mode: "all",
50
+ resolver: zodResolver(BedTagAdministrationSchema),
51
+ defaultValues: {
52
+ name: initialData.name || "",
53
+ },
54
+ });
55
+
56
+ const onSubmit = (formData: BedTagData) => {
57
+ const result = BedTagAdministrationSchema.safeParse(formData);
58
+ if (result.success) {
59
+ setShowErrorNotification(false);
60
+ if (handleDeleteBedTag) {
61
+ handleDeleteBedTag(formData);
62
+ }
63
+ }
64
+ };
65
+
66
+ const onError = (error: { [key: string]: ErrorType }) => {
67
+ setFormStateError(Object.entries(error)[0][1].message);
68
+ setShowErrorNotification(true);
69
+ };
70
+
71
+ return (
72
+ <ComposedModal
73
+ open={showModal}
74
+ onClose={() => onModalChange(false)}
75
+ preventCloseOnClickOutside
76
+ >
77
+ <ModalHeader title={headerTitle} />
78
+ <form onSubmit={handleSubmit(onSubmit, onError)}>
79
+ <ModalBody hasScrollingContent>
80
+ <Stack gap={3}>
81
+ <ModalBody>Are you sure you want to delete this bed tag?</ModalBody>
82
+ {showErrorNotification && (
83
+ <InlineNotification
84
+ lowContrast
85
+ title={t("error", "Error")}
86
+ style={{ minWidth: "100%", margin: "0rem", padding: "0rem" }}
87
+ role="alert"
88
+ kind="error"
89
+ subtitle={t("pleaseFillField", formStateError) + "."}
90
+ onClose={() => setShowErrorNotification(false)}
91
+ />
92
+ )}
93
+ </Stack>
94
+ </ModalBody>
95
+ <ModalFooter>
96
+ <Button onClick={() => onModalChange(false)} kind="secondary">
97
+ {t("cancel", "Cancel")}
98
+ </Button>
99
+ <Button type="submit" className={styles.deleteButton}>
100
+ <span>{t("delete", "Delete")}</span>
101
+ </Button>
102
+ </ModalFooter>
103
+ </form>
104
+ </ComposedModal>
105
+ );
106
+ };
107
+
108
+ export default DeleteBedTypesForm;
@@ -1,6 +1,6 @@
1
1
  import React, { useCallback } from "react";
2
2
  import { useTranslation } from "react-i18next";
3
- import { showToast, showNotification, useConfig } from "@openmrs/esm-framework";
3
+ import { showToast, showNotification } from "@openmrs/esm-framework";
4
4
 
5
5
  import { editBedType, useBedType } from "../../summary/summary.resource";
6
6
  import { BedTypeDataAdministration } from "../../bed-administration/bed-administration-types";
@@ -1,5 +1,5 @@
1
1
  import useSWR from "swr";
2
- import { FetchResponse, openmrsFetch } from "@openmrs/esm-framework";
2
+ import { FetchResponse, openmrsFetch, showToast } from "@openmrs/esm-framework";
3
3
  import type { AdmissionLocation, Bed, MappedBedData } from "../types";
4
4
 
5
5
  export const useLocationsByTag = (locationUuid: string) => {
@@ -163,49 +163,157 @@ interface BedTag {
163
163
  export async function saveBedType({
164
164
  bedPayload,
165
165
  }): Promise<FetchResponse<BedType>> {
166
- const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bedtype`, {
167
- method: "POST",
168
- headers: { "Content-Type": "application/json" },
169
- body: bedPayload,
170
- });
171
- return response;
166
+ try {
167
+ const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bedtype`, {
168
+ method: "POST",
169
+ headers: { "Content-Type": "application/json" },
170
+ body: bedPayload,
171
+ });
172
+ return response;
173
+ } catch (error) {
174
+ const errorMessages = extractErrorMessagesFromResponse(error);
175
+ showToast({
176
+ description: errorMessages.join(", "),
177
+ title: "Error on saving form",
178
+ kind: "error",
179
+ critical: true,
180
+ });
181
+ }
172
182
  }
173
183
 
174
184
  export async function saveBedTag({
175
185
  bedPayload,
176
186
  }): Promise<FetchResponse<BedTag>> {
177
- const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bedTag/`, {
178
- method: "POST",
179
- headers: { "Content-Type": "application/json" },
180
- body: bedPayload,
181
- });
182
- return response;
187
+ try {
188
+ const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bedTag/`, {
189
+ method: "POST",
190
+ headers: { "Content-Type": "application/json" },
191
+ body: bedPayload,
192
+ });
193
+ return response;
194
+ } catch (error) {
195
+ const errorMessages = extractErrorMessagesFromResponse(error);
196
+ showToast({
197
+ description: errorMessages.join(", "),
198
+ title: "Error on saving form",
199
+ kind: "error",
200
+ critical: true,
201
+ });
202
+ }
183
203
  }
184
204
  export async function editBedType({
185
205
  bedPayload,
186
206
  bedTypeId,
187
207
  }): Promise<FetchResponse<BedType>> {
188
- const response: FetchResponse = await openmrsFetch(
189
- `/ws/rest/v1/bedtype/${bedTypeId}`,
190
- {
191
- method: "POST",
192
- headers: { "Content-Type": "application/json" },
193
- body: bedPayload,
194
- }
195
- );
196
- return response;
208
+ try {
209
+ const response: FetchResponse = await openmrsFetch(
210
+ `/ws/rest/v1/bedtype/${bedTypeId}`,
211
+ {
212
+ method: "POST",
213
+ headers: { "Content-Type": "application/json" },
214
+ body: bedPayload,
215
+ }
216
+ );
217
+ return response;
218
+ } catch (error) {
219
+ const errorMessages = extractErrorMessagesFromResponse(error);
220
+ showToast({
221
+ description: errorMessages.join(", "),
222
+ title: "Error on saving form",
223
+ kind: "error",
224
+ critical: true,
225
+ });
226
+ }
197
227
  }
198
228
  export async function editBedTag({
199
229
  bedPayload,
200
230
  bedTagId,
201
231
  }): Promise<FetchResponse<BedType>> {
202
- const response: FetchResponse = await openmrsFetch(
203
- `/ws/rest/v1/bedTag/${bedTagId}`,
204
- {
205
- method: "POST",
206
- headers: { "Content-Type": "application/json" },
207
- body: bedPayload,
208
- }
232
+ try {
233
+ const response: FetchResponse = await openmrsFetch(
234
+ `/ws/rest/v1/bedTag/${bedTagId}`,
235
+ {
236
+ method: "POST",
237
+ headers: { "Content-Type": "application/json" },
238
+ body: bedPayload,
239
+ }
240
+ );
241
+ return response;
242
+ } catch (error) {
243
+ const errorMessages = extractErrorMessagesFromResponse(error);
244
+ showToast({
245
+ description: errorMessages.join(", "),
246
+ title: "Error on saving form",
247
+ kind: "error",
248
+ critical: true,
249
+ });
250
+ }
251
+ }
252
+
253
+ export function extractErrorMessagesFromResponse(errorObject) {
254
+ const fieldErrors = errorObject?.responseBody?.error?.fieldErrors;
255
+
256
+ if (!fieldErrors) {
257
+ return [errorObject?.responseBody?.error?.message ?? errorObject?.message];
258
+ }
259
+
260
+ return Object.values(fieldErrors).flatMap((errors: Array<Error>) =>
261
+ errors.map((error) => error.message)
209
262
  );
210
- return response;
263
+ }
264
+
265
+ export async function deleteBedTag(
266
+ bedTagId: string
267
+ ): Promise<FetchResponse<BedTag>> {
268
+ try {
269
+ const response: FetchResponse = await openmrsFetch(
270
+ `/ws/rest/v1/bedTag/${bedTagId}`,
271
+ {
272
+ method: "DELETE",
273
+ headers: { "Content-Type": "application/json" },
274
+ }
275
+ );
276
+
277
+ if (response.ok) {
278
+ return response;
279
+ } else {
280
+ throw new Error(`Failed to delete bed tag. Status: ${response.status}`);
281
+ }
282
+ } catch (error) {
283
+ const errorMessages = extractErrorMessagesFromResponse(error);
284
+ showToast({
285
+ description: errorMessages.join(", "),
286
+ title: "Error on deleting bed tag",
287
+ kind: "error",
288
+ critical: true,
289
+ });
290
+ }
291
+ }
292
+
293
+ export async function deleteBedType(
294
+ bedtype: string
295
+ ): Promise<FetchResponse<BedType>> {
296
+ try {
297
+ const response: FetchResponse = await openmrsFetch(
298
+ `/ws/rest/v1/bedtype/${bedtype}`,
299
+ {
300
+ method: "DELETE",
301
+ headers: { "Content-Type": "application/json" },
302
+ }
303
+ );
304
+
305
+ if (response.ok) {
306
+ return response;
307
+ } else {
308
+ throw new Error(`Failed to delete bed tag. Status: ${response.status}`);
309
+ }
310
+ } catch (error) {
311
+ const errorMessages = extractErrorMessagesFromResponse(error);
312
+ showToast({
313
+ description: errorMessages.join(", "),
314
+ title: "Error on saving form",
315
+ kind: "error",
316
+ critical: true,
317
+ });
318
+ }
211
319
  }