@openmrs/esm-fast-data-entry-app 1.0.0-pre.59 → 1.0.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 (193) hide show
  1. package/README.md +21 -2
  2. package/__mocks__/react-i18next.js +9 -14
  3. package/dist/101.js +1 -0
  4. package/dist/101.js.map +1 -0
  5. package/dist/132.js +1 -1
  6. package/dist/188.js +1 -0
  7. package/dist/188.js.map +1 -0
  8. package/dist/197.js +1 -0
  9. package/dist/219.js +1 -0
  10. package/dist/219.js.map +1 -0
  11. package/dist/221.js +1 -0
  12. package/dist/221.js.map +1 -0
  13. package/dist/259.js +1 -0
  14. package/dist/259.js.map +1 -0
  15. package/dist/29.js +2 -0
  16. package/dist/29.js.LICENSE.txt +3 -0
  17. package/dist/29.js.map +1 -0
  18. package/dist/300.js +1 -0
  19. package/dist/326.js +1 -0
  20. package/dist/326.js.map +1 -0
  21. package/dist/335.js +1 -0
  22. package/dist/367.js +1 -0
  23. package/dist/367.js.map +1 -0
  24. package/dist/480.js +1 -0
  25. package/dist/540.js +2 -0
  26. package/dist/{536.js.LICENSE.txt → 540.js.LICENSE.txt} +3 -2
  27. package/dist/540.js.map +1 -0
  28. package/dist/55.js +1 -0
  29. package/dist/564.js +1 -0
  30. package/dist/564.js.map +1 -0
  31. package/dist/602.js +1 -0
  32. package/dist/602.js.map +1 -0
  33. package/dist/626.js +2 -0
  34. package/dist/{294.js.LICENSE.txt → 626.js.LICENSE.txt} +3 -8
  35. package/dist/626.js.map +1 -0
  36. package/dist/652.js +1 -0
  37. package/dist/685.js +1 -0
  38. package/dist/685.js.map +1 -0
  39. package/dist/773.js +2 -0
  40. package/dist/773.js.LICENSE.txt +32 -0
  41. package/dist/773.js.map +1 -0
  42. package/dist/893.js +1 -0
  43. package/dist/893.js.map +1 -0
  44. package/dist/91.js +1 -0
  45. package/dist/91.js.map +1 -0
  46. package/dist/941.js +2 -0
  47. package/dist/941.js.LICENSE.txt +30 -0
  48. package/dist/941.js.map +1 -0
  49. package/dist/961.js +2 -0
  50. package/dist/{935.js.LICENSE.txt → 961.js.LICENSE.txt} +6 -10
  51. package/dist/961.js.map +1 -0
  52. package/dist/99.js +1 -0
  53. package/dist/99.js.map +1 -0
  54. package/dist/991.js +1 -0
  55. package/dist/991.js.map +1 -0
  56. package/dist/main.js +1 -0
  57. package/dist/main.js.map +1 -0
  58. package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
  59. package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +500 -122
  60. package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -0
  61. package/dist/routes.json +1 -0
  62. package/jest.config.json +21 -18
  63. package/package.json +59 -62
  64. package/prettier.config.js +8 -0
  65. package/src/CancelModal.tsx +42 -0
  66. package/src/CompleteModal.tsx +35 -0
  67. package/src/FormBootstrap.tsx +45 -10
  68. package/src/Root.tsx +11 -9
  69. package/src/add-group-modal/AddGroupModal.tsx +249 -0
  70. package/src/add-group-modal/styles.scss +49 -0
  71. package/src/config-schema.ts +77 -16
  72. package/src/constant.ts +1 -1
  73. package/src/context/FormWorkflowContext.tsx +32 -33
  74. package/src/context/FormWorkflowReducer.ts +53 -67
  75. package/src/context/GroupFormWorkflowContext.tsx +155 -0
  76. package/src/context/GroupFormWorkflowReducer.ts +405 -0
  77. package/src/declarations.d.ts +4 -0
  78. package/src/empty-state/EmptyDataIllustration.tsx +4 -16
  79. package/src/empty-state/EmptyState.tsx +16 -17
  80. package/src/empty-state/styles.scss +14 -14
  81. package/src/form-entry-workflow/FormEntryWorkflow.tsx +89 -125
  82. package/src/{form-review-card → form-entry-workflow/form-review-card}/FormReviewCard.tsx +7 -7
  83. package/src/form-entry-workflow/form-review-card/index.ts +3 -0
  84. package/src/form-entry-workflow/form-review-card/styles.scss +37 -0
  85. package/src/form-entry-workflow/index.ts +1 -1
  86. package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +9 -0
  87. package/src/{patient-banner → form-entry-workflow/patient-banner}/PatientBanner.tsx +14 -27
  88. package/src/form-entry-workflow/patient-banner/index.ts +3 -0
  89. package/src/form-entry-workflow/patient-banner/styles.scss +44 -0
  90. package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +54 -0
  91. package/src/form-entry-workflow/patient-search-header/index.ts +3 -0
  92. package/src/form-entry-workflow/patient-search-header/styles.scss +25 -0
  93. package/src/form-entry-workflow/styles.scss +16 -16
  94. package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +37 -0
  95. package/src/form-entry-workflow/workflow-review/index.ts +3 -0
  96. package/src/{workflow-review → form-entry-workflow/workflow-review}/styles.scss +0 -4
  97. package/src/forms-app-menu-link.tsx +5 -7
  98. package/src/forms-page/FormsPage.tsx +48 -37
  99. package/src/forms-page/forms-table/FormsTable.tsx +117 -0
  100. package/src/forms-page/forms-table/index.ts +3 -0
  101. package/src/forms-page/forms-table/styles.scss +19 -0
  102. package/src/forms-page/index.ts +1 -1
  103. package/src/forms-page/styles.scss +3 -5
  104. package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +26 -0
  105. package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +207 -0
  106. package/src/group-form-entry-workflow/SessionDetailsForm.tsx +154 -0
  107. package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +99 -0
  108. package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +130 -0
  109. package/src/group-form-entry-workflow/attendance-table/index.ts +1 -0
  110. package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +41 -0
  111. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.test.tsx +9 -0
  112. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +55 -0
  113. package/src/group-form-entry-workflow/group-display-header/index.ts +3 -0
  114. package/src/group-form-entry-workflow/group-display-header/styles.scss +60 -0
  115. package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +128 -0
  116. package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +66 -0
  117. package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +134 -0
  118. package/src/group-form-entry-workflow/group-search/compact-group-result.scss +63 -0
  119. package/src/group-form-entry-workflow/group-search/compact-group-search.scss +34 -0
  120. package/src/group-form-entry-workflow/group-search/group-search.scss +93 -0
  121. package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +72 -0
  122. package/src/group-form-entry-workflow/group-search-header/index.ts +3 -0
  123. package/src/group-form-entry-workflow/group-search-header/styles.scss +20 -0
  124. package/src/group-form-entry-workflow/index.ts +3 -0
  125. package/src/group-form-entry-workflow/styles.scss +94 -0
  126. package/src/hooks/index.ts +7 -5
  127. package/src/hooks/useForm.ts +56 -0
  128. package/src/hooks/useFormState.ts +3 -3
  129. package/src/hooks/useGetAllForms.ts +7 -15
  130. package/src/hooks/useGetEncounter.ts +3 -3
  131. package/src/hooks/useGetPatient.ts +3 -3
  132. package/src/hooks/useGetPatients.ts +32 -0
  133. package/src/hooks/useGetSystemSetting.ts +36 -0
  134. package/src/hooks/useKeyPress.ts +31 -0
  135. package/src/hooks/usePostEndpoint.ts +76 -0
  136. package/src/hooks/useSearchEndpoint.ts +103 -0
  137. package/src/hooks/useStartVisit.ts +82 -0
  138. package/src/index.ts +12 -72
  139. package/src/patient-card/PatientCard.tsx +10 -20
  140. package/src/patient-card/index.ts +1 -1
  141. package/src/patient-card/styles.scss +8 -8
  142. package/src/routes.json +24 -0
  143. package/src/setup-tests.ts +1 -1
  144. package/src/types.ts +20 -0
  145. package/tools/i18next-parser.config.js +93 -0
  146. package/translations/am.json +75 -0
  147. package/translations/ar.json +75 -0
  148. package/translations/en.json +57 -2
  149. package/translations/es.json +75 -0
  150. package/translations/fr.json +75 -0
  151. package/translations/he.json +75 -0
  152. package/translations/km.json +75 -0
  153. package/turbo.json +18 -0
  154. package/webpack.config.js +1 -1
  155. package/.editorconfig +0 -12
  156. package/.eslintignore +0 -2
  157. package/.eslintrc.js +0 -10
  158. package/.github/pull_request_template.md +0 -18
  159. package/.github/workflows/node.js.yml +0 -121
  160. package/.husky/pre-push +0 -1
  161. package/.prettierignore +0 -14
  162. package/dist/187.js +0 -1
  163. package/dist/247.js +0 -1
  164. package/dist/294.js +0 -2
  165. package/dist/312.js +0 -1
  166. package/dist/412.js +0 -1
  167. package/dist/536.js +0 -2
  168. package/dist/574.js +0 -1
  169. package/dist/592.js +0 -1
  170. package/dist/595.js +0 -2
  171. package/dist/595.js.LICENSE.txt +0 -1
  172. package/dist/776.js +0 -1
  173. package/dist/804.js +0 -1
  174. package/dist/880.js +0 -2
  175. package/dist/880.js.LICENSE.txt +0 -20
  176. package/dist/906.js +0 -1
  177. package/dist/935.js +0 -2
  178. package/dist/990.js +0 -1
  179. package/dist/openmrs-esm-fast-data-entry-app.old +0 -1
  180. package/src/declarations.d.tsx +0 -2
  181. package/src/form-review-card/index.ts +0 -3
  182. package/src/form-review-card/styles.scss +0 -38
  183. package/src/forms-table/FormsTable.tsx +0 -123
  184. package/src/forms-table/index.ts +0 -3
  185. package/src/forms-table/styles.scss +0 -20
  186. package/src/patient-banner/PatientBanner.test.tsx +0 -9
  187. package/src/patient-banner/index.ts +0 -3
  188. package/src/patient-banner/styles.scss +0 -44
  189. package/src/patient-search-header/PatientSearchHeader.tsx +0 -61
  190. package/src/patient-search-header/index.ts +0 -3
  191. package/src/patient-search-header/styles.scss +0 -21
  192. package/src/workflow-review/WorkflowReview.tsx +0 -35
  193. package/src/workflow-review/index.ts +0 -3
