@openmrs/esm-fast-data-entry-app 1.0.0-pre.9 → 1.0.1-pre.10

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 (134) hide show
  1. package/.eslintrc.js +10 -0
  2. package/.husky/pre-push +1 -6
  3. package/.tx/config +9 -0
  4. package/.yarn/plugins/@yarnpkg/plugin-version.cjs +550 -0
  5. package/.yarn/versions/45b499b6.yml +0 -0
  6. package/README.md +39 -12
  7. package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
  8. package/docs/config-icrc-forms.png +0 -0
  9. package/docs/config-other-forms.png +0 -0
  10. package/docs/configuring-form-categories.md +77 -0
  11. package/docs/fde-workflow.mov +0 -0
  12. package/docs/form-workflow-state-diagram.png +0 -0
  13. package/jest.config.json +20 -18
  14. package/package.json +97 -106
  15. package/src/FormBootstrap.tsx +151 -0
  16. package/src/Root.tsx +14 -3
  17. package/src/add-group-modal/AddGroupModal.tsx +209 -0
  18. package/src/add-group-modal/styles.scss +35 -0
  19. package/src/config-schema.ts +63 -31
  20. package/src/context/FormWorkflowContext.tsx +114 -0
  21. package/src/context/FormWorkflowReducer.ts +277 -0
  22. package/src/context/GroupFormWorkflowContext.tsx +141 -0
  23. package/src/context/GroupFormWorkflowReducer.ts +272 -0
  24. package/src/empty-state/EmptyDataIllustration.tsx +51 -0
  25. package/src/empty-state/EmptyState.tsx +33 -0
  26. package/src/empty-state/styles.scss +55 -0
  27. package/src/form-entry-workflow/FormEntryWorkflow.tsx +230 -0
  28. package/src/form-entry-workflow/form-review-card/FormReviewCard.tsx +50 -0
  29. package/src/form-entry-workflow/form-review-card/index.ts +3 -0
  30. package/src/form-entry-workflow/form-review-card/styles.scss +39 -0
  31. package/src/form-entry-workflow/index.ts +3 -0
  32. package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +9 -0
  33. package/src/form-entry-workflow/patient-banner/PatientBanner.tsx +86 -0
  34. package/src/form-entry-workflow/patient-banner/index.ts +3 -0
  35. package/src/form-entry-workflow/patient-banner/styles.scss +45 -0
  36. package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +63 -0
  37. package/src/form-entry-workflow/patient-search-header/index.ts +3 -0
  38. package/src/form-entry-workflow/patient-search-header/styles.scss +22 -0
  39. package/src/form-entry-workflow/styles.scss +64 -0
  40. package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +35 -0
  41. package/src/form-entry-workflow/workflow-review/index.ts +3 -0
  42. package/src/form-entry-workflow/workflow-review/styles.scss +34 -0
  43. package/src/forms-app-menu-link.tsx +3 -2
  44. package/src/forms-page/FormsPage.tsx +129 -0
  45. package/src/forms-page/forms-table/FormsTable.tsx +131 -0
  46. package/src/forms-page/forms-table/index.ts +3 -0
  47. package/src/forms-page/forms-table/styles.scss +20 -0
  48. package/src/forms-page/index.ts +3 -0
  49. package/src/forms-page/styles.scss +11 -0
  50. package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +413 -0
  51. package/src/group-form-entry-workflow/group-banner/GroupBanner.test.tsx +9 -0
  52. package/src/group-form-entry-workflow/group-banner/GroupBanner.tsx +45 -0
  53. package/src/group-form-entry-workflow/group-banner/index.ts +3 -0
  54. package/src/group-form-entry-workflow/group-banner/styles.scss +60 -0
  55. package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +106 -0
  56. package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +63 -0
  57. package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +93 -0
  58. package/src/group-form-entry-workflow/group-search/compact-group-result.scss +64 -0
  59. package/src/group-form-entry-workflow/group-search/compact-group-search.scss +35 -0
  60. package/src/group-form-entry-workflow/group-search/group-search.scss +94 -0
  61. package/src/group-form-entry-workflow/group-search/mock-group-data.ts +79 -0
  62. package/src/group-form-entry-workflow/group-search/useGroupSearch.ts +14 -0
  63. package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +42 -0
  64. package/src/group-form-entry-workflow/group-search-header/index.ts +3 -0
  65. package/src/group-form-entry-workflow/group-search-header/styles.scss +20 -0
  66. package/src/group-form-entry-workflow/index.ts +3 -0
  67. package/src/group-form-entry-workflow/styles.scss +86 -0
  68. package/src/hooks/index.ts +6 -0
  69. package/src/hooks/useFormState.ts +23 -0
  70. package/src/hooks/useGetAllForms.ts +45 -0
  71. package/src/hooks/useGetEncounter.ts +21 -0
  72. package/src/hooks/useGetPatient.ts +23 -0
  73. package/src/hooks/useKeyPress.ts +31 -0
  74. package/src/hooks/usePostCohort.ts +18 -0
  75. package/src/index.ts +20 -4
  76. package/src/patient-card/PatientCard.tsx +67 -0
  77. package/src/patient-card/index.ts +3 -0
  78. package/src/patient-card/styles.scss +45 -0
  79. package/translations/en.json +49 -4
  80. package/tsconfig.json +26 -23
  81. package/.eslintrc +0 -4
  82. package/.github/workflows/node.js.yml +0 -79
  83. package/.husky/pre-commit +0 -6
  84. package/dist/24.js +0 -3
  85. package/dist/24.js.LICENSE.txt +0 -16
  86. package/dist/24.js.map +0 -1
  87. package/dist/294.js +0 -3
  88. package/dist/294.js.LICENSE.txt +0 -14
  89. package/dist/294.js.map +0 -1
  90. package/dist/296.js +0 -2
  91. package/dist/296.js.map +0 -1
  92. package/dist/299.js +0 -2
  93. package/dist/299.js.map +0 -1
  94. package/dist/382.js +0 -3
  95. package/dist/382.js.LICENSE.txt +0 -8
  96. package/dist/382.js.map +0 -1
  97. package/dist/415.js +0 -2
  98. package/dist/415.js.map +0 -1
  99. package/dist/574.js +0 -1
  100. package/dist/595.js +0 -3
  101. package/dist/595.js.LICENSE.txt +0 -1
  102. package/dist/595.js.map +0 -1
  103. package/dist/69.js +0 -2
  104. package/dist/69.js.map +0 -1
  105. package/dist/735.js +0 -3
  106. package/dist/735.js.LICENSE.txt +0 -29
  107. package/dist/735.js.map +0 -1
  108. package/dist/777.js +0 -2
  109. package/dist/777.js.map +0 -1
  110. package/dist/860.js +0 -2
  111. package/dist/860.js.map +0 -1
  112. package/dist/906.js +0 -2
  113. package/dist/906.js.map +0 -1
  114. package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +0 -369
  115. package/dist/openmrs-esm-fast-data-entry-app.js.map +0 -1
  116. package/dist/openmrs-esm-fast-data-entry-app.old +0 -2
  117. package/src/boxes/extensions/blue-box.tsx +0 -15
  118. package/src/boxes/extensions/box.scss +0 -23
  119. package/src/boxes/extensions/brand-box.tsx +0 -15
  120. package/src/boxes/extensions/red-box.tsx +0 -15
  121. package/src/boxes/slot/boxes.css +0 -23
  122. package/src/boxes/slot/boxes.tsx +0 -19
  123. package/src/forms/FormsRoot.tsx +0 -32
  124. package/src/forms/FormsTable.tsx +0 -64
  125. package/src/forms/mockData.ts +0 -43
  126. package/src/greeter/greeter.css +0 -4
  127. package/src/greeter/greeter.test.tsx +0 -29
  128. package/src/greeter/greeter.tsx +0 -25
  129. package/src/hello.css +0 -3
  130. package/src/hello.test.tsx +0 -45
  131. package/src/hello.tsx +0 -30
  132. package/src/patient-getter/patient-getter.resource.ts +0 -31
  133. package/src/patient-getter/patient-getter.test.tsx +0 -28
  134. package/src/patient-getter/patient-getter.tsx +0 -28
