@openmrs/esm-fast-data-entry-app 1.0.1-pre.99 → 1.1.0

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 (190) hide show
  1. package/__mocks__/react-i18next.js +9 -14
  2. package/dist/12.js +1 -0
  3. package/dist/12.js.map +1 -0
  4. package/dist/132.js +1 -0
  5. package/dist/151.js +2 -0
  6. package/dist/151.js.map +1 -0
  7. package/dist/195.js +1 -0
  8. package/dist/195.js.map +1 -0
  9. package/dist/197.js +1 -0
  10. package/dist/221.js +1 -0
  11. package/dist/221.js.map +1 -0
  12. package/dist/259.js +1 -0
  13. package/dist/259.js.map +1 -0
  14. package/dist/265.js +1 -0
  15. package/dist/265.js.map +1 -0
  16. package/dist/269.js +1 -0
  17. package/dist/269.js.map +1 -0
  18. package/dist/{574.js → 300.js} +1 -1
  19. package/dist/335.js +1 -0
  20. package/dist/367.js +1 -0
  21. package/dist/367.js.map +1 -0
  22. package/dist/384.js +1 -0
  23. package/dist/384.js.map +1 -0
  24. package/dist/{294.js → 540.js} +2 -2
  25. package/dist/{294.js.map → 540.js.map} +1 -1
  26. package/dist/55.js +1 -0
  27. package/dist/579.js +1 -0
  28. package/dist/579.js.map +1 -0
  29. package/dist/595.js +2 -0
  30. package/dist/{409.js.LICENSE.txt → 595.js.LICENSE.txt} +14 -6
  31. package/dist/595.js.map +1 -0
  32. package/dist/602.js +1 -0
  33. package/dist/602.js.map +1 -0
  34. package/dist/616.js +1 -0
  35. package/dist/616.js.map +1 -0
  36. package/dist/626.js +2 -0
  37. package/dist/626.js.map +1 -0
  38. package/dist/652.js +1 -0
  39. package/dist/77.js +1 -0
  40. package/dist/77.js.map +1 -0
  41. package/dist/773.js +2 -0
  42. package/dist/{897.js.LICENSE.txt → 773.js.LICENSE.txt} +13 -2
  43. package/dist/773.js.map +1 -0
  44. package/dist/88.js +1 -0
  45. package/dist/88.js.map +1 -0
  46. package/dist/930.js +1 -0
  47. package/dist/930.js.map +1 -0
  48. package/dist/961.js +2 -0
  49. package/dist/961.js.map +1 -0
  50. package/dist/983.js +1 -0
  51. package/dist/983.js.map +1 -0
  52. package/dist/99.js +1 -0
  53. package/dist/main.js +1 -1
  54. package/dist/main.js.map +1 -1
  55. package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
  56. package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +386 -154
  57. package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -1
  58. package/dist/routes.json +1 -1
  59. package/jest.config.json +2 -1
  60. package/package.json +39 -36
  61. package/prettier.config.js +8 -0
  62. package/src/CancelModal.tsx +9 -15
  63. package/src/CompleteModal.tsx +7 -18
  64. package/src/FormBootstrap.tsx +31 -18
  65. package/src/Root.tsx +7 -12
  66. package/src/add-group-modal/AddGroupModal.tsx +73 -112
  67. package/src/add-group-modal/styles.scss +7 -3
  68. package/src/config-schema.ts +63 -24
  69. package/src/constant.ts +1 -1
  70. package/src/context/FormWorkflowContext.tsx +26 -39
  71. package/src/context/FormWorkflowReducer.ts +50 -74
  72. package/src/context/GroupFormWorkflowContext.tsx +40 -59
  73. package/src/context/GroupFormWorkflowReducer.ts +84 -109
  74. package/src/declarations.d.ts +3 -0
  75. package/src/empty-state/EmptyDataIllustration.tsx +4 -16
  76. package/src/empty-state/EmptyState.tsx +8 -13
  77. package/src/empty-state/styles.scss +14 -14
  78. package/src/form-entry-workflow/FormEntryWorkflow.tsx +43 -55
  79. package/src/form-entry-workflow/form-review-card/FormReviewCard.tsx +7 -7
  80. package/src/form-entry-workflow/form-review-card/index.ts +1 -1
  81. package/src/form-entry-workflow/form-review-card/styles.scss +9 -11
  82. package/src/form-entry-workflow/index.ts +1 -1
  83. package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +5 -5
  84. package/src/form-entry-workflow/patient-banner/PatientBanner.tsx +14 -27
  85. package/src/form-entry-workflow/patient-banner/index.ts +1 -1
  86. package/src/form-entry-workflow/patient-banner/styles.scss +11 -12
  87. package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +19 -28
  88. package/src/form-entry-workflow/patient-search-header/index.ts +1 -1
  89. package/src/form-entry-workflow/patient-search-header/styles.scss +13 -10
  90. package/src/form-entry-workflow/styles.scss +11 -13
  91. package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +13 -11
  92. package/src/form-entry-workflow/workflow-review/index.ts +1 -1
  93. package/src/form-entry-workflow/workflow-review/styles.scss +0 -4
  94. package/src/forms-app-menu-link.tsx +4 -6
  95. package/src/forms-page/FormsPage.tsx +23 -51
  96. package/src/forms-page/forms-table/FormsTable.tsx +22 -42
  97. package/src/forms-page/forms-table/index.ts +1 -1
  98. package/src/forms-page/forms-table/styles.scss +4 -5
  99. package/src/forms-page/index.ts +1 -1
  100. package/src/forms-page/styles.scss +3 -5
  101. package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +9 -9
  102. package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +77 -117
  103. package/src/group-form-entry-workflow/SessionDetailsForm.tsx +73 -50
  104. package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +20 -28
  105. package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +15 -29
  106. package/src/group-form-entry-workflow/attendance-table/index.ts +1 -1
  107. package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +45 -0
  108. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.test.tsx +5 -5
  109. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +13 -21
  110. package/src/group-form-entry-workflow/group-display-header/index.ts +1 -1
  111. package/src/group-form-entry-workflow/group-display-header/styles.scss +20 -20
  112. package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +24 -35
  113. package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +13 -15
  114. package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +22 -38
  115. package/src/group-form-entry-workflow/group-search/compact-group-result.scss +16 -17
  116. package/src/group-form-entry-workflow/group-search/compact-group-search.scss +7 -8
  117. package/src/group-form-entry-workflow/group-search/group-search.scss +20 -23
  118. package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +20 -21
  119. package/src/group-form-entry-workflow/group-search-header/index.ts +1 -1
  120. package/src/group-form-entry-workflow/group-search-header/styles.scss +8 -8
  121. package/src/group-form-entry-workflow/index.ts +1 -1
  122. package/src/group-form-entry-workflow/styles.scss +13 -16
  123. package/src/hooks/index.ts +7 -6
  124. package/src/hooks/useFormState.ts +3 -3
  125. package/src/hooks/useGetAllForms.ts +7 -15
  126. package/src/hooks/useGetEncounter.ts +3 -3
  127. package/src/hooks/useGetPatient.ts +2 -2
  128. package/src/hooks/useGetPatients.ts +4 -6
  129. package/src/hooks/useGetSystemSetting.ts +3 -5
  130. package/src/hooks/useKeyPress.ts +5 -5
  131. package/src/hooks/usePostEndpoint.ts +10 -10
  132. package/src/hooks/useSearchEndpoint.ts +23 -40
  133. package/src/hooks/useSpecificQuestions.ts +75 -0
  134. package/src/hooks/useStartVisit.ts +18 -28
  135. package/src/index.ts +8 -20
  136. package/src/patient-card/PatientCard.tsx +8 -20
  137. package/src/patient-card/index.ts +1 -1
  138. package/src/patient-card/styles.scss +2 -4
  139. package/src/routes.json +2 -2
  140. package/src/setup-tests.ts +1 -1
  141. package/src/types.ts +25 -0
  142. package/tools/i18next-parser.config.js +19 -19
  143. package/translations/am.json +75 -0
  144. package/translations/ar.json +75 -0
  145. package/translations/en.json +7 -1
  146. package/translations/es.json +75 -0
  147. package/translations/fr.json +33 -8
  148. package/translations/he.json +75 -0
  149. package/translations/km.json +75 -0
  150. package/tsconfig.json +2 -1
  151. package/turbo.json +18 -0
  152. package/webpack.config.js +1 -1
  153. package/dist/136.js +0 -1
  154. package/dist/136.js.map +0 -1
  155. package/dist/141.js +0 -2
  156. package/dist/141.js.map +0 -1
  157. package/dist/233.js +0 -2
  158. package/dist/233.js.map +0 -1
  159. package/dist/242.js +0 -1
  160. package/dist/242.js.map +0 -1
  161. package/dist/327.js +0 -1
  162. package/dist/327.js.map +0 -1
  163. package/dist/387.js +0 -1
  164. package/dist/387.js.map +0 -1
  165. package/dist/405.js +0 -1
  166. package/dist/405.js.map +0 -1
  167. package/dist/409.js +0 -2
  168. package/dist/409.js.map +0 -1
  169. package/dist/431.js +0 -1
  170. package/dist/431.js.map +0 -1
  171. package/dist/559.js +0 -1
  172. package/dist/559.js.map +0 -1
  173. package/dist/757.js +0 -1
  174. package/dist/820.js +0 -1
  175. package/dist/820.js.map +0 -1
  176. package/dist/846.js +0 -1
  177. package/dist/846.js.map +0 -1
  178. package/dist/885.js +0 -1
  179. package/dist/885.js.map +0 -1
  180. package/dist/897.js +0 -2
  181. package/dist/897.js.map +0 -1
  182. package/dist/92.js +0 -1
  183. package/dist/92.js.map +0 -1
  184. package/dist/935.js +0 -2
  185. package/dist/935.js.map +0 -1
  186. package/src/declarations.d.tsx +0 -2
  187. /package/dist/{141.js.LICENSE.txt → 151.js.LICENSE.txt} +0 -0
  188. /package/dist/{294.js.LICENSE.txt → 540.js.LICENSE.txt} +0 -0
  189. /package/dist/{233.js.LICENSE.txt → 626.js.LICENSE.txt} +0 -0
  190. /package/dist/{935.js.LICENSE.txt → 961.js.LICENSE.txt} +0 -0
