@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.
Files changed (108) hide show
  1. package/dist/26.js +1 -1
  2. package/dist/26.js.map +1 -1
  3. package/dist/294.js +1 -1
  4. package/dist/294.js.map +1 -1
  5. package/dist/360.js +1 -0
  6. package/dist/360.js.map +1 -0
  7. package/dist/452.js +1 -0
  8. package/dist/{884.js.map → 452.js.map} +1 -1
  9. package/dist/482.js +2 -0
  10. package/dist/482.js.LICENSE.txt +19 -0
  11. package/dist/482.js.map +1 -0
  12. package/dist/532.js +1 -0
  13. package/dist/532.js.map +1 -0
  14. package/dist/558.js +1 -1
  15. package/dist/558.js.map +1 -1
  16. package/dist/574.js +1 -1
  17. package/dist/663.js +2 -0
  18. package/dist/663.js.LICENSE.txt +44 -0
  19. package/dist/663.js.map +1 -0
  20. package/dist/666.js +1 -0
  21. package/dist/666.js.map +1 -0
  22. package/dist/708.js +2 -0
  23. package/dist/{330.js.LICENSE.txt → 708.js.LICENSE.txt} +0 -20
  24. package/dist/708.js.map +1 -0
  25. package/dist/763.js +2 -0
  26. package/dist/763.js.map +1 -0
  27. package/dist/774.js +1 -0
  28. package/dist/774.js.map +1 -0
  29. package/dist/815.js +1 -0
  30. package/dist/815.js.map +1 -0
  31. package/dist/847.js +1 -0
  32. package/dist/847.js.map +1 -0
  33. package/dist/898.js +1 -0
  34. package/dist/898.js.map +1 -0
  35. package/dist/931.js +1 -0
  36. package/dist/931.js.map +1 -0
  37. package/dist/935.js +1 -0
  38. package/dist/935.js.map +1 -0
  39. package/dist/esm-kenyaemr-bed-management-app.js +1 -1
  40. package/dist/esm-kenyaemr-bed-management-app.js.buildmanifest.json +207 -135
  41. package/dist/esm-kenyaemr-bed-management-app.js.map +1 -1
  42. package/dist/main.js +1 -1
  43. package/dist/main.js.map +1 -1
  44. package/dist/routes.json +1 -1
  45. package/package.json +4 -1
  46. package/src/bed-administration/bed-administration-table.scss +3 -0
  47. package/src/bed-administration/bed-administration-types.ts +8 -0
  48. package/src/bed-admission/active-patients/active-patients-table.component.tsx +13 -20
  49. package/src/bed-admission/active-patients/active-visits.resource.ts +1 -3
  50. package/src/bed-admission/active-patients/eligible-admissions.resource.ts +43 -0
  51. package/src/bed-admission/admitted-patients/active-admissions.resource.ts +5 -1
  52. package/src/bed-admission/admitted-patients/admitted-patients-table.component.tsx +3 -3
  53. package/src/bed-admission/bed-admission-tabs.component.tsx +0 -1
  54. package/src/bed-admission/bed-admission.resource.ts +1 -1
  55. package/src/bed-admission/bed-layout/bed-layout-list.component.tsx +2 -2
  56. package/src/bed-admission/bed-tag/bed-tag-administration-table.component.tsx +240 -0
  57. package/src/bed-admission/bed-tag/bed-tags-admin-form.component.tsx +146 -0
  58. package/src/bed-admission/bed-tag/delete-bed-tag.component.tsx +69 -0
  59. package/src/bed-admission/bed-tag/delete-bedForm.component.tsx +108 -0
  60. package/src/bed-admission/bed-tag/edit-tag-form.component.tsx +80 -0
  61. package/src/bed-admission/bed-tag/new-tag-form.component.tsx +83 -0
  62. package/src/bed-admission/bed-type/bed-type-admin-form.component.tsx +203 -0
  63. package/src/bed-admission/bed-type/bed-type-administration-table.component.tsx +246 -0
  64. package/src/bed-admission/bed-type/delete-bed-type.component.tsx +69 -0
  65. package/src/bed-admission/bed-type/deleteBedtypeForm.component.tsx +108 -0
  66. package/src/bed-admission/bed-type/edit-bed-type.component.tsx +80 -0
  67. package/src/bed-admission/bed-type/new-bed-type-form.component.tsx +87 -0
  68. package/src/bed-admission/types.ts +1 -3
  69. package/src/bed-admission/ward/new-ward-form.component.tsx +81 -0
  70. package/src/bed-admission/ward/ward-admin-form.component.tsx +193 -0
  71. package/src/bed-admission/ward/ward-administration-table.component.tsx +173 -0
  72. package/src/config-schema.ts +7 -1
  73. package/src/index.ts +21 -0
  74. package/src/root.component.tsx +6 -0
  75. package/src/routes.json +16 -1
  76. package/src/summary/summary.resource.ts +257 -1
  77. package/src/types.ts +23 -0
  78. package/src/workspace/allocate-bed-workspace.component.tsx +51 -18
  79. package/src/workspace/allocate-bed.scss +7 -0
  80. package/tsconfig.json +2 -1
  81. package/dist/187.js +0 -1
  82. package/dist/187.js.map +0 -1
  83. package/dist/207.js +0 -1
  84. package/dist/207.js.map +0 -1
  85. package/dist/283.js +0 -1
  86. package/dist/283.js.map +0 -1
  87. package/dist/330.js +0 -2
  88. package/dist/330.js.map +0 -1
  89. package/dist/352.js +0 -1
  90. package/dist/352.js.map +0 -1
  91. package/dist/404.js +0 -1
  92. package/dist/404.js.map +0 -1
  93. package/dist/455.js +0 -2
  94. package/dist/455.js.map +0 -1
  95. package/dist/629.js +0 -1
  96. package/dist/629.js.map +0 -1
  97. package/dist/707.js +0 -1
  98. package/dist/707.js.map +0 -1
  99. package/dist/800.js +0 -2
  100. package/dist/800.js.LICENSE.txt +0 -3
  101. package/dist/800.js.map +0 -1
  102. package/dist/884.js +0 -1
  103. package/dist/933.js +0 -1
  104. package/dist/933.js.map +0 -1
  105. package/dist/959.js +0 -1
  106. package/dist/959.js.map +0 -1
  107. /package/.yarn/versions/{6816f0d4.yml → 739e37b3.yml} +0 -0
  108. /package/dist/{455.js.LICENSE.txt → 763.js.LICENSE.txt} +0 -0