@@ -1,15 +1,11 @@
1
- import {
2
- openmrsFetch,
3
- userHasAccess,
4
- useSession,
5
- } from "@openmrs/esm-framework";
6
- import useSWR from "swr";
1
+ import { openmrsFetch, userHasAccess, useSession, restBaseUrl } from '@openmrs/esm-framework';
2
+ import useSWR from 'swr';
7
3
 
8
4
  const customFormRepresentation =
9
- "(uuid,name,display,encounterType:(uuid,name,viewPrivilege,editPrivilege),version,published,retired,resources:(uuid,name,dataType,valueReference))";
5
+ '(uuid,name,display,encounterType:(uuid,name,viewPrivilege,editPrivilege),version,published,retired,resources:(uuid,name,dataType,valueReference))';
10
6
 
11
- const formEncounterUrl = `/ws/rest/v1/form?v=custom:${customFormRepresentation}`;
12
- const formEncounterUrlPoc = `/ws/rest/v1/form?v=custom:${customFormRepresentation}&q=poc`;
7
+ const formEncounterUrl = `${restBaseUrl}/form?v=custom:${customFormRepresentation}`;
8
+ const formEncounterUrlPoc = `${restBaseUrl}/form?v=custom:${customFormRepresentation}&q=poc`;
13
9
 
