From cdf0ba96c41cdf2878865643e54a881e14f5b37e Mon Sep 17 00:00:00 2001 From: Gabriel Mbatha Ngao Date: Fri, 19 Jan 2024 16:44:43 +0300 Subject: [PATCH] Creation of bed type, bed tag (#15) --- .../bed-administration-types.ts | 8 + .../active-patients-table.component.tsx | 1 - .../bed-admission-tabs.component.tsx | 3 +- ...bed-tag-administration-table.component.tsx | 217 +++++++++++++++++ .../bed-tag/bed-tags-admin-form.component.tsx | 131 +++++++++++ .../bed-tag/edit-tag-form.component.tsx | 80 +++++++ .../bed-tag/new-tag-form.component.tsx | 83 +++++++ .../bed-type-admin-form.component.tsx | 173 ++++++++++++++ ...ed-type-administration-table.component.tsx | 222 ++++++++++++++++++ .../bed-type/edit-bed-type.component.tsx | 80 +++++++ .../bed-type/new-bed-type-form.component.tsx | 87 +++++++ src/index.ts | 14 ++ src/root.component.tsx | 6 +- src/routes.json | 10 + src/summary/summary.resource.ts | 91 ++++++- src/types.ts | 11 + 16 files changed, 1212 insertions(+), 5 deletions(-) create mode 100644 src/bed-admission/bed-tag/bed-tag-administration-table.component.tsx create mode 100644 src/bed-admission/bed-tag/bed-tags-admin-form.component.tsx create mode 100644 src/bed-admission/bed-tag/edit-tag-form.component.tsx create mode 100644 src/bed-admission/bed-tag/new-tag-form.component.tsx create mode 100644 src/bed-admission/bed-type/bed-type-admin-form.component.tsx create mode 100644 src/bed-admission/bed-type/bed-type-administration-table.component.tsx create mode 100644 src/bed-admission/bed-type/edit-bed-type.component.tsx create mode 100644 src/bed-admission/bed-type/new-bed-type-form.component.tsx diff --git a/src/bed-administration/bed-administration-types.ts b/src/bed-administration/bed-administration-types.ts index a7a6526..e879ae7 100644 --- a/src/bed-administration/bed-administration-types.ts +++ b/src/bed-administration/bed-administration-types.ts @@ -10,3 +10,11 @@ export interface BedAdministrationData { occupancyStatus: string; bedType: string; } +export interface BedTypeDataAdministration { + name: string; + displayName: string; + description: string; +} +export interface BedTagDataAdministration { + name: string; +} diff --git a/src/bed-admission/active-patients/active-patients-table.component.tsx b/src/bed-admission/active-patients/active-patients-table.component.tsx index 3142338..189091e 100644 --- a/src/bed-admission/active-patients/active-patients-table.component.tsx +++ b/src/bed-admission/active-patients/active-patients-table.component.tsx @@ -67,7 +67,6 @@ const ActivePatientsTable: React.FC = ({ session?.sessionLocation?.uuid, status ); - const handleBedAssigmentModal = useCallback( (entry) => { setSelectedPatientDetails({ diff --git a/src/bed-admission/bed-admission-tabs.component.tsx b/src/bed-admission/bed-admission-tabs.component.tsx index 38899ff..9889133 100644 --- a/src/bed-admission/bed-admission-tabs.component.tsx +++ b/src/bed-admission/bed-admission-tabs.component.tsx @@ -1,4 +1,4 @@ -import { Tab, TabList, TabPanel, TabPanels, Tabs } from "@carbon/react"; +import { Tab, TabList, TabPanel, TabPanels, Tabs, Button } from "@carbon/react"; import React, { useState } from "react"; import styles from "./bed-admission-tabs-styles.scss"; import { useTranslation } from "react-i18next"; @@ -12,7 +12,6 @@ const BedAdmissionTabs: React.FC = () => { const [admittedCount, setAdmittedCount] = useState(0); const [toAdmitCount, setToAdmitCount] = useState(0); const [toDischargeCount, setToDischargeCount] = useState(0); - return ( <>
diff --git a/src/bed-admission/bed-tag/bed-tag-administration-table.component.tsx b/src/bed-admission/bed-tag/bed-tag-administration-table.component.tsx new file mode 100644 index 0000000..157b847 --- /dev/null +++ b/src/bed-admission/bed-tag/bed-tag-administration-table.component.tsx @@ -0,0 +1,217 @@ +import React, { useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { + Button, + DataTable, + DataTableSkeleton, + InlineLoading, + Pagination, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableHeader, + TableRow, + Tile, +} from "@carbon/react"; +import { Add, Edit } from "@carbon/react/icons"; +import { + isDesktop as desktopLayout, + useLayoutType, +} from "@openmrs/esm-framework"; +import { CardHeader, ErrorState } from "@openmrs/esm-patient-common-lib"; +import type { BedTagData } from "../../types"; +import { useBedTag } from "../../summary/summary.resource"; +import Header from "../../header/header.component"; +import styles from "../../bed-administration/bed-administration-table.scss"; +import BedTagForm from "./new-tag-form.component"; +import EditBedTagForm from "./edit-tag-form.component"; + +const BedTagAdministrationTable: React.FC = () => { + const { t } = useTranslation(); + const headerTitle = t("bedTag", "Bed Tag"); + const layout = useLayoutType(); + const isTablet = layout === "tablet"; + const responsiveSize = isTablet ? "lg" : "sm"; + const isDesktop = desktopLayout(layout); + const [isBedDataLoading] = useState(false); + const [showBedTagsModal, setAddBedTagsModal] = useState(false); + const [showEditBedModal, setShowEditBedModal] = useState(false); + const [editData, setEditData] = useState(); + const [currentPage, setCurrentPage] = useState(1); + const [pageSize] = useState(10); + const { bedTypeData, isError, loading, validate, mutate } = useBedTag(); + const [currentPageSize, setPageSize] = useState(10); + const pageSizes = [10, 20, 30, 40, 50]; + + const tableHeaders = [ + { + header: t("ids", "Id"), + key: "ids", + }, + { + header: t("name", "Name"), + key: "name", + }, + { + header: t("actions", "Actions"), + key: "actions", + }, + ]; + + const tableRows = useMemo(() => { + return bedTypeData?.map((entry) => ({ + id: entry.uuid, + ids: entry.id, + name: entry?.name, + actions: ( + <> + + ) : null} + + + {({ rows, headers, getTableProps }) => ( + + + + + {headers.map((header) => ( + + {header.header?.content ?? header.header} + + ))} + + + + {rows.map((row) => ( + + {row.cells.map((cell) => ( + + {cell.value?.content ?? cell.value} + + ))} + + ))} + +
+ {rows.length === 0 ? ( +
+ +
+

+ {t("No data", "No data to display")} +

+

+ {t("checkFilters", "Check the filters above")} +

+
+

{t("or", "or")}

+ +
+
+ ) : null} + { + setCurrentPage(page); + setPageSize(pageSize); + }} + /> +
+ )} +
+
+ + ); +}; +export default BedTagAdministrationTable; diff --git a/src/bed-admission/bed-tag/bed-tags-admin-form.component.tsx b/src/bed-admission/bed-tag/bed-tags-admin-form.component.tsx new file mode 100644 index 0000000..76342f6 --- /dev/null +++ b/src/bed-admission/bed-tag/bed-tags-admin-form.component.tsx @@ -0,0 +1,131 @@ +import React, { useState } from "react"; +import { z } from "zod"; +import { useForm, Controller } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { + Button, + ComposedModal, + Form, + FormGroup, + ModalBody, + ModalFooter, + ModalHeader, + Stack, + TextInput, + InlineNotification, +} from "@carbon/react"; +import { useTranslation } from "react-i18next"; +import { Location } from "@openmrs/esm-framework"; +import type { BedTagData } from "../../types"; + +const BedTagAdministrationSchema = z.object({ + name: z.string().max(255), +}); + +interface BedTagAdministrationFormProps { + showModal: boolean; + onModalChange: (showModal: boolean) => void; + availableBedTypes: Array; + allLocations: Location[]; + handleCreateQuestion?: (formData: BedTagData) => void; + handleDeleteBedTag?: () => void; + headerTitle: string; + initialData: BedTagData; +} + +interface ErrorType { + message: string; +} + +const BedTagsAdministrationForm: React.FC = ({ + showModal, + onModalChange, + handleCreateQuestion, + headerTitle, + initialData, +}) => { + const { t } = useTranslation(); + + const [showErrorNotification, setShowErrorNotification] = useState(false); + const [formStateError, setFormStateError] = useState(""); + + const { + handleSubmit, + control, + formState: { isDirty }, + } = useForm({ + mode: "all", + resolver: zodResolver(BedTagAdministrationSchema), + defaultValues: { + name: initialData.name || "", + }, + }); + + const onSubmit = (formData: BedTagData) => { + const result = BedTagAdministrationSchema.safeParse(formData); + if (result.success) { + setShowErrorNotification(false); + handleCreateQuestion(formData); + } + }; + + const onError = (error: { [key: string]: ErrorType }) => { + setFormStateError(Object.entries(error)[0][1].message); + setShowErrorNotification(true); + }; + + return ( + onModalChange(false)} + preventCloseOnClickOutside + > + +
+ + + + ( + <> + + + )} + /> + + + {showErrorNotification && ( + setShowErrorNotification(false)} + /> + )} + + + + + + +
+
+ ); +}; + +export default BedTagsAdministrationForm; diff --git a/src/bed-admission/bed-tag/edit-tag-form.component.tsx b/src/bed-admission/bed-tag/edit-tag-form.component.tsx new file mode 100644 index 0000000..6367844 --- /dev/null +++ b/src/bed-admission/bed-tag/edit-tag-form.component.tsx @@ -0,0 +1,80 @@ +import React, { useCallback } from "react"; +import { useTranslation } from "react-i18next"; +import { showToast, showNotification, useConfig } from "@openmrs/esm-framework"; + +import { editBedTag, useBedTag } from "../../summary/summary.resource"; +import { BedTagDataAdministration } from "../../bed-administration/bed-administration-types"; +import BedTagsAdministrationForm from "./bed-tags-admin-form.component"; +import { BedTagData, Mutator } from "../../types"; + +interface EditBedTagFormProps { + showModal: boolean; + onModalChange: (showModal: boolean) => void; + editData: BedTagData; + mutate: Mutator; +} + +const EditBedTagForm: React.FC = ({ + showModal, + onModalChange, + editData, + mutate, +}) => { + const { t } = useTranslation(); + + const headerTitle = t("editBed", "Edit Tag"); + const { bedTypeData } = useBedTag(); + const availableBedTypes = bedTypeData ? bedTypeData : []; + + const handleCreateQuestion = useCallback( + (formData: BedTagDataAdministration) => { + const bedUuid = editData.uuid; + const { name } = formData; + const bedPayload = { + name, + }; + editBedTag({ bedPayload, bedTagId: bedUuid }) + .then(() => { + showToast({ + title: t("formSaved", "Bed Tag"), + kind: "success", + critical: true, + description: + bedPayload.name + + " " + + t("saveSuccessMessage", "was saved successfully."), + }); + + mutate(); + onModalChange(false); + }) + .catch((error) => { + showNotification({ + title: t("errorCreatingForm", "Error creating bed"), + kind: "error", + critical: true, + description: error?.message, + }); + onModalChange(false); + }); + onModalChange(false); + }, + [onModalChange, mutate, editData, t] + ); + + return ( + <> + + + ); +}; + +export default EditBedTagForm; diff --git a/src/bed-admission/bed-tag/new-tag-form.component.tsx b/src/bed-admission/bed-tag/new-tag-form.component.tsx new file mode 100644 index 0000000..06d438c --- /dev/null +++ b/src/bed-admission/bed-tag/new-tag-form.component.tsx @@ -0,0 +1,83 @@ +import React, { useCallback } from "react"; +import { useTranslation } from "react-i18next"; +import { showToast, showNotification, useConfig } from "@openmrs/esm-framework"; +import { useBedType } from "../../bed-administration/bed-administration.resource"; +import BedTagsAdministrationForm from "./bed-tags-admin-form.component"; +import { saveBedTag, useLocationsByTag } from "../../summary/summary.resource"; +import { BedTagData, Mutator } from "../../types"; + +interface BedTagFormProps { + showModal: boolean; + onModalChange: (showModal: boolean) => void; + mutate: Mutator; +} + +const NewTagForm: React.FC = ({ + showModal, + onModalChange, + mutate, +}) => { + const { t } = useTranslation(); + const { admissionLocationTagUuid } = useConfig(); + const { data: admissionLocations } = useLocationsByTag( + admissionLocationTagUuid + ); + const headerTitle = t("addBedTag", "Create Bed Tag"); + const { bedTypes } = useBedType(); + const availableBedTypes = bedTypes ? bedTypes : []; + + const initialData: BedTagData = { + uuid: "", + name: "", + }; + + const handleCreateQuestion = useCallback( + (formData: BedTagData) => { + const { name } = formData; + + const bedObject = { + name, + }; + + saveBedTag({ bedPayload: bedObject }) + .then(() => { + showToast({ + title: t("formCreated", "Add Bed Tag"), + kind: "success", + critical: true, + description: `Tag ${name} was created successfully.`, + }); + + mutate(); + onModalChange(false); + }) + .catch((error) => { + showNotification({ + title: t("errorCreatingForm", "Error creating bed"), + kind: "error", + critical: true, + description: error?.message, + }); + onModalChange(false); + }); + onModalChange(false); + }, + [onModalChange, mutate, t] + ); + + return ( + <> + + + ); +}; + +export default NewTagForm; diff --git a/src/bed-admission/bed-type/bed-type-admin-form.component.tsx b/src/bed-admission/bed-type/bed-type-admin-form.component.tsx new file mode 100644 index 0000000..a5950c3 --- /dev/null +++ b/src/bed-admission/bed-type/bed-type-admin-form.component.tsx @@ -0,0 +1,173 @@ +import React, { useState } from "react"; +import { z } from "zod"; +import { useForm, Controller } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { + Button, + ComposedModal, + Form, + FormGroup, + ModalBody, + ModalFooter, + ModalHeader, + Stack, + TextArea, + TextInput, + InlineNotification, +} from "@carbon/react"; +import { useTranslation } from "react-i18next"; +import { Location } from "@openmrs/esm-framework"; +import type { BedType, BedTypeData } from "../../types"; + +const BedTypeAdministrationSchema = z.object({ + name: z.string().max(255), + displayName: z.string().max(255), + description: z.string().max(255), +}); + +interface BedAdministrationFormProps { + showModal: boolean; + onModalChange: (showModal: boolean) => void; + availableBedTypes: Array; + allLocations: Location[]; + handleCreateQuestion?: (formData: BedTypeData) => void; + headerTitle: string; + initialData: BedTypeData; +} + +interface ErrorType { + message: string; +} + +const BedTypeAdministrationForm: React.FC = ({ + showModal, + onModalChange, + handleCreateQuestion, + headerTitle, + initialData, +}) => { + const { t } = useTranslation(); + + const [showErrorNotification, setShowErrorNotification] = useState(false); + const [formStateError, setFormStateError] = useState(""); + + const { + handleSubmit, + control, + formState: { isDirty }, + } = useForm({ + mode: "all", + resolver: zodResolver(BedTypeAdministrationSchema), + defaultValues: { + name: initialData.name || "", + displayName: initialData.displayName || "", + description: initialData.description || "", + }, + }); + + const onSubmit = (formData: BedTypeData) => { + const result = BedTypeAdministrationSchema.safeParse(formData); + if (result.success) { + setShowErrorNotification(false); + handleCreateQuestion(formData); + } + }; + + const onError = (error: { [key: string]: ErrorType }) => { + setFormStateError(Object.entries(error)[0][1].message); + setShowErrorNotification(true); + }; + + return ( + onModalChange(false)} + preventCloseOnClickOutside + > + +
+ + + + ( + <> + + + )} + /> + + + ( + <> + + + )} + /> + + + ( + <> +