@@ -0,0 +1,193 @@
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
+ ComboBox,
17
+ Dropdown,
18
+ } from "@carbon/react";
19
+ import { useTranslation } from "react-i18next";
20
+ import { Location } from "@openmrs/esm-framework";
21
+ import type { LocationTagData } from "../../types";
22
+ import { useLocationTags } from "../../summary/summary.resource";
23
+
24
+ const WardAdministrationSchema = z.object({
25
+ name: z.string().max(255),
26
+ tagLocation: z
27
+ .object({ display: z.string(), uuid: z.string() })
28
+ .refine(
29
+ (value) => value.display != "",
30
+ "Please select a valid location Tag"
31
+ ),
32
+ });
33
+
34
+ interface WardAdministrationFormProps {
35
+ showModal: boolean;
36
+ onModalChange: (showModal: boolean) => void;
37
+ allLocations: Location[];
38
+ handleCreateQuestion?: (formData: LocationTagData) => void;
39
+ handleDeleteBedTag?: () => void;
40
+ headerTitle: string;
41
+ initialData: LocationTagData;
42
+ }
43
+ interface ErrorType {
44
+ message: string;
45
+ }
46
+ const WardAdministrationForm: React.FC<WardAdministrationFormProps> = ({
47
+ showModal,
48
+ onModalChange,
49
+ handleCreateQuestion,
50
+ headerTitle,
51
+ initialData,
52
+ }) => {
53
+ const { t } = useTranslation();
54
+ const { tagList, tagError, tagLoading, tagValidate, tagMutate } =
55
+ useLocationTags();
56
+ const [showErrorNotification, setShowErrorNotification] = useState(false);
57
+ const [formStateError, setFormStateError] = useState("");
58
+
59
+ const filterLocationNames = (tagLocation) => {
60
+ return (
61
+ tagLocation.display
62
+ ?.toLowerCase()
63
+ .includes(tagLocation?.inputValue?.toLowerCase()) ?? []
64
+ );
65
+ };
66
+ const {
67
+ handleSubmit,
68
+ control,
69
+ formState: { isDirty },
70
+ } = useForm<LocationTagData>({
71
+ mode: "all",
72
+ resolver: zodResolver(WardAdministrationSchema),
73
+ defaultValues: {
74
+ name: initialData.name || "",
75
+ tagLocation: initialData.tagLocation || {},
76
+ },
77
+ });
78
+
79
+ const onSubmit = (formData: LocationTagData) => {
80
+ const result = WardAdministrationSchema.safeParse(formData);
81
+ if (result.success) {
82
+ setShowErrorNotification(false);
83
+ handleCreateQuestion(formData);
84
+ }
85
+ };
86
+
87
+ const onError = (error: { [key: string]: ErrorType }) => {
88
+ setFormStateError(Object.entries(error)[0][1].message);
89
+ setShowErrorNotification(true);
90
+ };
91
+
92
+ return (
93
+ <ComposedModal
94
+ open={showModal}
95
+ onClose={() => onModalChange(false)}
96
+ preventCloseOnClickOutside
97
+ >
98
+ <ModalHeader title={headerTitle} />
99
+ <Form onSubmit={handleSubmit(onSubmit, onError)}>
100
+ <ModalBody hasScrollingContent>
101
+ <Stack gap={3}>
102
+ <FormGroup legendText={""}>
103
+ <Controller
104
+ name="name"
105
+ control={control}
106
+ rules={{ required: true }}
107
+ render={({ field, fieldState }) => (
108
+ <>
109
+ <TextInput
110
+ id="ward"
111
+ labelText={t("ward", "Ward Name")}
112
+ placeholder={t("wardPlaceholder", "")}
113
+ invalidText={fieldState.error?.message}
114
+ {...field}
115
+ />
116
+ </>
117
+ )}
118
+ />
119
+ </FormGroup>
120
+ {/* <FormGroup>
121
+ <Controller
122
+ name="tagLocation"
123
+ control={control}
124
+ rules={{ required: true }}
125
+ render={({ field }) => (
126
+ <Dropdown
127
+ label={t("selectTag", "Select a Tag...")}
128
+ onChange={({ selectedItem }) =>
129
+ field.onChange(selectedItem?.uuid)
130
+ }
131
+ id="locationTags"
132
+ items={tagList}
133
+ itemToString={(item) => (item ? `${item.display}` : "")}
134
+ />
135
+ )}
136
+ />
137
+ </FormGroup> */}
138
+ <FormGroup>
139
+ <Controller
140
+ name="tagLocation"
141
+ control={control}
142
+ render={({
143
+ fieldState,
144
+ field: { onChange, onBlur, value, ref },
145
+ }) => (
146
+ <ComboBox
147
+ aria-label={t("selectTag", "Select location Tag")}
148
+ shouldFilterItem={filterLocationNames}
149
+ id="locationTags"
150
+ label={t("selectTag", "Select location Tag...")}
151
+ invalidText={fieldState?.error?.message}
152
+ items={tagList}
153
+ onBlur={onBlur}
154
+ ref={ref}
155
+ selectedItem={value}
156
+ onChange={({ selectedItem }) => onChange(selectedItem)}
157
+ itemToString={(location) => location?.display ?? ""}
158
+ placeholder={t(
159
+ "selectBedLocation",
160
+ "Select a bed location Tag"
161
+ )}
162
+ titleText={t("bedLocation", "Location")}
163
+ />
164
+ )}
165
+ />
166
+ </FormGroup>
167
+ {showErrorNotification && (
168
+ <InlineNotification
169
+ lowContrast
170
+ title={t("error", "Error")}
171
+ style={{ minWidth: "100%", margin: "0rem", padding: "0rem" }}
172
+ role="alert"
173
+ kind="error"
174
+ subtitle={t("pleaseFillField", formStateError) + "."}
175
+ onClose={() => setShowErrorNotification(false)}
176
+ />
177
+ )}
178
+ </Stack>
179
+ </ModalBody>
180
+ <ModalFooter>
181
+ <Button onClick={() => onModalChange(false)} kind="secondary">
182
+ {t("cancel", "Cancel")}
183
+ </Button>
184
+ <Button disabled={!isDirty} type="submit">
185
+ <span>{t("save", "Save")}</span>
186
+ </Button>
187
+ </ModalFooter>
188
+ </Form>
189
+ </ComposedModal>
190
+ );
191
+ };
192
+
193
+ export default WardAdministrationForm;
@@ -0,0 +1,173 @@
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 } from "@carbon/react/icons";
19
+ import {
20
+ isDesktop as desktopLayout,
21
+ useLayoutType,
22
+ } from "@openmrs/esm-framework";
23
+ import { CardHeader, ErrorState } from "@openmrs/esm-patient-common-lib";
24
+ import Header from "../../header/header.component";
25
+ import styles from "../../bed-administration/bed-administration-table.scss";
26
+ import { useWard } from "../../summary/summary.resource";
27
+ import NewWardForm from "./new-ward-form.component";
28
+
29
+ const WardAdministrationTable: React.FC = () => {
30
+ const { t } = useTranslation();
31
+ const headerTitle = t("wardList", "List of Wards");
32
+ const layout = useLayoutType();
33
+ const isTablet = layout === "tablet";
34
+ const responsiveSize = isTablet ? "lg" : "sm";
35
+ const isDesktop = desktopLayout(layout);
36
+ const [isBedDataLoading] = useState(false);
37
+ const [showWardModal, setAddWardModal] = useState(false);
38
+
39
+ const [currentPage, setCurrentPage] = useState(1);
40
+ const [pageSize] = useState(100);
41
+ const { wardList, isError, loading, validate, mutate } = useWard();
42
+
43
+ const tableHeaders = [
44
+ {
45
+ header: t("display", "Name"),
46
+ key: "display",
47
+ },
48
+ ];
49
+ const tableRows = useMemo(() => {
50
+ return wardList?.map((entry) => ({
51
+ id: entry.uuid,
52
+ display: entry?.display,
53
+ }));
54
+ }, [wardList]);
55
+
56
+ if (isBedDataLoading || loading) {
57
+ return (
58
+ <>
59
+ <Header route="List of Wards" />
60
+ <div className={styles.widgetCard}>
61
+ <DataTableSkeleton role="progressbar" compact={isDesktop} zebra />
62
+ </div>
63
+ </>
64
+ );
65
+ }
66
+ if (isError) {
67
+ return (
68
+ <>
69
+ <Header route="List of Wards" />
70
+ <div className={styles.widgetCard}>
71
+ <ErrorState error={isError} headerTitle={headerTitle} />
72
+ </div>
73
+ </>
74
+ );
75
+ }
76
+ return (
77
+ <>
78
+ <Header route="List of Wards" />
79
+
80
+ <div className={styles.widgetCard}>
81
+ {showWardModal ? (
82
+ <NewWardForm
83
+ onModalChange={setAddWardModal}
84
+ showModal={showWardModal}
85
+ mutate={mutate}
86
+ />
87
+ ) : null}
88
+ <CardHeader title={headerTitle}>
89
+ <span className={styles.backgroundDataFetchingIndicator}>
90
+ <span>{validate ? <InlineLoading /> : null}</span>
91
+ </span>
92
+ {wardList?.length ? (
93
+ <Button
94
+ kind="ghost"
95
+ renderIcon={(props) => <Add size={16} {...props} />}
96
+ onClick={() => setAddWardModal(true)}
97
+ >
98
+ {t("createWard", "Create Ward")}
99
+ </Button>
100
+ ) : null}
101
+ </CardHeader>
102
+ <DataTable
103
+ rows={tableRows}
104
+ headers={tableHeaders}
105
+ isSortable
106
+ size={isTablet ? "lg" : "sm"}
107
+ useZebraStyles
108
+ >
109
+ {({ rows, headers, getTableProps }) => (
110
+ <TableContainer>
111
+ <Table {...getTableProps()}>
112
+ <TableHead>
113
+ <TableRow>
114
+ {headers.map((header) => (
115
+ <TableHeader>
116
+ {header.header?.content ?? header.header}
117
+ </TableHeader>
118
+ ))}
119
+ </TableRow>
120
+ </TableHead>
121
+ <TableBody>
122
+ {rows.map((row) => (
123
+ <TableRow key={row.id}>
124
+ {row.cells.map((cell) => (
125
+ <TableCell key={cell.id}>
126
+ {cell.value?.content ?? cell.value}
127
+ </TableCell>
128
+ ))}
129
+ </TableRow>
130
+ ))}
131
+ </TableBody>
132
+ </Table>
133
+ {rows.length === 0 ? (
134
+ <div className={styles.tileContainer}>
135
+ <Tile className={styles.tile}>
136
+ <div className={styles.tileContent}>
137
+ <p className={styles.content}>
138
+ {t("No data", "No data to display")}
139
+ </p>
140
+ <p className={styles.helper}>
141
+ {t("checkFilters", "Check the filters above")}
142
+ </p>
143
+ </div>
144
+ <p className={styles.separator}>{t("or", "or")}</p>
145
+ <Button
146
+ kind="ghost"
147
+ size="sm"
148
+ renderIcon={(props) => <Add size={16} {...props} />}
149
+ onClick={() => setAddWardModal(true)}
150
+ >
151
+ {t("createWard", "Create Ward")}
152
+ </Button>
153
+ </Tile>
154
+ </div>
155
+ ) : null}
156
+ <Pagination
157
+ page={currentPage}
158
+ pageSize={pageSize}
159
+ pageSizes={[10, 20, 30, 40, 50]}
160
+ totalItems={wardList.length}
161
+ onChange={({ page, pageSize }) => {
162
+ setCurrentPage(page);
163
+ pageSize(pageSize);
164
+ }}
165
+ />
166
+ </TableContainer>
167
+ )}
168
+ </DataTable>
169
+ </div>
170
+ </>
171
+ );
172
+ };
173
+ export default WardAdministrationTable;
@@ -14,8 +14,14 @@ export const configSchema = {
14
14
  _default: "a73e2ac6-263b-47fc-99fc-e0f2c09fc914",
15
15
  },
