@openmrs/esm-fast-data-entry-app 1.0.0-pre.9 → 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 (214) hide show
  1. package/README.md +58 -12
  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 -0
  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/{382.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/{735.js.LICENSE.txt → 961.js.LICENSE.txt} +6 -16
  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 +537 -95
  60. package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -1
  61. package/dist/routes.json +1 -0
  62. package/docs/config-icrc-forms.png +0 -0
  63. package/docs/config-other-forms.png +0 -0
  64. package/docs/configuring-form-categories.md +77 -0
  65. package/docs/fde-workflow.mov +0 -0
  66. package/docs/form-workflow-state-diagram.png +0 -0
  67. package/jest.config.json +21 -18
  68. package/package.json +101 -106
  69. package/prettier.config.js +8 -0
  70. package/src/CancelModal.tsx +42 -0
  71. package/src/CompleteModal.tsx +35 -0
  72. package/src/FormBootstrap.tsx +179 -0
  73. package/src/Root.tsx +11 -5
  74. package/src/add-group-modal/AddGroupModal.tsx +249 -0
  75. package/src/add-group-modal/styles.scss +49 -0
  76. package/src/config-schema.ts +124 -31
  77. package/src/constant.ts +1 -1
  78. package/src/context/FormWorkflowContext.tsx +113 -0
  79. package/src/context/FormWorkflowReducer.ts +263 -0
  80. package/src/context/GroupFormWorkflowContext.tsx +155 -0
  81. package/src/context/GroupFormWorkflowReducer.ts +405 -0
  82. package/src/declarations.d.ts +4 -0
  83. package/src/empty-state/EmptyDataIllustration.tsx +39 -0
  84. package/src/empty-state/EmptyState.tsx +28 -0
  85. package/src/empty-state/styles.scss +55 -0
  86. package/src/form-entry-workflow/FormEntryWorkflow.tsx +184 -0
  87. package/src/form-entry-workflow/form-review-card/FormReviewCard.tsx +50 -0
  88. package/src/form-entry-workflow/form-review-card/index.ts +3 -0
  89. package/src/form-entry-workflow/form-review-card/styles.scss +37 -0
  90. package/src/form-entry-workflow/index.ts +3 -0
  91. package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +9 -0
  92. package/src/form-entry-workflow/patient-banner/PatientBanner.tsx +73 -0
  93. package/src/form-entry-workflow/patient-banner/index.ts +3 -0
  94. package/src/form-entry-workflow/patient-banner/styles.scss +44 -0
  95. package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +54 -0
  96. package/src/form-entry-workflow/patient-search-header/index.ts +3 -0
  97. package/src/form-entry-workflow/patient-search-header/styles.scss +25 -0
  98. package/src/form-entry-workflow/styles.scss +63 -0
  99. package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +37 -0
  100. package/src/form-entry-workflow/workflow-review/index.ts +3 -0
  101. package/src/form-entry-workflow/workflow-review/styles.scss +30 -0
  102. package/src/forms-app-menu-link.tsx +6 -7
  103. package/src/forms-page/FormsPage.tsx +106 -0
  104. package/src/forms-page/forms-table/FormsTable.tsx +117 -0
  105. package/src/forms-page/forms-table/index.ts +3 -0
  106. package/src/forms-page/forms-table/styles.scss +19 -0
  107. package/src/forms-page/index.ts +3 -0
  108. package/src/forms-page/styles.scss +9 -0
  109. package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +26 -0
  110. package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +207 -0
  111. package/src/group-form-entry-workflow/SessionDetailsForm.tsx +154 -0
  112. package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +99 -0
  113. package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +130 -0
  114. package/src/group-form-entry-workflow/attendance-table/index.ts +1 -0
  115. package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +41 -0
  116. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.test.tsx +9 -0
  117. package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +55 -0
  118. package/src/group-form-entry-workflow/group-display-header/index.ts +3 -0
  119. package/src/group-form-entry-workflow/group-display-header/styles.scss +60 -0
  120. package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +128 -0
  121. package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +66 -0
  122. package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +134 -0
  123. package/src/group-form-entry-workflow/group-search/compact-group-result.scss +63 -0
  124. package/src/group-form-entry-workflow/group-search/compact-group-search.scss +34 -0
  125. package/src/group-form-entry-workflow/group-search/group-search.scss +93 -0
  126. package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +72 -0
  127. package/src/group-form-entry-workflow/group-search-header/index.ts +3 -0
  128. package/src/group-form-entry-workflow/group-search-header/styles.scss +20 -0
  129. package/src/group-form-entry-workflow/index.ts +3 -0
  130. package/src/group-form-entry-workflow/styles.scss +94 -0
  131. package/src/hooks/index.ts +8 -0
  132. package/src/hooks/useForm.ts +56 -0
  133. package/src/hooks/useFormState.ts +23 -0
  134. package/src/hooks/useGetAllForms.ts +37 -0
  135. package/src/hooks/useGetEncounter.ts +21 -0
  136. package/src/hooks/useGetPatient.ts +23 -0
  137. package/src/hooks/useGetPatients.ts +32 -0
  138. package/src/hooks/useGetSystemSetting.ts +36 -0
  139. package/src/hooks/useKeyPress.ts +31 -0
  140. package/src/hooks/usePostEndpoint.ts +76 -0
  141. package/src/hooks/useSearchEndpoint.ts +103 -0
  142. package/src/hooks/useStartVisit.ts +82 -0
  143. package/src/index.ts +18 -66
  144. package/src/patient-card/PatientCard.tsx +55 -0
  145. package/src/patient-card/index.ts +3 -0
  146. package/src/patient-card/styles.scss +44 -0
  147. package/src/routes.json +24 -0
  148. package/src/setup-tests.ts +1 -1
  149. package/src/types.ts +20 -0
  150. package/tools/i18next-parser.config.js +93 -0
  151. package/translations/am.json +75 -0
  152. package/translations/ar.json +75 -0
  153. package/translations/en.json +75 -4
  154. package/translations/es.json +75 -0
  155. package/translations/fr.json +75 -0
  156. package/translations/he.json +75 -0
  157. package/translations/km.json +75 -0
  158. package/tsconfig.json +26 -23
  159. package/turbo.json +18 -0
  160. package/webpack.config.js +1 -1
  161. package/.editorconfig +0 -12
  162. package/.eslintignore +0 -2
  163. package/.eslintrc +0 -4
  164. package/.github/workflows/node.js.yml +0 -79
  165. package/.husky/pre-commit +0 -6
  166. package/.husky/pre-push +0 -6
  167. package/.prettierignore +0 -14
  168. package/dist/24.js +0 -3
  169. package/dist/24.js.LICENSE.txt +0 -16
  170. package/dist/24.js.map +0 -1
  171. package/dist/294.js +0 -3
  172. package/dist/294.js.map +0 -1
  173. package/dist/296.js +0 -2
  174. package/dist/296.js.map +0 -1
  175. package/dist/299.js +0 -2
  176. package/dist/299.js.map +0 -1
  177. package/dist/382.js +0 -3
  178. package/dist/382.js.map +0 -1
  179. package/dist/415.js +0 -2
  180. package/dist/415.js.map +0 -1
  181. package/dist/574.js +0 -1
  182. package/dist/595.js +0 -3
  183. package/dist/595.js.LICENSE.txt +0 -1
  184. package/dist/595.js.map +0 -1
  185. package/dist/69.js +0 -2
  186. package/dist/69.js.map +0 -1
  187. package/dist/735.js +0 -3
  188. package/dist/735.js.map +0 -1
  189. package/dist/777.js +0 -2
  190. package/dist/777.js.map +0 -1
  191. package/dist/860.js +0 -2
  192. package/dist/860.js.map +0 -1
  193. package/dist/906.js +0 -2
  194. package/dist/906.js.map +0 -1
  195. package/dist/openmrs-esm-fast-data-entry-app.old +0 -2
  196. package/src/boxes/extensions/blue-box.tsx +0 -15
  197. package/src/boxes/extensions/box.scss +0 -23
  198. package/src/boxes/extensions/brand-box.tsx +0 -15
  199. package/src/boxes/extensions/red-box.tsx +0 -15
  200. package/src/boxes/slot/boxes.css +0 -23
  201. package/src/boxes/slot/boxes.tsx +0 -19
  202. package/src/declarations.d.tsx +0 -2
  203. package/src/forms/FormsRoot.tsx +0 -32
  204. package/src/forms/FormsTable.tsx +0 -64
  205. package/src/forms/mockData.ts +0 -43
  206. package/src/greeter/greeter.css +0 -4
  207. package/src/greeter/greeter.test.tsx +0 -29
  208. package/src/greeter/greeter.tsx +0 -25
  209. package/src/hello.css +0 -3
  210. package/src/hello.test.tsx +0 -45
  211. package/src/hello.tsx +0 -30
  212. package/src/patient-getter/patient-getter.resource.ts +0 -31
  213. package/src/patient-getter/patient-getter.test.tsx +0 -28
  214. package/src/patient-getter/patient-getter.tsx +0 -28
@@ -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,75 +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 { getAsyncLifecycle, defineConfigSchema } from "@openmrs/esm-framework";
9
- import { configSchema } from "./config-schema";
4
+ const moduleName = '@openmrs/esm-fast-data-entry-app';
10
5
 
11
- /**
12
- * This tells the app shell how to obtain translation files: that they
13
- * are JSON files in the directory `../translations` (which you should
14
- * see in the directory structure).
15
- */
16
- const importTranslation = require.context(
17
- "../translations",
18
- false,
19
- /.json$/,
20
- "lazy"
21
- );
22
-
23
- /**
24
- * This tells the app shell what versions of what OpenMRS backend modules
25
- * are expected. Warnings will appear if suitable modules are not
26
- * installed. The keys are the part of the module name after
27
- * `openmrs-module-`; e.g., `openmrs-module-fhir2` becomes `fhir2`.
28
- */
29
- const backendDependencies = {
30
- fhir2: "^1.2.0",
31
- "webservices.rest": "^2.2.0",
6
+ const options = {
7
+ featureName: 'fast-data-entry-app',
8
+ moduleName,
32
9
  };
33
10
 
34
- /**
35
- * This function performs any setup that should happen at microfrontend
36
- * load-time (such as defining the config schema) and then returns an
37
- * object which describes how the React application(s) should be
38
- * rendered.
39
- *
40
- * In this example, our return object contains a single page definition.
41
- * It tells the app shell that the default export of `greeter.tsx`
42
- * should be rendered when the route matches `hello`. The full route
43
- * will be `openmrsSpaBase() + 'hello'`, which is usually
44
- * `/openmrs/spa/hello`.
45
- */
46
- function setupOpenMRS() {
47
- const moduleName = "@openmrs/esm-fast-data-entry";
11
+ export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
12
+
13
+ export const root = getAsyncLifecycle(() => import('./Root'), options);
48
14
 
49
- const options = {
50
- featureName: "fast-data-entry",
51
- moduleName,
52
- };
15
+ export const formsAppMenuLink = getAsyncLifecycle(() => import('./forms-app-menu-link'), options);
53
16
 
17
+ export function startupApp() {
54
18
  defineConfigSchema(moduleName, configSchema);
55
19
 
56
- return {
57
- pages: [
58
- {
59
- load: getAsyncLifecycle(() => import("./Root"), options),
60
- route: "forms",
61
- },
62
- ],
63
- extensions: [
64
- {
65
- name: "forms-app-link",
66
- slot: "app-menu-slot",
67
- load: getAsyncLifecycle(() => import("./forms-app-menu-link"), options),
68
- online: true,
69
- offline: true,
70
- },
71
- ],
72
- };
20
+ registerBreadcrumbs([
21
+ {
22
+ path: `${window.spaBase}/forms`,
23
+ title: 'Forms',
24
+ parent: `${window.spaBase}/home`,
25
+ },
26
+ ]);
73
27
  }
74
-
75
- export { backendDependencies, importTranslation, setupOpenMRS };
@@ -0,0 +1,55 @@
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';
6
+
7
+ const CardContainer = ({ onClick = () => undefined, active, children }) => {
8
+ return (
9
+ <div
10
+ onClick={onClick}
11
+ className={`${styles.cardContainer} ${!active && styles.inactiveCard}`}
12
+ role="button"
13
+ tabIndex={0}
14
+ >
15
+ {children}
16
+ </div>
17
+ );
18
+ };
19
+
20
+ const PatientCard = ({ patientUuid, activePatientUuid, editEncounter, encounters }) => {
21
+ const patient = useGetPatient(patientUuid);
22
+ const givenName = patient?.name?.[0]?.given?.[0];
23
+ const familyName = patient?.name?.[0]?.family;
24
+ const identifier = patient?.identifier?.[0]?.value;
25
+
26
+ if (!patient) {
27
+ return (
28
+ <CardContainer active={true}>
29
+ <SkeletonText className={styles.skeletonText} />
30
+ </CardContainer>
31
+ );
32
+ }
33
+
34
+ const active = activePatientUuid === patientUuid;
35
+
36
+ return (
37
+ <CardContainer onClick={active ? () => undefined : () => editEncounter(patientUuid)} active={active}>
38
+ <div className={styles.patientInfo}>
39
+ <div className={styles.identifier}>{identifier}</div>
40
+ <div className={`${styles.displayName} ${active && styles.activeDisplayName}`}>
41
+ {givenName} {familyName}
42
+ </div>
43
+ </div>
44
+ <div>
45
+ {patientUuid in encounters ? (
46
+ <CheckmarkOutline size={16} className={styles.statusSuccess} />
47
+ ) : (
48
+ <WarningAlt size={16} className={styles.statusWarning} />
49
+ )}
50
+ </div>
51
+ </CardContainer>
52
+ );
53
+ };
54
+
55
+ export default PatientCard;
@@ -0,0 +1,3 @@
1
+ import PatientCard from './PatientCard';
2
+
3
+ export default PatientCard;
@@ -0,0 +1,44 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+
4
+ .cardContainer {
5
+ padding: layout.$spacing-05;
6
+ display: flex;
7
+ cursor: pointer;
8
+ }
9
+
10
+ .skeletonText {
11
+ max-width: 8rem;
12
+ }
13
+
14
+ .identifier {
15
+ font-weight: 300;
16
+ font-size: 0.8rem;
17
+ line-height: 0.9rem;
18
+ }
19
+
20
+ .displayName {
21
+ font-weight: bold;
22
+ }
23
+
24
+ .activeDisplayName {
25
+ color: colors.$blue-50;
26
+ }
27
+
28
+ .inactiveCard {
29
+ &:hover {
30
+ background-color: colors.$gray-30;
31
+ }
32
+ }
33
+
34
+ .patientInfo {
35
+ flex-grow: 1;
36
+ }
37
+
38
+ .statusSuccess {
39
+ fill: colors.$green-60;
40
+ }
41
+
42
+ .statusWarning {
43
+ fill: colors.$yellow-40;
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';
package/src/types.ts ADDED
@@ -0,0 +1,20 @@
1
+ export interface Concept {
2
+ uuid: string;
3
+ display: string;
4
+ }
5
+
6
+ export interface SpecificQuestion {
7
+ question: {
8
+ id: string;
9
+ display: string;
10
+ };
11
+ answers: Array<{
12
+ value: string;
13
+ display: string;
14
+ }>;
15
+ }
16
+
17
+ export interface SpecificQuestionConfig {
18
+ forms: Array<string>;
19
+ questionId: string;
20
+ }