@@ -1,19 +1,13 @@
1
- import { useConfig, useSession } from "@openmrs/esm-framework";
2
- import { Tab, Tabs, TabList, TabPanels, TabPanel } from "@carbon/react";
3
- import React from "react";
4
- import { Config } from "../config-schema";
5
- import { useGetAllForms } from "../hooks";
6
- import FormsTable from "./forms-table";
7
- import styles from "./styles.scss";
8
- import { useTranslation } from "react-i18next";
9
- import {
10
- fdeWorkflowStorageName,
11
- fdeWorkflowStorageVersion,
12
- } from "../context/FormWorkflowReducer";
13
- import {
14
- fdeGroupWorkflowStorageName,
15
- fdeGroupWorkflowStorageVersion,
16
- } from "../context/GroupFormWorkflowReducer";
1
+ import { useConfig, useSession } from '@openmrs/esm-framework';
2
+ import { Tab, Tabs, TabList, TabPanels, TabPanel } from '@carbon/react';
3
+ import React from 'react';
4
+ import { type Config } from '../config-schema';
5
+ import { useGetAllForms } from '../hooks';
6
+ import FormsTable from './forms-table';
7
+ import styles from './styles.scss';
8
+ import { useTranslation } from 'react-i18next';
9
+ import { fdeWorkflowStorageName, fdeWorkflowStorageVersion } from '../context/FormWorkflowReducer';
10
+ import { fdeGroupWorkflowStorageName, fdeGroupWorkflowStorageVersion } from '../context/GroupFormWorkflowReducer';
17
11
 
