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

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 (131) 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/6816f0d4.yml +0 -0
  13. package/LICENSE +373 -0
  14. package/README.md +40 -0
  15. package/dist/187.js +1 -0
  16. package/dist/187.js.map +1 -0
  17. package/dist/207.js +1 -0
  18. package/dist/207.js.map +1 -0
  19. package/dist/26.js +2 -0
  20. package/dist/26.js.LICENSE.txt +32 -0
  21. package/dist/26.js.map +1 -0
  22. package/dist/283.js +1 -0
  23. package/dist/283.js.map +1 -0
  24. package/dist/294.js +2 -0
  25. package/dist/294.js.LICENSE.txt +9 -0
  26. package/dist/294.js.map +1 -0
  27. package/dist/330.js +2 -0
  28. package/dist/330.js.LICENSE.txt +44 -0
  29. package/dist/330.js.map +1 -0
  30. package/dist/352.js +1 -0
  31. package/dist/352.js.map +1 -0
  32. package/dist/404.js +1 -0
  33. package/dist/404.js.map +1 -0
  34. package/dist/455.js +2 -0
  35. package/dist/455.js.LICENSE.txt +9 -0
  36. package/dist/455.js.map +1 -0
  37. package/dist/558.js +2 -0
  38. package/dist/558.js.LICENSE.txt +14 -0
  39. package/dist/558.js.map +1 -0
  40. package/dist/574.js +1 -0
  41. package/dist/629.js +1 -0
  42. package/dist/629.js.map +1 -0
  43. package/dist/707.js +1 -0
  44. package/dist/707.js.map +1 -0
  45. package/dist/800.js +2 -0
  46. package/dist/800.js.LICENSE.txt +3 -0
  47. package/dist/800.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/959.js +1 -0
  53. package/dist/959.js.map +1 -0
  54. package/dist/esm-kenyaemr-bed-management-app.js +1 -0
  55. package/dist/esm-kenyaemr-bed-management-app.js.buildmanifest.json +532 -0
  56. package/dist/esm-kenyaemr-bed-management-app.js.map +1 -0
  57. package/dist/main.js +1 -0
  58. package/dist/main.js.map +1 -0
  59. package/dist/routes.json +1 -0
  60. package/i18next-parser.config.js +89 -0
  61. package/jest.config.js +0 -0
  62. package/package.json +112 -0
  63. package/src/__mocks__/react-i18next.js +55 -0
  64. package/src/admin-card-link.component.tsx +27 -0
  65. package/src/assets/landing-page.png +0 -0
  66. package/src/assets/logo.svg +1 -0
  67. package/src/bed-administration/bed-administration-form.component.tsx +326 -0
  68. package/src/bed-administration/bed-administration-form.scss +0 -0
  69. package/src/bed-administration/bed-administration-table.component.tsx +317 -0
  70. package/src/bed-administration/bed-administration-table.scss +112 -0
  71. package/src/bed-administration/bed-administration-types.ts +12 -0
  72. package/src/bed-administration/bed-administration.resource.ts +59 -0
  73. package/src/bed-administration/edit-bed-form.component.tsx +100 -0
  74. package/src/bed-administration/new-bed-form.component.tsx +112 -0
  75. package/src/bed-admission/active-patients/active-patients-table.component.tsx +299 -0
  76. package/src/bed-admission/active-patients/active-visits.resource.ts +171 -0
  77. package/src/bed-admission/active-patients/admission-action-button-styles.scss +0 -0
  78. package/src/bed-admission/active-patients/admission-action-button.component.tsx +26 -0
  79. package/src/bed-admission/active-patients/index.tsx +15 -0
  80. package/src/bed-admission/active-patients/patient-queues.resource.ts +136 -0
  81. package/src/bed-admission/active-patients/styles.scss +284 -0
  82. package/src/bed-admission/active-patients/view-action-menu.component.tsx +33 -0
  83. package/src/bed-admission/admitted-patients/active-admissions.resource.ts +121 -0
  84. package/src/bed-admission/admitted-patients/admitted-patients-table.component.tsx +280 -0
  85. package/src/bed-admission/admitted-patients/admitted-patients.component.tsx +22 -0
  86. package/src/bed-admission/admitted-patients/location-combo-box.component.tsx +55 -0
  87. package/src/bed-admission/admitted-patients/styles.scss +284 -0
  88. package/src/bed-admission/bed-admission-tabs-styles.scss +30 -0
  89. package/src/bed-admission/bed-admission-tabs.component.tsx +69 -0
  90. package/src/bed-admission/bed-admission.component.tsx +15 -0
  91. package/src/bed-admission/bed-admission.resource.ts +35 -0
  92. package/src/bed-admission/bed-layout/bed-layout-list.component.tsx +101 -0
  93. package/src/bed-admission/bed-layout/bed-layout.component.tsx +64 -0
  94. package/src/bed-admission/bed-layout/bed-layout.scss +118 -0
  95. package/src/bed-admission/bed-layout/min-bed-layout.component.tsx +26 -0
  96. package/src/bed-admission/createDashboardLink.tsx +47 -0
  97. package/src/bed-admission/discharged-patients/discharged-patients.componet.tsx +19 -0
  98. package/src/bed-admission/helpers/functions.ts +102 -0
  99. package/src/bed-admission/types.ts +133 -0
  100. package/src/config-schema.ts +21 -0
  101. package/src/declarations.d.ts +7 -0
  102. package/src/empty-state/empty-state.component.tsx +69 -0
  103. package/src/empty-state/empty-state.scss +62 -0
  104. package/src/header/header.component.tsx +51 -0
  105. package/src/header/header.scss +72 -0
  106. package/src/header/illustration.component.tsx +13 -0
  107. package/src/home.component.tsx +15 -0
  108. package/src/home.scss +5 -0
  109. package/src/index.ts +65 -0
  110. package/src/left-panel/left-panel.component.tsx +33 -0
  111. package/src/left-panel/left-panel.scss +41 -0
  112. package/src/left-panel-link.component.tsx +49 -0
  113. package/src/root.component.tsx +35 -0
  114. package/src/root.scss +11 -0
  115. package/src/routes.json +46 -0
  116. package/src/setup-tests.ts +1 -0
  117. package/src/summary/summary.component.tsx +74 -0
  118. package/src/summary/summary.resource.ts +123 -0
  119. package/src/summary/summary.scss +72 -0
  120. package/src/types.ts +152 -0
  121. package/src/ward-card/ward-card.component.tsx +41 -0
  122. package/src/ward-card/ward-card.scss +51 -0
  123. package/src/ward-with-beds/ward-with-beds.component.tsx +186 -0
  124. package/src/ward-with-beds/ward-with-beds.scss +27 -0
  125. package/src/workspace/allocate-bed-workspace.component.tsx +141 -0
  126. package/src/workspace/allocate-bed.scss +117 -0
  127. package/src/workspace/overlay.component.tsx +55 -0
  128. package/src/workspace/overlay.scss +96 -0
  129. package/translations/en.json +7 -0
  130. package/tsconfig.json +23 -0
  131. package/webpack.config.js +1 -0