14
10
  export function useGetAllForms(cachedOfflineFormsOnly = false) {
15
11
  const session = useSession();
@@ -24,7 +20,7 @@ export function useGetAllForms(cachedOfflineFormsOnly = false) {
24
20
  // forms should be published
25
21
  form.published &&
26
22
  // forms should not be component forms
27
- !/component/i.test(form.name)
23
+ !/component/i.test(form.name),
28
24
  // user should have privileges to edit forms
29
25
  ) ?? [];
30
26
 
@@ -32,11 +28,7 @@ export function useGetAllForms(cachedOfflineFormsOnly = false) {
32
28
  });
33
29
 
34
30
  return {
35
- forms: data?.filter((form) =>
36
- Boolean(
37
- userHasAccess(form.encounterType?.editPrivilege?.display, session?.user)
38
- )
39
- ),
31
+ forms: data?.filter((form) => Boolean(userHasAccess(form.encounterType?.editPrivilege?.display, session?.user))),
40
32
  isLoading: !error && !data,
41
33
  error,
42
34
  };
@@ -1,7 +1,7 @@
1
- import { openmrsFetch } from "@openmrs/esm-framework";
2
- import useSWR from "swr";
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import useSWR from 'swr';
3
3
 
4
- const encounterUrl = "/ws/rest/v1/encounter/";
4
+ const encounterUrl = `${restBaseUrl}/encounter/`;
5
5
 