@@ -0,0 +1,93 @@
1
+ import React from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { Layer, Tile } from "@carbon/react";
4
+ import styles from "./group-search.scss";
5
+ import { EmptyDataIllustration } from "../../empty-state/EmptyDataIllustration";
6
+ import { useGroupSearch } from "./useGroupSearch";
7
+ import CompactGroupResults, {
8
+ SearchResultSkeleton,
9
+ } from "./CompactGroupResults";
10
+ import { GroupType } from "../../context/GroupFormWorkflowContext";
11
+
12
+ interface GroupSearchProps {
13
+ query: string;
14
+ selectGroupAction?: (group: GroupType) => void;
15
+ }
16
+
17
+ const GroupSearch: React.FC<GroupSearchProps> = ({
18
+ query = "",
19
+ selectGroupAction,
20
+ }) => {
21
+ const { t } = useTranslation();
22
+ const results = useGroupSearch(query);
23
+ const error = false;
24
+
25
+ if (error) {
26
+ return (
27
+ <div className={styles.searchResults}>
28
+ <Layer>
29
+ <Tile className={styles.emptySearchResultsTile}>
30
+ <EmptyDataIllustration />
31
+ <div>
32
+ <p className={styles.errorMessage}>{t("error", "Error")}</p>
33
+ <p className={styles.errorCopy}>
34
+ {t(
35
+ "errorCopy",
36
+ "Sorry, there was an error. You can try to reload this page, or contact the site administrator and quote the error code above."
37
+ )}
38
+ </p>
39
+ </div>
40
+ </Tile>
41
+ </Layer>
42
+ </div>
43
+ );
44
+ }
45
+
46
+ if (query.length <= 2) return <SearchResultSkeleton />;
47
+
48
+ if (results.length === 0) {
49
+ return (
50
+ <div className={styles.searchResults}>
51
+ <Layer>
52
+ <Tile className={styles.emptySearchResultsTile}>
53
+ <EmptyDataIllustration />
54
+ <p className={styles.emptyResultText}>
55
+ {t("noGroupsFoundMessage", "Sorry, no groups have been found")}
56
+ </p>
57
+ <p className={styles.actionText}>
58
+ <span>
59
+ {t(
60
+ "trySearchWithPatientUniqueID",
61
+ "Try searching with the cohort's description"
62
+ )}
63
+ </span>
64
+ <br />
65
+ <span>{t("orLabelName", "OR label name")}</span>
66
+ </p>
67
+ </Tile>
68
+ </Layer>
69
+ </div>
70
+ );
71
+ }
72
+
73
+ return (
74
+ <div className={styles.searchResultsContainer}>
75
+ <div
76
+ className={styles.searchResults}
77
+ style={{
78
+ maxHeight: "22rem",
79
+ }}
80
+ >
81
+ <p className={styles.resultsText}>
82
+ {results.length} {t("searchResultsText", "search result(s)")}
83
+ </p>
84
+ <CompactGroupResults
85
+ groups={results}
86
+ selectGroupAction={selectGroupAction}
87
+ />
88
+ </div>
89
+ </div>
90
+ );
91
+ };
92
+
93
+ export default GroupSearch;
@@ -0,0 +1,64 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/styles/scss/type';
3
+ @use '@carbon/styles/scss/colors';
4
+ @import '~@openmrs/esm-styleguide/src/vars';
5
+
6
+ .patientSearchResult {
7
+ text-decoration: none;
8
+ display: flex;
9
+ align-items: center;
10
+ border-bottom: 1px solid $ui-03;
11
+ padding: 0 spacing.$spacing-04;
12
+
13
+ &:hover,
14
+ &:focus {
15
+ background-color: $ui-01;
16
+ }
17
+ }
18
+
19
+ .patientSearchResultSelected {
20
+ background-color: colors.$gray-20;
21
+ }
22
+
23
+ .patientBanner {
24
+ display: flex;
25
+ }
26
+
27
+ .patientName {
28
+ @include type.type-style('heading-02');
29
+ }
30
+
31
+ .patientAvatar {
32
+ width: spacing.$spacing-09;
33
+ height: spacing.$spacing-09;
34
+ margin: spacing.$spacing-03 spacing.$spacing-05 spacing.$spacing-03 0;
35
+ border-radius: 1px;
36
+ }
37
+
38
+ .patientInfo {
39
+ width: 100%;
40
+ display: flex;
41
+ flex-flow: column wrap;
42
+ margin: spacing.$spacing-05;
43
+ cursor: pointer;
44
+ }
45
+
46
+ .demographics {
47
+ margin-top: spacing.$spacing-03;
48
+ @include type.type-style('body-compact-02');
49
+ color: $text-02;
50
+ }
51
+
52
+ .identifiers {
53
+ @include type.type-style('body-compact-02');
54
+ color: $ui-04;
55
+ }
56
+
57
+ .actionsContainer {
58
+ padding-top: spacing.$spacing-03;
59
+ margin-top: spacing.$spacing-05;
60
+ }
61
+
62
+ .middot {
63
+ margin: 0 spacing.$spacing-03;
64
+ }
@@ -0,0 +1,35 @@
1
+
2
+ @use '@carbon/styles/scss/spacing';
3
+ @use '@carbon/styles/scss/colors';
4
+ @import '~@openmrs/esm-styleguide/src/vars';
5
+
6
+ .patientSearchBar {
7
+ width: 50vw;
8
+ position: relative;
9
+ }
10
+
11
+ .floatingSearchResultsContainer {
12
+ position: absolute;
13
+ overflow-y: auto;
14
+ box-shadow: 0 spacing.$spacing-03 spacing.$spacing-05 $ui-03;
15
+ z-index: 99;
16
+ border: 0 1px 1px 1px solid $ui-03;
17
+ width: 100%;
18
+ background-color: $ui-02;
19
+ }
20
+
21
+ .searchArea {
22
+ width: inherit;
23
+ display: flex;
24
+ justify-content: center;
25
+ align-items: center;
26
+ border: 1px solid $ui-04;
27
+ }
28
+
29
+ .patientSearchInput {
30
+ border: none;
31
+ }
32
+
33
+ .patientSearchInput input:focus {
34
+ outline: 1px solid 1px solid colors.$orange-40;
35
+ }
@@ -0,0 +1,94 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/styles/scss/type';
3
+ @import '~@openmrs/esm-styleguide/src/vars';
4
+
5
+
6
+
7
+ .searchResultsContainer {
8
+ width: 100%;
9
+ background-color: $ui-02;
10
+
11
+ a {
12
+ text-decoration: none;
13
+ @include type.type-style('heading-02');
14
+ color: $text-02;
15
+ margin: 0rem;
16
+ }
17
+ }
18
+
19
+ :global(.omrs-breakpoint-lt-desktop) .searchResultsContainer {
20
+ top: 6.25rem;
21
+ }
22
+
23
+ :global(.omrs-breakpoint-gt-tablet) .searchResultsContainer {
24
+ padding: 0;
25
+ top: spacing.$spacing-09;
26
+ }
27
+
28
+ .searchResults {
29
+ width: 100%;
30
+ }
31
+
32
+ .loadingIcon {
33
+ padding: spacing.$spacing-05 0;
34
+ display: flex;
35
+ justify-content: center;
36
+ align-items: center;
37
+ }
38
+
39
+ .searchTerm {
40
+ @include type.type-style('heading-03');
41
+ margin-top: 0.375rem;
42
+ }
43
+
44
+ .resultsText {
45
+ @include type.type-style('label-01');
46
+ color: $text-02;
47
+ line-height: spacing.$spacing-05;
48
+ margin: spacing.$spacing-03 spacing.$spacing-05;
49
+ }
50
+
51
+ .helperText {
52
+ color: var(--omrs-color-ink-medium-contrast);
53
+ margin-left: 2.375rem;
54
+ }
55
+
56
+ .emptyResultText {
57
+ @include type.type-style('heading-compact-01');
58
+ color: $text-02;
59
+ margin-top: spacing.$spacing-05;
60
+ margin-bottom: 0.313rem;
61
+ }
62
+
63
+ .actionText {
64
+ @include type.type-style('body-01');
65
+ color: $text-02;
66
+ }
67
+
68
+ .pagination {
69
+ display: flex;
70
+ justify-content: space-evenly;
71
+ padding: 4.688rem 0 spacing.$spacing-06;
72
+ }
73
+
74
+ .emptySearchResultsTile {
75
+ text-align: center;
76
+ margin-top: spacing.$spacing-05;
77
+ padding: spacing.$spacing-09 0rem;
78
+ }
79
+
80
+ :global(.omrs-breakpoint-gt-tablet) .emptySearchResultsTile {
81
+ margin: spacing.$spacing-05;
82
+ }
83
+
84
+ .errorMessage {
85
+ @include type.type-style('heading-compact-02');
86
+ margin-top: 2.25rem;
87
+ margin-bottom: spacing.$spacing-03;
88
+ }
89
+
90
+ .errorCopy {
91
+ margin-bottom: spacing.$spacing-03;
92
+ @include type.type-style('body-01');
93
+ color: $text-02;
94
+ }
@@ -0,0 +1,79 @@
1
+ export const mockGroupData = [
2
+ {
3
+ id: 1,
4
+ name: "Teal Group",
5
+ description: "Coping skills group - Calgary",
6
+ members: [
7
+ {
8
+ name: "Donna Campbell",
9
+ uuid: "f87cae5e-6b64-4f64-884d-d46043a3b7da",
10
+ },
11
+ {
12
+ name: "Agnes Lewis",
13
+ uuid: "8af48d72-b155-4b41-ba9c-39e017fcf452",
14
+ },
15
+ {
16
+ name: "Daniel Mitchell",
17
+ uuid: "63665703-de71-4a2b-baa4-1a3acf995b7f",
18
+ },
19
+ ],
20
+ },
21
+ {
22
+ id: 2,
23
+ name: "Orange Group",
24
+ description: "Thursday night depression session",
25
+ members: [
26
+ {
27
+ name: "Mark Martin",
28
+ uuid: "eaef5256-ce7c-402c-9e56-f8e5d1fba22f",
29
+ },
30
+ {
31
+ name: "Robert Evans",
32
+ uuid: "8648a68d-1d68-4293-9d1a-a7a188b91418",
33
+ },
34
+ {
35
+ name: "Linda Johnson",
36
+ uuid: "8078cc5f-3cd7-4ebb-9ade-515c0dd5f85f",
37
+ },
38
+ {
39
+ name: "Daniel Green",
40
+ uuid: "4ff33dfa-e4ad-4cb5-bbad-8936f9d162df",
41
+ },
42
+ {
43
+ name: "Kimberly Adams",
44
+ uuid: "65bb2ebd-fef9-48c4-9c64-16445fa4fe7c",
45
+ },
46
+ {
47
+ name: "Daniel Lee",
48
+ uuid: "7d46336f-4b6e-4daa-a122-77a7efeb7a2e",
49
+ },
50
+ {
51
+ name: "Nancy Hernández",
52
+ uuid: "89ee2163-4dd4-4d4b-9882-f6be19c15b8f",
53
+ },
54
+ ],
55
+ },
56
+ {
57
+ id: 3,
58
+ name: "Blue Group",
59
+ description: "Thursday night depression session",
60
+ members: [
61
+ {
62
+ name: "Patty Patterson",
63
+ uuid: "9bf3adf4-3a5e-48b2-9adf-e117ce2ecdc5",
64
+ },
65
+ {
66
+ name: "Johnny Cash",
67
+ uuid: "f43172b8-a6fc-4edb-b92b-8d759ed9da50",
68
+ },
69
+ {
70
+ name: "John Doe Two",
71
+ uuid: "fa918efe-a4a4-4ac8-8381-3ba14ac61953",
72
+ },
73
+ {
74
+ name: "Foo Bazzi Bar",
75
+ uuid: "791c9475-8396-4519-a8ab-905cee8cccd3",
76
+ },
77
+ ],
78
+ },
79
+ ];
@@ -0,0 +1,14 @@
1
+ import { mockGroupData } from "./mock-group-data";
2
+
3
+ export function useGroupSearch(filter) {
4
+ const searchHistory = mockGroupData || [];
5
+ // if (filter.length <= 2) return [];
6
+
7
+ return filter
8
+ ? searchHistory?.filter(
9
+ (item) =>
10
+ item?.description?.toLowerCase()?.includes(filter?.toLowerCase()) ||
11
+ item?.name?.toLowerCase()?.includes(filter?.toLowerCase())
12
+ )
13
+ : searchHistory;
14
+ }
@@ -0,0 +1,42 @@
1
+ import { Close } from "@carbon/react/icons";
2
+ import { Button } from "@carbon/react";
3
+ import React, { useContext } from "react";
4
+ import { Link } from "react-router-dom";
5
+ import GroupFormWorkflowContext from "../../context/GroupFormWorkflowContext";
6
+ import styles from "./styles.scss";
7
+ import { useTranslation } from "react-i18next";
8
+ import CompactGroupSearch from "../group-search/CompactGroupSearch";
9
+ import AddGroupModal from "../../add-group-modal/AddGroupModal";
10
+
11
+ const GroupSearchHeader = () => {
12
+ const { t } = useTranslation();
13
+ const { activeGroupUuid, setGroup } = useContext(GroupFormWorkflowContext);
14
+ const handleSelectGroup = (group) => {
15
+ setGroup(group);
16
+ };
17
+
18
+ if (activeGroupUuid) return null;
19
+
20
+ return (
21
+ <div className={styles.searchHeaderContainer}>
22
+ <span className={styles.padded}>{t("findGroup", "Find group")}:</span>
23
+ <span className={styles.searchBarWrapper}>
24
+ <CompactGroupSearch selectGroupAction={handleSelectGroup} />
25
+ </span>
26
+ <span className={styles.padded}>{t("or", "or")}</span>
27
+ <span>
28
+ <AddGroupModal />
29
+ </span>
30
+ <span style={{ flexGrow: 1 }} />
31
+ <span>
32
+ <Link to="..">
33
+ <Button kind="ghost">
34
+ {t("cancel", "Cancel")} <Close size={20} />
35
+ </Button>
36
+ </Link>
37
+ </span>
38
+ </div>
39
+ );
40
+ };
41
+
42
+ export default GroupSearchHeader;
@@ -0,0 +1,3 @@
1
+ import GroupSearchHeader from "./GroupSearchHeader";
2
+
3
+ export default GroupSearchHeader;
@@ -0,0 +1,20 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @import '~@openmrs/esm-styleguide/src/vars';
3
+
4
+ .searchHeaderContainer {
5
+ height: spacing.$spacing-11;
6
+ display: flex;
7
+ align-items: center;
8
+ background-color: $ui-02;
9
+ border-top: 0.0125rem solid $ui-03;
10
+ border-bottom: 0.0125rem solid $ui-03;
11
+ padding: 0 spacing.$spacing-05;
12
+ }
13
+
14
+ .searchBarWrapper {
15
+ min-width: 35rem;
16
+ }
17
+
18
+ .padded {
19
+ padding: spacing.$spacing-05;
20
+ }
@@ -0,0 +1,3 @@
1
+ import GroupFormEntryWorkflow from "./GroupFormEntryWorkflow";
2
+
3
+ export default GroupFormEntryWorkflow;
@@ -0,0 +1,86 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/colors';
3
+ @use '@carbon/styles/scss/type';
4
+ @import '~@openmrs/esm-styleguide/src/vars';
5
+
6
+
7
+ .breadcrumbsContainer > div > div > nav {
8
+ background-color: $ui-02;
9
+ padding: spacing.$spacing-04 spacing.$spacing-05;
10
+ height: spacing.$spacing-08;
11
+ }
12
+
13
+ .workspaceWrapper {
14
+ display: flex;
15
+ justify-content: center;
16
+ }
17
+
18
+ .workspace {
19
+ width: 1100px;
20
+ }
21
+
22
+ .selectPatientMessage {
23
+ @include type.type-style('productive-heading-03');
24
+ margin: spacing.$spacing-07;
25
+ text-align: center;
26
+ }
27
+
28
+ .formMainContent {
29
+ display: flex;
30
+ text-align: center;
31
+ margin-top: spacing.$spacing-05;
32
+ column-gap: spacing.$spacing-05;
33
+ }
34
+
35
+ .formContainer {
36
+ flex-grow: 1;
37
+ max-height: calc(100vh - 14rem);
38
+ overflow-y: scroll;
39
+ }
40
+
41
+ .formContainer :global(.cds--form-item) :global(.question-area) {
42
+ max-width: 100%;
43
+ }
44
+
45
+ .rightPanel {
46
+ width: 13rem;
47
+ text-align: left;
48
+ overflow-y: scroll;
49
+ display: flex;
50
+ flex-direction: column;
51
+ row-gap: spacing.$spacing-05;
52
+ }
53
+
54
+ .patientCardsSection {
55
+ margin: spacing.$spacing-05 0;
56
+ border-bottom: 1px solid colors.$gray-10;
57
+ }
58
+
59
+ .rightPanelActionButtons {
60
+ display: flex;
61
+ flex-direction: column;
62
+ row-gap: spacing.$spacing-03;
63
+ & button {
64
+ width: 100%;
65
+ text-decoration: "none";
66
+ }
67
+ }
68
+
69
+ .formSection {
70
+ display: flex;
71
+ flex-direction: column;
72
+ row-gap: 1rem;
73
+ justify-content: flex-start;
74
+ align-items: flex-start;
75
+ text-align: left;
76
+ }
77
+
78
+ .formSectionTile {
79
+ width: 500px;
80
+ }
81
+
82
+
83
+ .formError {
84
+ @include type.type-style("helper-text-02");
85
+ color: colors.$red-60;
86
+ }
@@ -0,0 +1,6 @@
1
+ import useGetAllForms from "./useGetAllForms";
2
+ import useGetPatient from "./useGetPatient";
3
+ import useFormState from "./useFormState";
4
+ import useGetEncounter from "./useGetEncounter";
5
+
6
+ export { useGetAllForms, useGetPatient, useFormState, useGetEncounter };
@@ -0,0 +1,23 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ const useFormState = (formUuid) => {
4
+ const [state, setState] = useState(null);
5
+
6
+ useEffect(() => {
7
+ const handler = (e) => {
8
+ if (e.detail?.formUuid === formUuid) {
9
+ setState(e.detail?.state);
10
+ }
11
+ };
12
+
13
+ window.addEventListener("ampath-form-state", handler);
14
+
15
+ return () => {
16
+ window.removeEventListener("ampath-form-state", handler);
17
+ };
18
+ }, [formUuid]);
19
+
20
+ return state;
21
+ };
22
+
23
+ export default useFormState;
@@ -0,0 +1,45 @@
1
+ import {
2
+ openmrsFetch,
3
+ userHasAccess,
4
+ useSession,
5
+ } from "@openmrs/esm-framework";
6
+ import useSWR from "swr";
7
+
8
+ const customFormRepresentation =
9
+ "(uuid,name,display,encounterType:(uuid,name,viewPrivilege,editPrivilege),version,published,retired,resources:(uuid,name,dataType,valueReference))";
10
+
11
+ const formEncounterUrl = `/ws/rest/v1/form?v=custom:${customFormRepresentation}`;
12
+ const formEncounterUrlPoc = `/ws/rest/v1/form?v=custom:${customFormRepresentation}&q=poc`;
13
+
14
+ export function useGetAllForms(cachedOfflineFormsOnly = false) {
15
+ const session = useSession();
16
+ const showHtmlFormEntryForms = true;
17
+ const url = showHtmlFormEntryForms ? formEncounterUrl : formEncounterUrlPoc;
18
+ const { data, error } = useSWR([url, cachedOfflineFormsOnly], async () => {
19
+ const res = await openmrsFetch(url);
20
+ // show published forms, and hide component forms, and filter based on privileges
21
+ const forms =
22
+ res.data?.results?.filter(
23
+ (form) =>
24
+ // forms should be published
25
+ form.published &&
26
+ // forms should not be component forms
27
+ !/component/i.test(form.name)
28
+ // user should have privileges to edit forms
29
+ ) ?? [];
30
+
31
+ return forms;
32
+ });
33
+
34
+ return {
35
+ forms: data?.filter((form) =>
36
+ Boolean(
37
+ userHasAccess(form.encounterType?.editPrivilege?.display, session?.user)
38
+ )
39
+ ),
40
+ isLoading: !error && !data,
41
+ error,
42
+ };
43
+ }
44
+
45
+ export default useGetAllForms;
@@ -0,0 +1,21 @@
1
+ import { openmrsFetch } from "@openmrs/esm-framework";
2
+ import useSWR from "swr";
3
+
4
+ const encounterUrl = "/ws/rest/v1/encounter/";
5
+
6
+ const useGetEncounter = (encounterUuid) => {
7
+ const url = `${encounterUrl}${encounterUuid}`;
8
+ const { data, error } = useSWR(url, async () => {
9
+ const res = await openmrsFetch(url);
10
+ const encounter = res.data || null;
11
+ return encounter;
12
+ });
13
+
14
+ return {
15
+ encounter: data,
16
+ isLoading: !error && data,
17
+ error,
18
+ };
19
+ };
20
+
21
+ export default useGetEncounter;
@@ -0,0 +1,23 @@
1
+ import { fetchCurrentPatient } from "@openmrs/esm-framework";
2
+ import { useEffect, useState } from "react";
3
+
4
+ const useGetPatient = (patientUuid) => {
5
+ const [patient, setPatient] = useState(null);
6
+
7
+ useEffect(() => {
8
+ if (!patientUuid) {
9
+ setPatient(null);
10
+ } else {
11
+ getPatient(patientUuid);
12
+ }
13
+ }, [patientUuid]);
14
+
15
+ const getPatient = async (uuid) => {
16
+ const result = await fetchCurrentPatient(uuid);
17
+ setPatient(result?.data);
18
+ };
19
+
20
+ return patient;
21
+ };
22
+
23
+ export default useGetPatient;
@@ -0,0 +1,31 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ const useKeyPress = (targetKey) => {
4
+ const [keyPressed, setKeyPressed] = useState(false);
5
+
6
+ useEffect(() => {
7
+ const downHandler = ({ key }) => {
8
+ if (key === targetKey) {
9
+ setKeyPressed(true);
10
+ }
11
+ };
12
+
13
+ const upHandler = ({ key }) => {
14
+ if (key === targetKey) {
15
+ setKeyPressed(false);
16
+ }
17
+ };
18
+
19
+ window.addEventListener("keydown", downHandler);
20
+ window.addEventListener("keyup", upHandler);
21
+
22
+ return () => {
23
+ window.removeEventListener("keydown", downHandler);
24
+ window.removeEventListener("keyup", upHandler);
25
+ };
26
+ }, [targetKey]);
27
+
28
+ return keyPressed;
29
+ };
30
+
31
+ export default useKeyPress;