18
12
  // helper function useful for debugging
19
13
  // given a list of forms, it will organize into permissions
@@ -25,7 +19,7 @@ export const getFormPermissions = (forms) => {
25
19
  (output[form.encounterType.editPrivilege.display] = [
26
20
  ...(output[form.encounterType.editPrivilege.display] || []),
27
21
  form.display,
28
- ])
22
+ ]),
29
23
  );
30
24
  return output;
31
25
  };
@@ -44,41 +38,29 @@ const prepareRowsForTable = (rawFormData) => {
44
38
  };
45
39
 
46
40
  const FormsPage = () => {
47
- const config = useConfig() as Config;
41
+ const config = useConfig();
48
42
  const { t } = useTranslation();
49
43
  const { formCategories, formCategoriesToShow } = config;
50
44
  const { forms, isLoading, error } = useGetAllForms();
51
45
  const cleanRows = prepareRowsForTable(forms);
52
46
  const { user } = useSession();
53
- const savedFormsData = localStorage.getItem(
54
- fdeWorkflowStorageName + ":" + user?.uuid
55
- );
56
- const savedGroupFormsData = localStorage.getItem(
57
- fdeGroupWorkflowStorageName + ":" + user?.uuid
58
- );
47
+ const savedFormsData = localStorage.getItem(fdeWorkflowStorageName + ':' + user?.uuid);
48
+ const savedGroupFormsData = localStorage.getItem(fdeGroupWorkflowStorageName + ':' + user?.uuid);
59
49
  const activeForms = [];
60
50
  const activeGroupForms = [];
61
51
 
62
- if (
63
- savedFormsData &&
64
- JSON.parse(savedFormsData)?.["_storageVersion"] ===
65
- fdeWorkflowStorageVersion
66
- ) {
52
+ if (savedFormsData && JSON.parse(savedFormsData)?.['_storageVersion'] === fdeWorkflowStorageVersion) {
67
53
  Object.entries(JSON.parse(savedFormsData).forms).forEach(
68
54
  ([formUuid, form]: [string, { [key: string]: unknown }]) => {
69
55
  if (form.workflowState) activeForms.push(formUuid);
70
- }
56
+ },
71
57
  );
72
58
  }
73
- if (
74
- savedGroupFormsData &&
75
- JSON.parse(savedGroupFormsData)?.["_storageVersion"] ===
76
- fdeGroupWorkflowStorageVersion
77
- ) {
59
+ if (savedGroupFormsData && JSON.parse(savedGroupFormsData)?.['_storageVersion'] === fdeGroupWorkflowStorageVersion) {
78
60
  Object.entries(JSON.parse(savedGroupFormsData).forms).forEach(
79
61
  ([formUuid, form]: [string, { [key: string]: unknown }]) => {
80
62
  if (form.workflowState) activeGroupForms.push(formUuid);
81
- }
63
+ },
82
64
  );
83
65
  }
84
66
 
@@ -94,15 +76,11 @@ const FormsPage = () => {
94
76
 
95
77
  return (
96
78
  <div className={styles.mainContent}>
97
- <h3 className={styles.pageTitle}>
98
- {t("fastDataEntry", "Fast Data Entry")}
99
- </h3>
79
+ <h3 className={styles.pageTitle}>{t('fastDataEntry', 'Fast Data Entry')}</h3>
100
80
  <Tabs>
101
81
  <TabList>
102
- <Tab label={t("allForms", "All Forms")}>
103
- {`${t("allForms", "All Forms")} (${
104
- cleanRows ? cleanRows?.length : "??"
105
- })`}
82
+ <Tab label={t('allForms', 'All Forms')}>
83
+ {`${t('allForms', 'All Forms')} (${cleanRows ? cleanRows?.length : '??'})`}
106
84
  </Tab>
107
85
  {categoryRows?.map((category, index) => (
108
86
  <Tab label={category.name} key={index}>
@@ -112,17 +90,11 @@ const FormsPage = () => {
112
90
  </TabList>
113
91
  <TabPanels>
114
92
  <TabPanel>
115
- <FormsTable
116
- rows={cleanRows}
117
- {...{ error, isLoading, activeForms, activeGroupForms }}
118
- />
93
+ <FormsTable rows={cleanRows} {...{ error, isLoading, activeForms, activeGroupForms }} />
119
94
  </TabPanel>
120
95
  {categoryRows?.map((category, index) => (
121
96
  <TabPanel key={index}>
122
- <FormsTable
123
- rows={category.rows}
124
- {...{ error, isLoading, activeForms, activeGroupForms }}
125
- />
97
+ <FormsTable rows={category.rows} {...{ error, isLoading, activeForms, activeGroupForms }} />
126
98
  </TabPanel>
127
99
  ))}
128
100
  </TabPanels>
@@ -1,4 +1,4 @@
1
- import { ErrorState } from "@openmrs/esm-framework";
1
+ import { ErrorState } from '@openmrs/esm-framework';
2
2
  import {
3
3
  DataTable,
4
4
  DataTableSkeleton,
@@ -12,35 +12,29 @@ import {
12
12
  TableToolbar,
13
13
  TableToolbarContent,
14
14
  TableToolbarSearch,
15
- } from "@carbon/react";
16
- import React from "react";
17
- import { useTranslation } from "react-i18next";
18
- import { Link } from "react-router-dom";
19
- import EmptyState from "../../empty-state/EmptyState";
20
- import styles from "./styles.scss";
15
+ } from '@carbon/react';
16
+ import React from 'react';
17
+ import { useTranslation } from 'react-i18next';
18
+ import { Link } from 'react-router-dom';
19
+ import EmptyState from '../../empty-state/EmptyState';
20
+ import styles from './styles.scss';
21
21
 
22
- const FormsTable = ({
23
- rows,
24
- error,
25
- isLoading,
26
- activeForms,
27
- activeGroupForms,
28
- }) => {
22
+ const FormsTable = ({ rows, error, isLoading, activeForms, activeGroupForms }) => {
29
23
  const { t } = useTranslation();
30
24
 
31
25
  const tableHeaders = [
32
26
  {
33
- key: "display",
34
- header: t("formName", "Form Name"),
27
+ key: 'display',
28
+ header: t('formName', 'Form Name'),
35
29
  isSortable: true,
36
30
  },
37
31
  {
38
- key: "actions",
39
- header: t("actions", "Actions"),
32
+ key: 'actions',
33
+ header: t('actions', 'Actions'),
40
34
  },
41
35
  {
42
- key: "actions2",
43
- header: "",
36
+ key: 'actions2',
37
+ header: '',
44
38
  },
45
39
  ];
46
40
 
@@ -48,50 +42,36 @@ const FormsTable = ({
48
42
  ...row,
49
43
  actions: (
50
44
  <Link to={`form/${row.uuid}`}>
51
- {activeForms.includes(row.uuid)
52
- ? t("resumeSession", "Resume Session")
53
- : t("fillForm", "Fill Form")}
45
+ {activeForms.includes(row.uuid) ? t('resumeSession', 'Resume Session') : t('fillForm', 'Fill Form')}
54
46
  </Link>
55
47
  ),
56
48
  actions2: (
57
49
  <Link to={`groupform/${row.uuid}`}>
58
50
  {activeGroupForms.includes(row.uuid)
59
- ? t("resumeGroupSession", "Resume Group Session")
60
- : t("startGroupSession", "Start Group Session")}
51
+ ? t('resumeGroupSession', 'Resume Group Session')
52
+ : t('startGroupSession', 'Start Group Session')}
61
53
  </Link>
62
54
  ),
63
55
  }));
64
56
 
65
57
  if (isLoading) return <DataTableSkeleton />;
66
58
  if (error) {
67
- return (
68
- <ErrorState
69
- headerTitle={t("errorLoadingData", "Error Loading Data")}
70
- error={error}
71
- />
72
- );
59
+ return <ErrorState headerTitle={t('errorLoadingData', 'Error Loading Data')} error={error} />;
73
60
  }
74
61
  if (augmentedRows.length === 0) {
75
62
  return (
76
63
  <EmptyState
77
- headerTitle={t("noFormsFound", "No Forms To Show")}
64
+ headerTitle={t('noFormsFound', 'No Forms To Show')}
78
65
  displayText={t(
79
- "noFormsFoundMessage",
80
- "No forms could be found for this category. Please double check the form concept uuids and access permissions."
66
+ 'noFormsFoundMessage',
67
+ 'No forms could be found for this category. Please double check the form concept uuids and access permissions.',
81
68
  )}
82
69
  />
83
70
  );
84
71
  }
85
72
  return (
86
73
  <DataTable rows={augmentedRows} headers={tableHeaders}>
87
- {({
88
- rows,
89
- headers,
90
- getTableProps,
91
- getHeaderProps,
92
- getRowProps,
93
- onInputChange,
94
- }) => {
74
+ {({ rows, headers, getTableProps, getHeaderProps, getRowProps, onInputChange }) => {
95
75
  return (
96
76
  <TableContainer>
97
77
  <div className={styles.toolbarWrapper}>
@@ -1,3 +1,3 @@
1
- import FormsTable from "./FormsTable";
1
+ import FormsTable from './FormsTable';
2
2
 
3
3
  export default FormsTable;
@@ -1,11 +1,10 @@
1
- @import "~@openmrs/esm-styleguide/src/vars";
2
- @import "~carbon-components/src/globals/scss/vars";
3
- @import "~carbon-components/src/globals/scss/mixins";
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
4
3
 
5
4
  .toolbarWrapper {
6
5
  position: relative;
7
6
  display: flex;
8
- height: $spacing-09;
7
+ height: layout.$spacing-09;
9
8
  justify-content: flex-end;
10
9
  }
11
10
 
@@ -15,6 +14,6 @@
15
14
  }
16
15
 
17
16
  .inactiveLink {
18
- color: $carbon--gray-40;
17
+ color: colors.$gray-40;
19
18
  cursor: not-allowed;
20
19
  }
@@ -1,3 +1,3 @@
1
- import FormsPage from "./FormsPage";
1
+ import FormsPage from './FormsPage';
2
2
 
3
3
  export default FormsPage;
@@ -1,11 +1,9 @@
1
- @use '@carbon/styles/scss/spacing';
2
- // @use '@carbon/styles/scss/type';
3
- // @import '~@openmrs/esm-styleguide/src/vars';
1
+ @use '@carbon/layout';
4
2
 
5
3
  .mainContent {
6
- padding: spacing.$spacing-07;
4
+ padding: layout.$spacing-07;
7
5
  }
8
6
 
9
7
  .pageTitle {
10
- margin-bottom: spacing.$spacing-06;
8
+ margin-bottom: layout.$spacing-06;
11
9
  }
@@ -1,17 +1,17 @@
1
- import { ExtensionSlot } from "@openmrs/esm-framework";
2
- import React from "react";
3
- import GroupDisplayHeader from "./group-display-header";
4
- import styles from "./styles.scss";
5
- import { GroupFormWorkflowProvider } from "../context/GroupFormWorkflowContext";
6
- import GroupSearchHeader from "./group-search-header";
7
- import SessionMetaWorkspace from "./SessionMetaWorkspace";
8
- import GroupSessionWorkspace from "./GroupSessionWorkspace";
1
+ import { ExtensionSlot } from '@openmrs/esm-framework';
2
+ import React from 'react';
3
+ import GroupDisplayHeader from './group-display-header';
4
+ import styles from './styles.scss';
5
+ import { GroupFormWorkflowProvider } from '../context/GroupFormWorkflowContext';
6
+ import GroupSearchHeader from './group-search-header';
7
+ import SessionMetaWorkspace from './SessionMetaWorkspace';
8
+ import GroupSessionWorkspace from './GroupSessionWorkspace';
9
9
 
10
10
  const GroupFormEntryWorkflow = () => {
11
11
  return (
12
12
  <GroupFormWorkflowProvider>
13
13
  <div className={styles.breadcrumbsContainer}>
14
- <ExtensionSlot extensionSlotName="breadcrumbs-slot" />
14
+ <ExtensionSlot name="breadcrumbs-slot" />
15
15
  </div>
16
16
  <GroupSearchHeader />
17
17
  <GroupDisplayHeader />
@@ -1,48 +1,32 @@
1
- import {
2
- getGlobalStore,
3
- useConfig,
4
- useSession,
5
- useStore,
6
- } from "@openmrs/esm-framework";
7
- import { Button } from "@carbon/react";
8
- import React, { useCallback, useContext, useEffect, useState } from "react";
9
- import PatientCard from "../patient-card/PatientCard";
10
- import styles from "./styles.scss";
11
- import { useTranslation } from "react-i18next";
12
- import GroupFormWorkflowContext from "../context/GroupFormWorkflowContext";
13
- import FormBootstrap from "../FormBootstrap";
14
- import useStartVisit from "../hooks/useStartVisit";
15
- import CompleteModal from "../CompleteModal";
16
- import CancelModal from "../CancelModal";
17
-
18
- const formStore = getGlobalStore("ampath-form-state");
1
+ import { getGlobalStore, useConfig, useSession, useStore } from '@openmrs/esm-framework';
2
+ import { Button } from '@carbon/react';
3
+ import React, { useCallback, useContext, useEffect, useState } from 'react';
4
+ import PatientCard from '../patient-card/PatientCard';
5
+ import styles from './styles.scss';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { v4 as uuid } from 'uuid';
8
+ import GroupFormWorkflowContext from '../context/GroupFormWorkflowContext';
9
+ import FormBootstrap from '../FormBootstrap';
10
+ import CompleteModal from '../CompleteModal';
11
+ import CancelModal from '../CancelModal';
12
+
13
+ const formStore = getGlobalStore('ampath-form-state');
19
14
 
20
15
  const WorkflowNavigationButtons = () => {
21
16
  const context = useContext(GroupFormWorkflowContext);
22
- const {
23
- activeFormUuid,
24
- submitForNext,
25
- patientUuids,
26
- activePatientUuid,
27
- workflowState,
28
- } = context;
17
+ const { activeFormUuid, submitForNext, patientUuids, activePatientUuid, workflowState } = context;
29
18
  const store = useStore(formStore);
30
19
  const formState = store[activeFormUuid];
31
20
  const navigationDisabled =
32
- (formState !== "ready" || workflowState !== "EDIT_FORM") &&
33
- formState !== "readyWithValidationErrors";
21
+ (formState !== 'ready' || workflowState !== 'EDIT_FORM') && formState !== 'readyWithValidationErrors';
34
22
  const [cancelModalOpen, setCancelModalOpen] = useState(false);
35
23
  const [completeModalOpen, setCompleteModalOpen] = useState(false);
36
24
  const { t } = useTranslation();
37
25
 
38
- const isLastPatient =
39
- activePatientUuid === patientUuids[patientUuids.length - 1];
26
+ const isLastPatient = activePatientUuid === patientUuids[patientUuids.length - 1];
40
27
 
41
28
  const handleClickNext = () => {
42
- if (
43
- workflowState === "EDIT_FORM" ||
44
- formState === "readyWithValidationErrors"
45
- ) {
29
+ if (workflowState === 'EDIT_FORM' || formState === 'readyWithValidationErrors') {
46
30
  submitForNext();
47
31
  }
48
32
  };
@@ -50,33 +34,18 @@ const WorkflowNavigationButtons = () => {
50
34
  return (
51
35
  <>
52
36
  <div className={styles.rightPanelActionButtons}>
53
- <Button
54
- kind="primary"
55
- onClick={handleClickNext}
56
- disabled={navigationDisabled}
57
- >
58
- {isLastPatient
59
- ? t("saveForm", "Save Form")
60
- : t("nextPatient", "Next Patient")}
37
+ <Button kind="primary" onClick={handleClickNext} disabled={navigationDisabled}>
38
+ {isLastPatient ? t('saveForm', 'Save Form') : t('nextPatient', 'Next patient')}
61
39
  </Button>
62
40
  <Button kind="secondary" onClick={() => setCompleteModalOpen(true)}>
63
- {t("saveAndComplete", "Save & Complete")}
41
+ {t('saveAndComplete', 'Save & Complete')}
64
42
  </Button>
65
43
  <Button kind="tertiary" onClick={() => setCancelModalOpen(true)}>
66
- {t("cancel", "Cancel")}
44
+ {t('cancel', 'Cancel')}
67
45
  </Button>
68
46
  </div>
69
- <CancelModal
70
- open={cancelModalOpen}
71
- setOpen={setCancelModalOpen}
72
- context={context}
73
- />
74
- <CompleteModal
75
- open={completeModalOpen}
76
- setOpen={setCompleteModalOpen}
77
- context={context}
78
- validateFirst={false}
79
- />
47
+ <CancelModal open={cancelModalOpen} setOpen={setCancelModalOpen} context={context} />
48
+ <CompleteModal open={completeModalOpen} setOpen={setCompleteModalOpen} context={context} validateFirst={false} />
80
49
  </>
81
50
  );
82
51
  };
@@ -91,6 +60,9 @@ const GroupSessionWorkspace = () => {
91
60
  activeEncounterUuid,
92
61
  activeVisitUuid,
93
62
  activeFormUuid,
63
+ activeGroupUuid,
64
+ activeGroupName,
65
+ activeSessionUuid,
94
66
  saveEncounter,
95
67
  activeSessionMeta,
96
68
  groupVisitTypeUuid,
@@ -100,53 +72,17 @@ const GroupSessionWorkspace = () => {
100
72
  } = useContext(GroupFormWorkflowContext);
101
73
 
102
74
  const { sessionLocation } = useSession();
103
- const [encounter, setEncounter] = useState(null);
104
- const [visit, setVisit] = useState(null);
105
75
 
106
- const {
107
- saveVisit,
108
- updateEncounter,
109
- success: visitSaveSuccess,
110
- } = useStartVisit({
111
- showSuccessNotification: false,
112
- showErrorNotification: true,
113
- });
114
-
115
- // 0. user clicks "next patient" in WorkflowNavigationButtons
116
- // which triggers submitForNext() if workflowState === "EDIT_FORM"
117
-
118
- // 1. save the new visit uuid and start form submission
119
76
  useEffect(() => {
120
- if (
121
- visitSaveSuccess &&
122
- visitSaveSuccess.data.patient.uuid === activePatientUuid
123
- ) {
124
- setVisit(visitSaveSuccess.data);
125
- // Update visit UUID on workflow
126
- updateVisitUuid(visitSaveSuccess.data.uuid);
77
+ if (activeVisitUuid) {
78
+ updateVisitUuid(activeVisitUuid);
127
79
  }
128
- }, [
129
- visitSaveSuccess,
130
- updateVisitUuid,
131
- activeVisitUuid,
132
- activePatientUuid,
133
- visit,
134
- setVisit,
135
- ]);
80
+ }, [updateVisitUuid, activeVisitUuid, activePatientUuid]);
136
81
 
137
- // 2. If there's no active visit, trigger the creation of a new one
82
+ // If there's no active visit, trigger the creation of a new one
138
83
  const handleEncounterCreate = useCallback(
139
84
  (payload) => {
140
85
  // Create a visit with the same date as the encounter being saved
141
- if (!activeVisitUuid) {
142
- saveVisit({
143
- patientUuid: activePatientUuid,
144
- startDatetime: activeSessionMeta.sessionDate,
145
- stopDatetime: activeSessionMeta.sessionDate,
146
- visitType: groupVisitTypeUuid,
147
- location: sessionLocation?.uuid,
148
- });
149
- }
150
86
  const obsTime = new Date(activeSessionMeta.sessionDate);
151
87
  payload.obs.forEach((item, index) => {
152
88
  payload.obs[index] = {
@@ -158,55 +94,79 @@ const GroupSessionWorkspace = () => {
158
94
  obsDatetime: obsTime.toISOString(),
159
95
  };
160
96
  });
161
- // If this is a newly created encounter and visit, add session concepts to encounter payload.
97
+ const visitUuid = activeVisitUuid ? activeVisitUuid : uuid();
162
98
  if (!activeVisitUuid) {
163
99
  Object.entries(groupSessionConcepts).forEach(([field, uuid]) => {
164
- payload.obs.push({
165
- concept: uuid,
166
- value: activeSessionMeta?.[field],
167
- });
100
+ if (activeSessionMeta?.[field] != null) {
101
+ payload.obs.push({
102
+ concept: uuid,
103
+ value: activeSessionMeta[field],
104
+ });
105
+ }
168
106
  });
107
+
108
+ const otherIdentifiers = [
109
+ { concept: groupSessionConcepts.cohortId, value: activeGroupUuid },
110
+ { concept: groupSessionConcepts.cohortName, value: activeGroupName },
111
+ {
112
+ concept: groupSessionConcepts.sessionUuid,
113
+ value: activeSessionUuid,
114
+ },
115
+ ];
116
+ payload.obs.push(...otherIdentifiers);
117
+ // If this is a newly created encounter and visit, add session concepts to encounter payload.
118
+ const visitInfo = {
119
+ startDatetime: activeSessionMeta.sessionDate,
120
+ stopDatetime: activeSessionMeta.sessionDate,
121
+ uuid: visitUuid,
122
+ patient: {
123
+ uuid: activePatientUuid,
124
+ },
125
+ location: {
126
+ uuid: sessionLocation?.uuid,
127
+ },
128
+ visitType: {
129
+ uuid: groupVisitTypeUuid,
130
+ },
131
+ };
132
+ payload.visit = visitInfo;
133
+ updateVisitUuid(visitUuid);
169
134
  }
170
135
  payload.location = sessionLocation?.uuid;
171
136
  payload.encounterDatetime = obsTime.toISOString();
172
137
  },
173
138
  [
174
- activePatientUuid,
175
- activeVisitUuid,
176
139
  activeSessionMeta,
140
+ activeVisitUuid,
141
+ sessionLocation?.uuid,
177
142
  groupSessionConcepts,
143
+ activeGroupUuid,
144
+ activeGroupName,
145
+ activeSessionUuid,
146
+ activePatientUuid,
178
147
  groupVisitTypeUuid,
179
- saveVisit,
180
- sessionLocation,
181
- ]
148
+ updateVisitUuid,
149
+ ],
182
150
  );
183
151
 
184
- // 3. Update encounter so that it belongs to the created visit
185
- useEffect(() => {
186
- if (encounter && visit && encounter.patient?.uuid === visit.patient?.uuid) {
187
- updateEncounter({ uuid: encounter.uuid, visit: visit.uuid });
188
- }
189
- }, [encounter, updateEncounter, visit]);
190
-
191
- // 4. Once form has been posted, save the new encounter uuid so we can edit it later
152
+ // Once form has been posted, save the new encounter uuid so we can edit it later
192
153
  const handlePostResponse = useCallback(
193
154
  (encounter) => {
194
155
  if (encounter && encounter.uuid) {
195
156
  saveEncounter(encounter.uuid);
196
- setEncounter(encounter);
197
157
  }
198
158
  },
199
- [saveEncounter]
159
+ [saveEncounter],
200
160
  );
201
161
 
202
162
  const switchPatient = useCallback(
203
163
  (patientUuid) => {
204
164
  submitForNext(patientUuid);
205
165
  },
206
- [submitForNext]
166
+ [submitForNext],
207
167
  );
208
168
 
209
- if (workflowState === "NEW_GROUP_SESSION") return null;
169
+ if (workflowState === 'NEW_GROUP_SESSION') return null;
210
170
 
211
171
  return (
212
172
  <div className={styles.workspace}>
@@ -223,7 +183,7 @@ const GroupSessionWorkspace = () => {
223
183
  />
224
184
  </div>
225
185
  <div className={styles.rightPanel}>
226
- <h4>{t("formsFilled", "Forms filled")}</h4>
186
+ <h4>{t('formsFilled', 'Forms filled')}</h4>
227
187
  <div className={styles.patientCardsSection}>
228
188
  {patientUuids?.map((patientUuid) => (
229
189
  <PatientCard