16
16
  restrictWardAdministrationToLoginLocation: {
17
- _type: boolean,
17
+ _type: Type.Boolean,
18
18
  _description: "UUID for the inpatient visit",
19
19
  _default: false,
20
20
  },
21
+ patientListForAdmissionUrl: {
22
+ _type: Type.String,
23
+ _description:
24
+ "Endpoint for fetching list of patients eligible for ward admission",
25
+ _default: "",
26
+ },
21
27
  };
package/src/index.ts CHANGED
@@ -55,7 +55,28 @@ export const adminLeftPanelLink = getSyncLifecycle(
55
55
  }),
56
56
  options
57
57
  );
58
+ export const wardLeftPanelLink = getSyncLifecycle(
59
+ createLeftPanelLink({
60
+ name: "ward",
61
+ title: "Wards",
62
+ }),
63
+ options
64
+ );
58
65
 
66
+ export const bedTypeLeftPanelLink = getSyncLifecycle(
67
+ createLeftPanelLink({
68
+ name: "bed-type",
69
+ title: "Bed Type",
70
+ }),
71
+ options
72
+ );
73
+ export const bedTagLeftPanelLink = getSyncLifecycle(
74
+ createLeftPanelLink({
75
+ name: "bed-tag",
76
+ title: "Bed Tag",
77
+ }),
78
+ options
79
+ );
59
80
  export const bedAdmissionDashboardLink = getSyncLifecycle(
60
81
  createDashboardLink({
61
82
  name: "bed-admission",
@@ -6,6 +6,9 @@ import Home from "./home.component";
6
6
  import LeftPanel from "./left-panel/left-panel.component";
7
7
  import WardWithBeds from "./ward-with-beds/ward-with-beds.component";
8
8
  import styles from "./root.scss";
9
+ import BedTagAdministrationTable from "./bed-admission/bed-tag/bed-tag-administration-table.component";
10
+ import BedTypeAdministrationTable from "./bed-admission/bed-type/bed-type-administration-table.component";
11
+ import WardAdministrationTable from "./bed-admission/ward/ward-administration-table.component";
9
12
 
10
13
  const Root: React.FC = () => {
11
14
  const spaBasePath = window.spaBase;
@@ -25,7 +28,10 @@ const Root: React.FC = () => {
25
28
  <Routes>
26
29
  <Route path="/" element={<Home />} />
27
30
  <Route path="/location/:location" element={<WardWithBeds />} />
31
+ <Route path="/ward" element={<WardAdministrationTable />} />
28
32
  <Route path="/administration" element={<BedAdministrationTable />} />
33
+ <Route path="/bed-tag" element={<BedTagAdministrationTable />} />
34
+ <Route path="/bed-type" element={<BedTypeAdministrationTable />} />
29
35
  </Routes>
30
36
  </main>
31
37
  </BrowserRouter>
package/src/routes.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.openmrs.org/routes.schema.json",
3
3
  "backendDependencies": {
4
- "fhir2": "^1.2.0",
4
+ "fhir2": ">=1.2",
5
5
  "webservices.rest": "^2.24.0"
6
6
  },
7
7
  "pages": [
@@ -27,11 +27,26 @@
27
27
  "slot": "bed-management-left-panel-slot",
28
28
  "order": 0
29
29
  },
30
+ {
31
+ "component": "wardLeftPanelLink",
32
+ "name": "ward-left-panel-link",
33
+ "slot": "bed-management-left-panel-slot"
34
+ },
30
35
  {
31
36
  "component": "bedAdmission",
32
37
  "name": "bed-admission-dashboard",
33
38
  "slot": "bed-admission-dashboard-slot"
34
39
  },
40
+ {
41
+ "component": "bedTypeLeftPanelLink",
42
+ "name": "bed-type-left-panel-link",
43
+ "slot": "bed-management-left-panel-slot"
44
+ },
45
+ {
46
+ "component": "bedTagLeftPanelLink",
47
+ "name": "bed-tag-left-panel-link",
48
+ "slot": "bed-management-left-panel-slot"
49
+ },
35
50
  {
36
51
  "name": "bed-admission-dashboard-link",
37
52
  "component": "bedAdmissionDashboardLink",