@@ -0,0 +1,55 @@
1
+ /** At present, this entire mock is boilerplate. */
2
+ import "react";
3
+ import "react-i18next";
4
+
5
+ const hasChildren = (node) =>
6
+ node && (node.children || (node.props && node.props.children));
7
+
8
+ const getChildren = (node) =>
9
+ node && node.children ? node.children : node.props && node.props.children;
10
+
11
+ const renderNodes = (reactNodes) => {
12
+ if (typeof reactNodes === "string") {
13
+ return reactNodes;
14
+ }
15
+
16
+ return Object.keys(reactNodes).map((key, i) => {
17
+ const child = reactNodes[key];
18
+ const isElement = React.isValidElement(child);
19
+
20
+ if (typeof child === "string") {
21
+ return child;
22
+ }
23
+ if (hasChildren(child)) {
24
+ const inner = renderNodes(getChildren(child));
25
+ return React.cloneElement(child, { ...child.props, key: i }, inner);
26
+ }
27
+ if (typeof child === "object" && !isElement) {
28
+ return Object.keys(child).reduce(
29
+ (str, childKey) => `${str}${child[childKey]}`,
30
+ ""
31
+ );
32
+ }
33
+
34
+ return child;
35
+ });
36
+ };
37
+
38
+ const useMock = [(k) => k, {}];
39
+ useMock.t = (k, o) => (o && o.defaultValue) || (typeof o === "string" ? o : k);
40
+ useMock.i18n = {};
41
+
42
+ module.exports = {
43
+ // this mock makes sure any components using the translate HoC receive the t function as a prop
44
+ Trans: ({ children }) => renderNodes(children),
45
+ Translation: ({ children }) => children((k) => k, { i18n: {} }),
46
+ useTranslation: () => useMock,
47
+
48
+ // mock if needed
49
+ I18nextProvider: reactI18next.I18nextProvider,
50
+ initReactI18next: reactI18next.initReactI18next,
51
+ setDefaults: reactI18next.setDefaults,
52
+ getDefaults: reactI18next.getDefaults,
53
+ setI18n: reactI18next.setI18n,
54
+ getI18n: reactI18next.getI18n,
55
+ };
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { Layer, ClickableTile } from "@carbon/react";
4
+ import { ArrowRight } from "@carbon/react/icons";
5
+
6
+ const BedManagementAdminCardLink: React.FC = () => {
7
+ const { t } = useTranslation();
8
+ const header = t("manageBeds", "Manage Beds");
9
+ return (
10
+ <Layer>
11
+ <ClickableTile
12
+ href={window.getOpenmrsSpaBase() + "bed-management/summary"}
13
+ rel="noopener noreferrer"
14
+ >
15
+ <div>
16
+ <div className="heading">{header}</div>
17
+ <div className="content">{t("bedManagement", "Bed Management")}</div>
18
+ </div>
19
+ <div className="iconWrapper">
20
+ <ArrowRight size={16} />
21
+ </div>
22
+ </ClickableTile>
23
+ </Layer>
24
+ );
25
+ };
26
+
27
+ export default BedManagementAdminCardLink;
Binary file
@@ -0,0 +1 @@
1
+ <svg width="320" height="100" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#409184" d="M0 0h320v100H0z"/><g fill-rule="nonzero"><path d="M57.97 55.541c0 6.26-5.85 9.37-12.48 9.37-6.63 0-12.49-3.11-12.49-9.37v-21.19s5.56 0 5.56 2.7v17.88c0 3.73 2.86 5.68 6.93 5.68s6.93-1.95 6.93-5.68v-20.58s5.56 0 5.56 2.7v18.49h-.01Zm48.45-6.14c0-1.49-.83-2.82-4.02-2.82-3.48 0-6.64 1.2-6.64 4.69-1.2-1.62-1.58-2.9-1.58-4.02 0-3.61 4.85-4.69 8.25-4.69 6.1 0 9.33 2.57 9.33 7.09v15.18c-1.08-.54-2.16-.66-3.19-.66-2.07 0-4.15.75-6.51.75-4.27 0-8.46-1.58-8.46-6.51 0-7.76 11.12-5.73 12.82-9.01Zm.12 4.23c-.95 2.2-7.59 1-7.59 4.69 0 1.87 1.37 2.82 3.73 2.82 2.2 0 3.86-.75 3.86-.75v-6.76Zm23.27-3.61c0-2.2-1.04-3.44-3.98-3.44-2.12 0-3.94.58-3.94.58v17.54s-5.39 0-5.39-2.7v-19.44s1.62.87 3.73.87c2.03 0 3.94-.87 6.18-.87 4.27 0 8.79 1.45 8.79 6.84v15.3s-5.39-.08-5.39-2.7v-11.98Zm23.27-17.21c.37 0 5.39-.04 5.39 3.11v28.99c-1.08-.54-2.2-.71-3.32-.71-2.2 0-4.31.71-6.05.71-5.93 0-9.33-2.61-9.33-7.22v-7.96c0-4.48 3.86-7.17 8.29-7.17 3.44 0 5.35 1.62 5.35 1.62s-.33-1.37-.33-2.41v-8.96Zm0 17.13c0-2.03-2.24-3.44-4.48-3.44-1.99 0-3.44 1.16-3.44 3.86v6.72c0 2.61 1 3.9 4.44 3.9 1.87 0 3.48-.5 3.48-.5v-10.54Zm22.44-.54c0-1.49-.83-2.82-4.02-2.82-3.48 0-6.64 1.2-6.64 4.69-1.2-1.62-1.58-2.9-1.58-4.02 0-3.61 4.85-4.69 8.25-4.69 6.1 0 9.33 2.57 9.33 7.09v15.18c-1.08-.54-2.16-.66-3.19-.66-2.07 0-4.15.75-6.51.75-4.27 0-8.46-1.58-8.46-6.51 0-7.76 11.12-5.73 12.82-9.01Zm.12 4.23c-.95 2.2-7.59 1-7.59 4.69 0 1.87 1.37 2.82 3.73 2.82 2.2 0 3.86-.75 3.86-.75v-6.76Zm17.3-2.53v8.29h14.81c0 .29-.08 5.02-3.86 5.02h-12.73s-5.35 0-5.35-3.19v-26.95h21.94s0 5.06-3.86 5.06h-10.95v6.72h7.8c4.11 0 5.35-.66 5.35-.66 0 2.86-.58 5.72-4.69 5.72h-8.46v-.01Zm41.93-.16c0-2.03.54-4.65.54-4.65l-6.3 13.4s-4.31 0-6.3-3.11l-4.44-10.04s.46 2.36.46 4.4v13.89s-7.13 0-7.13-3.19v-27.37h4.4c.25 0 3.36-.04 4.65 2.78l6.1 13.52 7.63-16.3c1.58 0 7.55 0 7.55 3.19v27.37s-7.13 0-7.13-3.19v-10.7h-.03Zm27 .41c5.23 3.44 6.68 8.38 9.75 12.73 0 0-2.53.66-3.53.66-1.74 0-4.15-.54-5.64-2.95-1.7-2.7-3.82-7.92-7.92-9.7v12.73s-7.13-.12-7.13-3.19v-27.36h10.41c6.72 0 11.57 1.91 11.57 7.88v1.24c0 4.35-2.7 7.88-7.51 7.96Zm-7.34-12.03v7.51h3.61c3.03 0 4.11-1.33 4.11-4.06 0-2.7-1.45-3.44-4.44-3.44h-3.28v-.01Z" fill="#FDFFFF"/><path d="M103.92 73.601c0-.59.07-1.22.07-1.22l-3.51 7.12s-.43 0-.83-.64l-3.09-6.52s.07.67.07 1.26v8.17s-.84 0-.84-.64v-9.57h.71s.57 0 .88.68l2.87 6.1 3.26-6.77s1.25.01 1.25.64v9.57s-.84 0-.84-.64v-7.54Zm9.66 6.76c0 1-1.44 1.45-2.73 1.45-1.67 0-2.74-.83-2.74-2.25v-3.01c0-1.41.94-2.25 2.67-2.25s2.73.84 2.73 2.1c0 1.15-.78 2.03-2.8 2.03-.94 0-1.8-.38-1.8-.38v1.29c0 1.09.46 1.68 1.94 1.68 1.32 0 2.39-.52 2.39-1.59.26.35.34.65.34.93Zm-4.66-3.05c-.06.03 1 .33 1.73.33 1.54 0 2.07-.48 2.07-1.25 0-.8-.48-1.35-1.9-1.35-1.54 0-1.9.64-1.9 1.71v.56Zm12.24-6.41c.13 0 .8-.01.8.77v10.03c-.26-.1-.52-.14-.77-.14-.59 0-1.32.25-2.04.25-1.67 0-2.64-.87-2.64-2.2v-3.1c0-1.38 1.09-2.19 2.36-2.19 2.03 0 2.45.9 2.45.9s-.16-.28-.16-1.52v-2.8Zm0 5.67c0-.9-1.06-1.51-2.1-1.51-1 0-1.75.51-1.75 1.65v2.67c0 1.12.51 1.67 2.1 1.67 1.07 0 1.75-.35 1.75-.35v-4.13Zm4.1-4.72h.75c.13 0 .16.12.16.2v.8h-.75c-.09 0-.16-.1-.16-.19v-.81Zm.06 2.52c.09 0 .8.03.8.64v6.73s-.8 0-.8-.64v-6.73Zm9.58 5.97c0 1.01-1.38 1.46-2.68 1.46-1.74 0-2.88-.83-2.88-2.25v-3.01c0-1.41 1.01-2.25 2.74-2.25 1.51 0 2.51.57 2.51 1.44 0 .28-.1.58-.32.87 0-.91-.81-1.52-2.22-1.52-1.48 0-1.91.71-1.91 1.62v2.71c0 .96.68 1.61 2.09 1.61 1.32 0 2.32-.52 2.32-1.59.22.33.35.65.35.91Zm7.22-3.81c0-.84-.36-1.45-1.83-1.45-1.41 0-2.23.61-2.23 1.52-.22-.29-.3-.61-.3-.87 0-.86 1.01-1.44 2.54-1.44 1.8 0 2.62.87 2.62 2.28v5.13c-.26-.1-.64-.14-.88-.14-.45 0-1.17.25-1.78.25-1.81 0-2.74-.86-2.74-2.06-.01-2.71 4.11-1.74 4.6-3.22Zm-1.75 4.54c1.07 0 1.75-.38 1.75-.38v-3.22c-.29 1.01-3.78.39-3.78 2.29 0 .76.59 1.31 2.03 1.31Zm5.76-10.21c.06 0 .8.01.8.64v7.8c0 1.12.25 2.16.94 2.16 0 0-.19.28-.57.28-.81 0-1.17-.88-1.17-2.06v-8.82Zm15.67 3.52c0 1.74-1.3 2.52-3.1 2.45 2.12.67 3.04 3.96 3.65 4.91-.67.09-.94.01-1.35-.77-1.23-2.41-1.87-3.94-4.41-4.13v4.93s-.84-.01-.84-.64v-9.57h2.81c1.87 0 3.23.62 3.23 2.38v.44h.01Zm-5.2-2.03v3.78h2.09c1.68 0 2.28-.71 2.28-1.97 0-1.28-.78-1.81-2.39-1.81h-1.98Zm13.45 8.01c0 1-1.44 1.45-2.73 1.45-1.67 0-2.74-.83-2.74-2.25v-3.01c0-1.41.94-2.25 2.67-2.25s2.73.84 2.73 2.1c0 1.15-.78 2.03-2.8 2.03-.94 0-1.8-.38-1.8-.38v1.29c0 1.09.46 1.68 1.94 1.68 1.32 0 2.39-.52 2.39-1.59.25.35.34.65.34.93Zm-4.67-3.05c-.06.03 1 .33 1.73.33 1.54 0 2.07-.48 2.07-1.25 0-.8-.48-1.35-1.9-1.35-1.54 0-1.9.64-1.9 1.71v.56Zm13.16 3.03c0 1.01-1.38 1.46-2.68 1.46-1.74 0-2.88-.83-2.88-2.25v-3.01c0-1.41 1.01-2.25 2.74-2.25 1.51 0 2.51.57 2.51 1.44 0 .28-.1.58-.32.87 0-.91-.81-1.52-2.22-1.52-1.48 0-1.91.71-1.91 1.62v2.71c0 .96.68 1.61 2.09 1.61 1.32 0 2.32-.52 2.32-1.59.22.33.35.65.35.91Zm8.67-.78c0 1.42-.94 2.25-2.94 2.25-2.01 0-2.96-.83-2.96-2.25v-3.01c0-1.41.94-2.25 2.96-2.25 2 0 2.94.84 2.94 2.25v3.01Zm-.8-2.8c0-1.07-.36-1.71-2.15-1.71-1.8 0-2.16.64-2.16 1.71v2.58c0 1.09.36 1.72 2.16 1.72 1.78 0 2.15-.64 2.15-1.72v-2.58Zm6.45-1.61c-.62 0-1.29.12-1.64.3v6.28s-.8 0-.8-.64v-6.68c.29.14.46.2.7.2.59 0 1.3-.32 2.06-.32 1.19 0 1.64.67 1.12 1.75-.03-.7-.7-.89-1.44-.89Zm8.49-4.25c.13 0 .8-.01.8.77v10.03c-.26-.1-.52-.14-.77-.14-.59 0-1.32.25-2.04.25-1.67 0-2.64-.87-2.64-2.2v-3.1c0-1.38 1.09-2.19 2.36-2.19 2.03 0 2.45.9 2.45.9s-.16-.28-.16-1.52v-2.8Zm0 5.67c0-.9-1.06-1.51-2.1-1.51-1 0-1.75.51-1.75 1.65v2.67c0 1.12.51 1.67 2.1 1.67 1.07 0 1.75-.35 1.75-.35v-4.13Zm3.73-.07c0-1.45.91-2.2 2.67-2.2 1.29 0 2.54.36 2.54 1.39 0 .3-.12.65-.35 1.07.01-.07.01-.16.01-.23 0-.87-.61-1.48-2.2-1.48-1.42 0-1.87.51-1.87 1.38 0 2.1 4.67-.12 4.67 3.25 0 1.25-.94 2.13-2.8 2.13-1.26 0-2.64-.3-2.64-1.46 0-.26.07-.55.22-.9 0 .91.71 1.61 2.42 1.61 1.58 0 2-.68 2-1.45 0-2.31-4.6-.15-4.67-3.11Zm17.1-5.12c1.52 0 3.3.33 3.3 1.67 0 .28-.09.64-.26 1.04 0-1.51-1.57-1.9-3.15-1.9-1.54 0-2.78.42-2.78 1.94 0 2.94 6.51.51 6.51 4.68 0 2.03-1.52 2.99-3.68 2.99-1.52 0-3.48-.45-3.48-1.7 0-.29.07-.65.23-1.06 0 1.46 1.67 1.94 3.33 1.94 1.83 0 2.72-.83 2.72-2.13 0-3.26-6.51-.91-6.51-4.65.01-2.17 1.8-2.82 3.77-2.82Zm11.01 6.16.26-2.45c.06-.59.55-.65.84-.7l-.28 2.8c-.19 1.97-1.26 3.15-2.07 3.77l-.57.44c-1.04.81-1.77 1.33-1.77 2.46 0 .36.12.78.33 1.29-.06.01-.15.03-.22.03-.39 0-.94-.23-.94-1.38 0-1.26 1-2.17 2.06-2.88-.7-.44-1.91-1.7-2.12-3.73l-.29-2.81s.77 0 .84.64l.29 2.52c.2 1.8 1.81 2.94 1.81 2.94s1.65-1.21 1.83-2.94Zm3.45-1.04c0-1.45.91-2.2 2.67-2.2 1.29 0 2.54.36 2.54 1.39 0 .3-.12.65-.35 1.07.01-.07.01-.16.01-.23 0-.87-.61-1.48-2.2-1.48-1.42 0-1.87.51-1.87 1.38 0 2.1 4.67-.12 4.67 3.25 0 1.25-.94 2.13-2.8 2.13-1.26 0-2.64-.3-2.64-1.46 0-.26.07-.55.22-.9 0 .91.71 1.61 2.42 1.61 1.58 0 2-.68 2-1.45 0-2.31-4.6-.15-4.67-3.11Zm8.39-3.93s.8.01.8.64v1.43h3.03s-.01.78-.54.78h-2.49v3.84c0 1.09.59 1.75 1.75 1.75.94 0 1.75-.59 1.75-1.48.19.35.26.61.26.87 0 .94-.99 1.39-2.03 1.39-1.39 0-2.54-.75-2.54-2.17v-7.05h.01Zm12.31 7.79c0 1-1.44 1.45-2.73 1.45-1.67 0-2.74-.83-2.74-2.25v-3.01c0-1.41.94-2.25 2.67-2.25s2.73.84 2.73 2.1c0 1.15-.78 2.03-2.8 2.03-.94 0-1.8-.38-1.8-.38v1.29c0 1.09.46 1.68 1.94 1.68 1.32 0 2.39-.52 2.39-1.59.25.35.34.65.34.93Zm-4.67-3.05c-.06.03 1 .33 1.73.33 1.54 0 2.07-.48 2.07-1.25 0-.8-.48-1.35-1.9-1.35-1.54 0-1.9.64-1.9 1.71v.56Zm12.39-.71c0-1.1-.62-1.52-1.93-1.52-1.22 0-1.93.35-1.93.35v6.31s-.8 0-.8-.62v-6.7s.36.2.65.2c.75 0 1.44-.32 2.28-.32 1.7 0 2.16.87 2.16.87.41-.38 1.2-.86 2.52-.86 1.17 0 2.49.58 2.49 2.09v5.33s-.8-.01-.8-.62v-4.55c0-1.03-.61-1.46-1.94-1.46-.91 0-1.91.46-1.91 1.26v5.38s-.8 0-.8-.62v-4.52h.01Z" fill="#FAFCFC"/><path d="M276.95 30.661c.3-.52.49-1.1.7-1.71.21-.63.43-1.28.78-1.89a5.25 5.25 0 0 1 1.93-1.9v-4.96c0-.63.12-3.99 0-6.2-1.85-.08-6.36 3.4-6.81 6.2v5.91h-5.91c-.63 0-1.14.51-1.14 1.14v4.54c0 .63.51 1.14 1.14 1.14h5.87c1.41-.17 2.74-1.03 3.44-2.27Z" fill="#FFF"/><path d="M286.28 26.811h-5.9c-.5.36-.93.82-1.24 1.36-.31.53-.51 1.12-.72 1.74-.21.62-.42 1.26-.76 1.85-.84 1.47-2.42 2.49-4.1 2.67v12.31c2.37-.49 6.93-2.44 6.81-7.21v-5.91h5.91c.63 0 1.14-.51 1.14-1.14v-4.54c-.01-.63-.52-1.13-1.14-1.13Z" fill="#FDFFFF"/><path d="M66.09 61.081c-1.51-1.46-2.36-4.37-2.36-6.45v-2.64c0-6.67 5.55-9.14 11.22-9.14 3.08 0 6 1.18 8.75 1.18 1.29 0 2.8-.34 4.77-1.12v11.72c0 6.22-4.32 9.93-12.34 9.93-4.21 0-7.07-1.57-7.07-1.57-.17.56-.34 1.46-.34 2.19 0 2.52 2.58 2.92 6.45 2.92h1.85c5.94 0 12.45-.06 12.45 7.96 0 5.94-4.21 9.93-13.35 9.93-7.63 0-12.28-2.41-12.28-6.11 0-1.46.56-2.97 1.91-4.71.5 4.43 5.16 5.5 9.87 5.5 4.99 0 6.73-1.63 6.73-4.21 0-2.63-2.24-2.92-5.5-2.92H74.1c-5.89 0-11.05-.73-11.05-6.39.01-2.25 1.25-3.94 3.04-6.07Zm10.04-1.85c4.15 0 5.1-1.96 5.1-5.44v-4.77s-2.52-.95-4.99-.95c-3.81 0-5.27 1.35-5.27 4.77v.95c0 3.48.95 5.44 5.16 5.44Z" fill="#FFF"/></g></g></svg>
@@ -0,0 +1,326 @@
1
+ import React, { useState } from "react";
2
+ import capitalize from "lodash-es/capitalize";
3
+ import { z } from "zod";
4
+ import { useForm, Controller } from "react-hook-form";
5
+ import { zodResolver } from "@hookform/resolvers/zod";
6
+ import {
7
+ Button,
8
+ ComboBox,
9
+ ComposedModal,
10
+ Form,
11
+ FormGroup,
12
+ ModalBody,
13
+ ModalFooter,
14
+ ModalHeader,
15
+ NumberInput,
16
+ Select,
17
+ SelectItem,
18
+ Stack,
19
+ TextArea,
20
+ TextInput,
21
+ InlineNotification,
22
+ } from "@carbon/react";
23
+ import { useTranslation } from "react-i18next";
24
+ import { Location } from "@openmrs/esm-framework";
25
+ import type { BedType, InitialData } from "../types";
26
+ import { BedAdministrationData } from "./bed-administration-types";
27
+
28
+ const numberInString = z.string().transform((val, ctx) => {
29
+ const parsed = parseInt(val);
30
+ if (isNaN(parsed) || parsed < 1) {
31
+ ctx.addIssue({
32
+ code: z.ZodIssueCode.custom,
33
+ message: "Please enter a valid number",
34
+ });
35
+ return z.NEVER;
36
+ }
37
+ return val;
38
+ });
39
+
40
+ const BedAdministrationSchema = z.object({
41
+ bedId: z.string().min(5).max(255),
42
+ description: z.string().max(255),
43
+ bedRow: numberInString,
44
+ bedColumn: numberInString,
45
+ location: z
46
+ .object({ display: z.string(), uuid: z.string() })
47
+ .refine((value) => value.display != "", "Please select a valid location"),
48
+ occupancyStatus: z
49
+ .string()
50
+ .refine((value) => value != "", "Please select a valid occupied status"),
51
+ bedType: z
52
+ .string()
53
+ .refine((value) => value != "", "Please select a valid bed type"),
54
+ });
55
+
56
+ interface BedAdministrationFormProps {
57
+ showModal: boolean;
58
+ onModalChange: (showModal: boolean) => void;
59
+ availableBedTypes: Array<BedType>;
60
+ allLocations: Location[];
61
+ handleCreateQuestion?: (formData: BedAdministrationData) => void;
62
+ headerTitle: string;
63
+ occupancyStatuses: string[];
64
+ initialData: InitialData;
65
+ }
66
+
67
+ interface ErrorType {
68
+ message: string;
69
+ }
70
+
71
+ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
72
+ showModal,
73
+ onModalChange,
74
+ availableBedTypes,
75
+ allLocations,
76
+ handleCreateQuestion,
77
+ headerTitle,
78
+ occupancyStatuses,
79
+ initialData,
80
+ }) => {
81
+ const { t } = useTranslation();
82
+ const [occupancyStatus, setOccupancyStatus] = useState(
83
+ capitalize(initialData.status)
84
+ );
85
+ const [selectedBedType] = useState(initialData.bedType.name);
86
+ const [showErrorNotification, setShowErrorNotification] = useState(false);
87
+ const [formStateError, setFormStateError] = useState("");
88
+
89
+ const filterLocationNames = (location) => {
90
+ return (
91
+ location.item.display
92
+ ?.toLowerCase()
93
+ .includes(location?.inputValue?.toLowerCase()) ?? []
94
+ );
95
+ };
96
+
97
+ const {
98
+ handleSubmit,
99
+ control,
100
+ formState: { isDirty },
101
+ } = useForm<BedAdministrationData>({
102
+ mode: "all",
103
+ resolver: zodResolver(BedAdministrationSchema),
104
+ defaultValues: {
105
+ bedId: initialData.bedNumber || "",
106
+ description: initialData.description || "",
107
+ bedRow: initialData.row.toString() || "0",
108
+ bedColumn: initialData.column.toString() || "0",
109
+ location: initialData.location || {},
110
+ occupancyStatus: capitalize(initialData.status) || occupancyStatus,
111
+ bedType: initialData.bedType.name || "",
112
+ },
113
+ });
114
+
115
+ const onSubmit = (formData: BedAdministrationData) => {
116
+ const result = BedAdministrationSchema.safeParse(formData);
117
+ if (result.success) {
118
+ setShowErrorNotification(false);
119
+ handleCreateQuestion(formData);
120
+ }
121
+ };
122
+
123
+ const onError = (error: { [key: string]: ErrorType }) => {
124
+ setFormStateError(Object.entries(error)[0][1].message);
125
+ setShowErrorNotification(true);
126
+ };
127
+
128
+ return (
129
+ <ComposedModal
130
+ open={showModal}
131
+ onClose={() => onModalChange(false)}
132
+ preventCloseOnClickOutside
133
+ >
134
+ <ModalHeader title={headerTitle} />
135
+ <Form onSubmit={handleSubmit(onSubmit, onError)}>
136
+ <ModalBody hasScrollingContent>
137
+ <Stack gap={3}>
138
+ <FormGroup legendText={""}>
139
+ <Controller
140
+ name="bedId"
141
+ control={control}
142
+ render={({ field, fieldState }) => (
143
+ <>
144
+ <TextInput
145
+ id="bedId"
146
+ labelText={t("bedId", "Bed number")}
147
+ placeholder={t("bedIdPlaceholder", "e.g. BMW-201")}
148
+ invalidText={fieldState.error?.message}
149
+ {...field}
150
+ />
151
+ </>
152
+ )}
153
+ />
154
+ </FormGroup>
155
+
156
+ <FormGroup>
157
+ <Controller
158
+ name="description"
159
+ control={control}
160
+ render={({ field, fieldState }) => (
161
+ <>
162
+ <TextArea
163
+ rows={2}
164
+ id="description"
165
+ invalidText={fieldState?.error?.message}
166
+ labelText={t("description", "Bed description")}
167
+ {...field}
168
+ placeholder={t(
169
+ "description",
170
+ "Enter the bed description"
171
+ )}
172
+ />
173
+ </>
174
+ )}
175
+ />
176
+ </FormGroup>
177
+
178
+ <FormGroup>
179
+ <Controller
180
+ name="bedRow"
181
+ control={control}
182
+ render={({ fieldState, field }) => (
183
+ <NumberInput
184
+ hideSteppers
185
+ id="bedRow"
186
+ label="Bed row"
187
+ labelText="Bed row"
188
+ invalidText={fieldState?.error?.message}
189
+ {...field}
190
+ />
191
+ )}
192
+ />
193
+ </FormGroup>
194
+
195
+ <FormGroup>
196
+ <Controller
197
+ name="bedColumn"
198
+ control={control}
199
+ render={({ field, fieldState }) => (
200
+ <NumberInput
201
+ hideSteppers
202
+ id="bedColumn"
203
+ label="Bed column"
204
+ labelText="Bed column"
205
+ invalidText={fieldState.error?.message}
206
+ {...field}
207
+ />
208
+ )}
209
+ />
210
+ </FormGroup>
211
+
212
+ <FormGroup>
213
+ <Controller
214
+ name="location"
215
+ control={control}
216
+ render={({
217
+ fieldState,
218
+ field: { onChange, onBlur, value, ref },
219
+ }) => (
220
+ <ComboBox
221
+ aria-label={t("location", "Location")}
222
+ shouldFilterItem={filterLocationNames}
223
+ id="location"
224
+ label={t("location", "Location")}
225
+ invalidText={fieldState?.error?.message}
226
+ items={allLocations}
227
+ onBlur={onBlur}
228
+ ref={ref}
229
+ selectedItem={value}
230
+ onChange={({ selectedItem }) => onChange(selectedItem)}
231
+ itemToString={(location) => location?.display ?? ""}
232
+ placeholder={t(
233
+ "selectBedLocation",
234
+ "Select a bed location"
235
+ )}
236
+ titleText={t("bedLocation", "Location")}
237
+ />
238
+ )}
239
+ />
240
+ </FormGroup>
241
+
242
+ <FormGroup>
243
+ <Controller
244
+ name="occupancyStatus"
245
+ control={control}
246
+ render={({ field, fieldState }) => (
247
+ <Select
248
+ id="occupancyStatus"
249
+ labelText={t("occupancyStatus", "Occupied Status")}
250
+ invalidText={fieldState.error?.message}
251
+ defaultValue={occupancyStatus}
252
+ onChange={(event) => setOccupancyStatus(event.target.value)}
253
+ value={occupancyStatus}
254
+ {...field}
255
+ >
256
+ <SelectItem
257
+ text={t("chooseOccupiedStatus", "Choose occupied status")}
258
+ value=""
259
+ />
260
+ {occupancyStatuses.map((occupancyStatus, index) => (
261
+ <SelectItem
262
+ text={t("occupancyStatus", `${occupancyStatus}`)}
263
+ value={t("occupancyStatus", `${occupancyStatus}`)}
264
+ key={`occupancyStatus-${index}`}
265
+ />
266
+ ))}
267
+ </Select>
268
+ )}
269
+ />
270
+ </FormGroup>
271
+
272
+ <FormGroup>
273
+ <Controller
274
+ name="bedType"
275
+ control={control}
276
+ render={({ field }) => (
277
+ <Select
278
+ id="bedType"
279
+ labelText={t("bedType", "Bed type")}
280
+ invalidText={t("required", "Required")}
281
+ defaultValue={selectedBedType}
282
+ {...field}
283
+ >
284
+ <SelectItem
285
+ text={t("chooseBedtype", "Choose a bed type")}
286
+ />
287
+ {availableBedTypes.map((bedType, index) => (
288
+ <SelectItem
289
+ text={bedType.name}
290
+ value={bedType.name}
291
+ key={`bedType-${index}`}
292
+ >
293
+ {bedType.name}
294
+ </SelectItem>
295
+ ))}
296
+ </Select>
297
+ )}
298
+ />
299
+ </FormGroup>
300
+ {showErrorNotification && (
301
+ <InlineNotification
302
+ lowContrast
303
+ title={t("error", "Error")}
304
+ style={{ minWidth: "100%", margin: "0rem", padding: "0rem" }}
305
+ role="alert"
306
+ kind="error"
307
+ subtitle={t("pleaseFillField", formStateError) + "."}
308
+ onClose={() => setShowErrorNotification(false)}
309
+ />
310
+ )}
311
+ </Stack>
312
+ </ModalBody>
313
+ <ModalFooter>
314
+ <Button onClick={() => onModalChange(false)} kind="secondary">
315
+ {t("cancel", "Cancel")}
316
+ </Button>
317
+ <Button disabled={!isDirty} type="submit">
318
+ <span>{t("save", "Save")}</span>
319
+ </Button>
320
+ </ModalFooter>
321
+ </Form>
322
+ </ComposedModal>
323
+ );
324
+ };
325
+
326
+ export default BedAdministrationForm;