6
6
  const useGetEncounter = (encounterUuid) => {
7
7
  const url = `${encounterUrl}${encounterUuid}`;
@@ -1,5 +1,5 @@
1
- import { fetchCurrentPatient } from "@openmrs/esm-framework";
2
- import { useEffect, useState } from "react";
1
+ import { fetchCurrentPatient } from '@openmrs/esm-framework';
2
+ import { useEffect, useState } from 'react';
3
3
 
4
4
  const useGetPatient = (patientUuid) => {
5
5
  const [patient, setPatient] = useState(null);
@@ -14,7 +14,7 @@ const useGetPatient = (patientUuid) => {
14
14
 
15
15
  const getPatient = async (uuid) => {
16
16
  const result = await fetchCurrentPatient(uuid);
17
- setPatient(result?.data);
17
+ setPatient(result);
18
18
  };
19
19
 
20
20
  return patient;
@@ -0,0 +1,32 @@
1
+ import { fetchCurrentPatient } from '@openmrs/esm-framework';
2
+ import { useEffect, useState } from 'react';
3
+
4
+ const useGetPatients = (patientUuids) => {
5
+ const [patients, setPatients] = useState([]);
6
+ const [isLoading, setIsLoading] = useState(true);
7
+
8
+ useEffect(() => {
9
+ if (!patientUuids || patientUuids.length === 0) {
10
+ setPatients([]);
11
+ setIsLoading(false);
12
+ } else {
13
+ getPatients(patientUuids);
14
+ }
15
+ }, [patientUuids]);
16
+
17
+ const getPatients = async (uuids) => {
18
+ try {
19
+ setIsLoading(true);
20
+ const results = await Promise.all(uuids.map(async (uuid) => await fetchCurrentPatient(uuid)));
21
+ setPatients(results);
22
+ setIsLoading(false);
23
+ } catch (error) {
24
+ console.error('Error fetching patients:', error);
25
+ setIsLoading(false);
26
+ }
27
+ };
28
+
29
+ return { patients, isLoading };
30
+ };
31
+
32
+ export default useGetPatients;
@@ -0,0 +1,36 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
3
+
4
+ const useGetSystemSetting = (settingId) => {
5
+ const [isSubmitting, setIsSubmitting] = useState(false);
6
+ const [result, setResult] = useState(null);
7
+ const [error, setError] = useState(null);
8
+
9
+ const onResult = useCallback((result) => {
10
+ setIsSubmitting(false);
11
+ setError(false);
12
+ setResult(result);
13
+ }, []);
14
+
15
+ const onError = useCallback((error) => {
16
+ setIsSubmitting(false);
17
+ setResult(null);
18
+ setError(error);
19
+ }, []);
20
+
21
+ const getSetting = useCallback(() => {
22
+ openmrsFetch(`${restBaseUrl}/systemsetting?q=${settingId}&v=default`).then(onResult).catch(onError);
23
+ }, [onError, onResult, settingId]);
24
+
25
+ useEffect(() => {
26
+ getSetting();
27
+ }, [getSetting]);
28
+
29
+ return {
30
+ result,
31
+ error,
32
+ isSubmitting,
33
+ };
34
+ };
35
+
36
+ export default useGetSystemSetting;
@@ -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;
@@ -0,0 +1,76 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { useCallback, useState } from 'react';
3
+
4
+ const usePostEndpoint = ({ endpointUrl }) => {
5
+ const [submissionInProgress, setSubmissionInProgress] = useState(null);
6
+ const [result, setResult] = useState(null);
7
+ const [error, setError] = useState(null);
8
+
9
+ const onFormPosted = useCallback(
10
+ (result) => {
11
+ setSubmissionInProgress(false);
12
+ if (error) {
13
+ setError(null);
14
+ }
15
+ setResult(result.data);
16
+ },
17
+ [error],
18
+ );
19
+
20
+ const onError = useCallback(
21
+ (error) => {
22
+ setSubmissionInProgress(false);
23
+ if (result) {
24
+ setResult(null);
25
+ }
26
+ setError(error?.responseBody?.error ?? error?.responseBody ?? error);
27
+ },
28
+ [result],
29
+ );
30
+
31
+ const post = useCallback(
32
+ async (data) => {
33
+ setSubmissionInProgress(true);
34
+
35
+ let path = endpointUrl;
36
+ if (data.uuid) {
37
+ path += '/' + data.uuid;
38
+ }
39
+
40
+ return openmrsFetch(path, {
41
+ method: 'POST',
42
+ headers: {
43
+ 'Content-Type': 'application/json',
44
+ },
45
+ body: data,
46
+ })
47
+ .then(onFormPosted)
48
+ .catch(onError);
49
+ },
50
+ [endpointUrl, onError, onFormPosted],
51
+ );
52
+
53
+ const reset = () => {
54
+ setSubmissionInProgress(null);
55
+ setResult(null);
56
+ setError(null);
57
+ };
58
+
59
+ return {
60
+ post,
61
+ isPosting: submissionInProgress,
62
+ result,
63
+ error,
64
+ reset,
65
+ };
66
+ };
67
+
68
+ const usePostVisit = () => {
69
+ return usePostEndpoint({ endpointUrl: `${restBaseUrl}/visit` });
70
+ };
71
+
72
+ const usePostCohort = () => {
73
+ return usePostEndpoint({ endpointUrl: `${restBaseUrl}/cohortm/cohort` });
74
+ };
75
+
76
+ export { usePostEndpoint, usePostVisit, usePostCohort };
@@ -0,0 +1,103 @@
1
+ import { openmrsFetch, type FetchResponse, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { useCallback, useMemo } from 'react';
3
+ import useSWRInfinite from 'swr/infinite';
4
+
5
+ export interface SearchResponse {
6
+ data: Array<Record<string, unknown>> | null;
7
+ isLoading: boolean;
8
+ error: Error;
9
+ loadingNewData: boolean;
10
+ hasMore: boolean;
11
+ currentPage: number;
12
+ totalResults: number;
13
+ setPage: (size: number | ((_size: number) => number)) => Promise<
14
+ Array<
15
+ FetchResponse<{
16
+ results: Array<Record<string, unknown>>;
17
+ links: Array<{
18
+ rel: 'prev' | 'next';
19
+ }>;
20
+ }>
21
+ >
22
+ >;
23
+ }
24
+
25
+ interface SearchInfiniteProps {
26
+ baseUrl?: string;
27
+ searchTerm: string;
28
+ parameters?: Record<string, unknown> | undefined;
29
+ searching: boolean;
30
+ resultsToFetch?: number;
31
+ }
32
+
33
+ const useSearchEndpointInfinite = (arg0: SearchInfiniteProps): SearchResponse => {
34
+ const { baseUrl, searchTerm, parameters, searching = true, resultsToFetch = 10 } = arg0;
35
+
36
+ const getUrl = useCallback(
37
+ (
38
+ page: number,
39
+ prevPageData: FetchResponse<{
40
+ results: Array<Record<string, unknown>>;
41
+ links: Array<{ rel: 'prev' | 'next' }>;
42
+ }>,
43
+ ) => {
44
+ if (prevPageData && !prevPageData?.data?.links.some((link) => link.rel === 'next')) {
45
+ return null;
46
+ }
47
+ let url = `${baseUrl}?q=${searchTerm}`;
48
+ const params = {
49
+ // merge passed parameters and default parameters
50
+ // this way the defaults can be overriden if needed
51
+ totalCount: true,
52
+ limit: resultsToFetch,
53
+ ...parameters,
54
+ };
55
+ Object.entries(params).forEach(([key, value]) => {
56
+ // don't send null parmeters
57
+ if (value !== null && value !== undefined) {
58
+ url += `&${key}=${value}`;
59
+ }
60
+ });
61
+ if (page) {
62
+ url += `&startIndex=${page * resultsToFetch}`;
63
+ }
64
+ return url;
65
+ },
66
+ [baseUrl, searchTerm, parameters, resultsToFetch],
67
+ );
68
+
69
+ const { data, isValidating, setSize, error, size } = useSWRInfinite<
70
+ FetchResponse<{
71
+ results: Array<Record<string, unknown>>;
72
+ links: Array<{ rel: 'prev' | 'next' }>;
73
+ totalCount: number;
74
+ }>,
75
+ Error
76
+ >(searching ? getUrl : null, openmrsFetch);
77
+
78
+ const results = useMemo(
79
+ () => ({
80
+ data: data ? [].concat(...(data?.map((resp) => resp?.data?.results) ?? [])) : null,
81
+ isLoading: !data && !error,
82
+ error,
83
+ hasMore: data?.length ? !!data[data.length - 1].data?.links?.some((link) => link.rel === 'next') : false,
84
+ loadingNewData: isValidating,
85
+ setPage: setSize,
86
+ currentPage: size,
87
+ totalResults: data?.[0]?.data?.totalCount,
88
+ }),
89
+ [data, isValidating, error, setSize, size],
90
+ );
91
+
92
+ return results;
93
+ };
94
+
95
+ const useSearchCohortInfinite = ({ ...props }: SearchInfiniteProps): SearchResponse => {
96
+ return useSearchEndpointInfinite({
97
+ baseUrl: `${restBaseUrl}/cohortm/cohort`,
98
+ resultsToFetch: 10,
99
+ ...props,
100
+ });
101
+ };
102
+
103
+ export { useSearchEndpointInfinite, useSearchCohortInfinite };
@@ -0,0 +1,82 @@
1
+ import { useCallback, useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { showNotification, showToast, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
4
+
5
+ const useStartVisit = ({ showSuccessNotification = true, showErrorNotification = true }) => {
6
+ const { t } = useTranslation();
7
+ const [isSubmitting, setIsSubmitting] = useState(false);
8
+ const [success, setSuccess] = useState(null);
9
+ const [error, setError] = useState(null);
10
+
11
+ const onSave = useCallback(
12
+ (result) => {
13
+ setIsSubmitting(false);
14
+ setError(false);
15
+ setSuccess(result);
16
+ if (showSuccessNotification) {
17
+ showToast({
18
+ critical: true,
19
+ kind: 'success',
20
+ description: t('visitStartedSuccessfully', `${result?.data?.visitType?.display} started successfully`),
21
+ title: t('visitStarted', 'Visit started'),
22
+ });
23
+ }
24
+ },
25
+ [t, showSuccessNotification],
26
+ );
27
+
28
+ const onError = useCallback(
29
+ (error) => {
30
+ setIsSubmitting(false);
31
+ setSuccess(false);
32
+ setError(error);
33
+ if (showErrorNotification) {
34
+ showNotification({
35
+ title: t('startVisitError', 'Error starting visit'),
36
+ kind: 'error',
37
+ critical: true,
38
+ description: error?.message,
39
+ });
40
+ }
41
+ },
42
+ [t, showErrorNotification],
43
+ );
44
+
45
+ const saveVisit = useCallback(
46
+ (data) => {
47
+ const payload = {
48
+ patient: data.patientUuid,
49
+ startDatetime: data.startDatetime,
50
+ stopDatetime: data.stopDatetime,
51
+ visitType: data.visitType,
52
+ location: data.location,
53
+ };
54
+ openmrsFetch(`${restBaseUrl}/visit`, {
55
+ method: 'POST',
56
+ body: payload,
57
+ headers: { 'Content-Type': 'application/json' },
58
+ })
59
+ .then(onSave)
60
+ .catch(onError);
61
+ },
62
+ [onError, onSave],
63
+ );
64
+
65
+ const updateEncounter = useCallback((data) => {
66
+ openmrsFetch(`${restBaseUrl}/encounter/` + data.uuid, {
67
+ method: 'POST',
68
+ body: { visit: data.visit },
69
+ headers: { 'Content-Type': 'application/json' },
70
+ });
71
+ }, []);
72
+
73
+ return {
74
+ saveVisit,
75
+ updateEncounter,
76
+ success,
77
+ error,
78
+ isSubmitting,
79
+ };
80
+ };
81
+
82
+ export default useStartVisit;
package/src/index.ts CHANGED
@@ -1,87 +1,27 @@
1
- /**
2
- * This is the entrypoint file of the application. It communicates the
3
- * important features of this microfrontend to the app shell. It
4
- * connects the app shell to the React application(s) that make up this
5
- * microfrontend.
6
- */
1
+ import { getAsyncLifecycle, defineConfigSchema, registerBreadcrumbs } from '@openmrs/esm-framework';
2
+ import { configSchema } from './config-schema';
7
3
 
8
- import {
9
- getAsyncLifecycle,
10
- defineConfigSchema,
11
- registerBreadcrumbs,
12
- } from "@openmrs/esm-framework";
13
- import { configSchema } from "./config-schema";
4
+ const moduleName = '@openmrs/esm-fast-data-entry-app';
14
5
 
15
- /**
16
- * This tells the app shell how to obtain translation files: that they
17
- * are JSON files in the directory `../translations` (which you should
18
- * see in the directory structure).
19
- */
20
- const importTranslation = require.context(
21
- "../translations",
22
- false,
23
- /.json$/,
24
- "lazy"
25
- );
26
-
27
- /**
28
- * This tells the app shell what versions of what OpenMRS backend modules
29
- * are expected. Warnings will appear if suitable modules are not
30
- * installed. The keys are the part of the module name after
31
- * `openmrs-module-`; e.g., `openmrs-module-fhir2` becomes `fhir2`.
32
- */
33
- const backendDependencies = {
34
- fhir2: "^1.2.0",
35
- "webservices.rest": "^2.2.0",
6
+ const options = {
7
+ featureName: 'fast-data-entry-app',
8
+ moduleName,
36
9
  };
37
10
 
38
- /**
39
- * This function performs any setup that should happen at microfrontend
40
- * load-time (such as defining the config schema) and then returns an
41
- * object which describes how the React application(s) should be
42
- * rendered.
43
- *
44
- * In this example, our return object contains a single page definition.
45
- * It tells the app shell that the default export of `greeter.tsx`
46
- * should be rendered when the route matches `hello`. The full route
47
- * will be `openmrsSpaBase() + 'hello'`, which is usually
48
- * `/openmrs/spa/hello`.
49
- */
50
- function setupOpenMRS() {
51
- const moduleName = "@openmrs/esm-fast-data-entry-app";
11
+ export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
12
+
13
+ export const root = getAsyncLifecycle(() => import('./Root'), options);
52
14
 
53
- const options = {
54
- featureName: "fast-data-entry-app",
55
- moduleName,
56
- };
15
+ export const formsAppMenuLink = getAsyncLifecycle(() => import('./forms-app-menu-link'), options);
57
16
 
17
+ export function startupApp() {
58
18
  defineConfigSchema(moduleName, configSchema);
59
19
 
60
20
  registerBreadcrumbs([
61
21
  {
62
22
  path: `${window.spaBase}/forms`,
63
- title: "Forms",
23
+ title: 'Forms',
64
24
  parent: `${window.spaBase}/home`,
65
25
  },
66
26
  ]);
67
-
68
- return {
69
- pages: [
70
- {
71
- load: getAsyncLifecycle(() => import("./Root"), options),
72
- route: "forms",
73
- },
74
- ],
75
- extensions: [
76
- {
77
- name: "forms-app-link",
78
- slot: "app-menu-slot",
79
- load: getAsyncLifecycle(() => import("./forms-app-menu-link"), options),
80
- online: true,
81
- offline: true,
82
- },
83
- ],
84
- };
85
27
  }
86
-
87
- export { backendDependencies, importTranslation, setupOpenMRS };
@@ -1,9 +1,8 @@
1
- import { CheckmarkOutline16, WarningAlt16 } from "@carbon/icons-react";
2
- import { SkeletonText } from "carbon-components-react";
3
- import React, { useContext } from "react";
4
- import FormWorkflowContext from "../context/FormWorkflowContext";
5
- import useGetPatient from "../hooks/useGetPatient";
6
- import styles from "./styles.scss";
1
+ import { CheckmarkOutline, WarningAlt } from '@carbon/react/icons';
2
+ import { SkeletonText } from '@carbon/react';
3
+ import React from 'react';
4
+ import useGetPatient from '../hooks/useGetPatient';
5
+ import styles from './styles.scss';
7
6
 
8
7
  const CardContainer = ({ onClick = () => undefined, active, children }) => {
9
8
  return (
@@ -18,9 +17,7 @@ const CardContainer = ({ onClick = () => undefined, active, children }) => {
18
17
  );
19
18
  };
20
19
 
21
- const PatientCard = ({ patientUuid }) => {
22
- const { activePatientUuid, editEncounter, encounters } =
23
- useContext(FormWorkflowContext);
20
+ const PatientCard = ({ patientUuid, activePatientUuid, editEncounter, encounters }) => {
24
21
  const patient = useGetPatient(patientUuid);
25
22
  const givenName = patient?.name?.[0]?.given?.[0];
26
23
  const familyName = patient?.name?.[0]?.family;
@@ -37,25 +34,18 @@ const PatientCard = ({ patientUuid }) => {
37
34
  const active = activePatientUuid === patientUuid;
38
35
 
39
36
  return (
40
- <CardContainer
41
- onClick={active ? () => undefined : () => editEncounter(patientUuid)}
42
- active={active}
43
- >
37
+ <CardContainer onClick={active ? () => undefined : () => editEncounter(patientUuid)} active={active}>
44
38
  <div className={styles.patientInfo}>
45
39
  <div className={styles.identifier}>{identifier}</div>
46
- <div
47
- className={`${styles.displayName} ${
48
- active && styles.activeDisplayName
49
- }`}
50
- >
40
+ <div className={`${styles.displayName} ${active && styles.activeDisplayName}`}>
51
41
  {givenName} {familyName}
52
42
  </div>
53
43
  </div>
54
44
  <div>
55
45
  {patientUuid in encounters ? (
56
- <CheckmarkOutline16 className={styles.statusSuccess} />
46
+ <CheckmarkOutline size={16} className={styles.statusSuccess} />
57
47
  ) : (
58
- <WarningAlt16 className={styles.statusWarning} />
48
+ <WarningAlt size={16} className={styles.statusWarning} />
59
49
  )}
60
50
  </div>
61
51
  </CardContainer>
@@ -1,3 +1,3 @@
1
- import PatientCard from "./PatientCard";
1
+ import PatientCard from './PatientCard';
2
2
 
3
3
  export default PatientCard;
@@ -1,10 +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
  .cardContainer {
6
- padding: $spacing-05;
5
+ padding: layout.$spacing-05;
7
6
  display: flex;
7
+ cursor: pointer;
8
8
  }
9
9
 
10
10
  .skeletonText {
@@ -22,12 +22,12 @@
22
22
  }
23
23
 
24
24
  .activeDisplayName {
25
- color: $carbon--blue-50;
25
+ color: colors.$blue-50;
26
26
  }
27
27
 
28
28
  .inactiveCard {
29
29
  &:hover {
30
- background-color: $carbon--gray-40;
30
+ background-color: colors.$gray-30;
31
31
  }
32
32
  }
33
33
 
@@ -36,9 +36,9 @@
36
36
  }
37
37
 
38
38
  .statusSuccess {
39
- fill: $support-02;
39
+ fill: colors.$green-60;
40
40
  }
41
41
 
42
42
  .statusWarning {
43
- fill: $support-03;
43
+ fill: colors.$yellow-40;
44
44
  }
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://json.openmrs.org/routes.schema.json",
3
+ "backendDependencies": {
4
+ "fhir2": ">=1.2",
5
+ "webservices.rest": "^2.2.0"
6
+ },
7
+ "pages": [
8
+ {
9
+ "component": "root",
10
+ "routeRegex": "forms",
11
+ "online": true,
12
+ "offline": true
13
+ }
14
+ ],
15
+ "extensions": [
16
+ {
17
+ "name": "forms-app-link",
18
+ "slot": "app-menu-slot",
19
+ "component": "formsAppMenuLink",
20
+ "online": true,
21
+ "offline": true
22
+ }
23
+ ]
24
+ }
@@ -1 +1 @@
1
- import "@testing-library/jest-dom/extend-expect";
1
+ import '@testing-library/jest-dom/extend-expect';