@openmrs/esm-patient-forms-app 11.3.1-pre.9452 → 11.3.1-pre.9455

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 (62) hide show
  1. package/.turbo/turbo-build.log +14 -15
  2. package/dist/1197.js +1 -1
  3. package/dist/1197.js.map +1 -0
  4. package/dist/2608.js +1 -0
  5. package/dist/2608.js.map +1 -0
  6. package/dist/3578.js +1 -0
  7. package/dist/4341.js +1 -0
  8. package/dist/4341.js.map +1 -0
  9. package/dist/5277.js +1 -0
  10. package/dist/5277.js.map +1 -0
  11. package/dist/5696.js +1 -1
  12. package/dist/5696.js.map +1 -1
  13. package/dist/5764.js +1 -0
  14. package/dist/5764.js.map +1 -0
  15. package/dist/5792.js +2 -0
  16. package/dist/{7906.js.LICENSE.txt → 5792.js.LICENSE.txt} +10 -0
  17. package/dist/5792.js.map +1 -0
  18. package/dist/7003.js +1 -1
  19. package/dist/7003.js.map +1 -1
  20. package/dist/7007.js +1 -1
  21. package/dist/7007.js.map +1 -1
  22. package/dist/707.js +1 -1
  23. package/dist/707.js.map +1 -1
  24. package/dist/main.js +1 -1
  25. package/dist/main.js.map +1 -1
  26. package/dist/openmrs-esm-patient-forms-app.js +1 -1
  27. package/dist/openmrs-esm-patient-forms-app.js.buildmanifest.json +180 -137
  28. package/dist/openmrs-esm-patient-forms-app.js.map +1 -1
  29. package/dist/routes.json +1 -1
  30. package/package.json +2 -2
  31. package/src/clinical-form-action-button.component.tsx +13 -40
  32. package/src/clinical-form-action-button.test.tsx +23 -22
  33. package/src/config-schema.ts +1 -1
  34. package/src/forms/exported-form-entry.workspace.tsx +37 -0
  35. package/src/forms/exported-forms-dashboard.workspace.tsx +43 -0
  36. package/src/forms/form-entry.component.tsx +138 -0
  37. package/src/forms/form-entry.resources.ts +37 -0
  38. package/src/forms/form-entry.test.tsx +14 -28
  39. package/src/forms/form-entry.workspace.tsx +25 -99
  40. package/src/forms/forms-dashboard.component.tsx +13 -58
  41. package/src/forms/forms-dashboard.test.tsx +3 -15
  42. package/src/forms/forms-dashboard.workspace.tsx +34 -10
  43. package/src/forms/forms-list.component.tsx +20 -41
  44. package/src/forms/forms-list.test.tsx +2 -2
  45. package/src/forms/forms-table.component.tsx +1 -1
  46. package/src/hooks/use-forms.ts +3 -4
  47. package/src/index.ts +6 -8
  48. package/src/offline-forms/use-offline-form-encounters.ts +2 -2
  49. package/src/offline.ts +5 -7
  50. package/src/routes.json +13 -49
  51. package/dist/1123.js +0 -2
  52. package/dist/1123.js.LICENSE.txt +0 -9
  53. package/dist/1123.js.map +0 -1
  54. package/dist/2773.js +0 -1
  55. package/dist/2773.js.map +0 -1
  56. package/dist/4078.js +0 -1
  57. package/dist/4078.js.map +0 -1
  58. package/dist/7906.js +0 -2
  59. package/dist/7906.js.map +0 -1
  60. package/dist/8803.js +0 -1
  61. package/dist/8803.js.map +0 -1
  62. package/src/htmlformentry/html-form-entry.workspace.tsx +0 -54
@@ -1,54 +1,27 @@
1
1
  import React, { type ComponentProps } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
- import { ActionMenuButton, DocumentIcon, launchWorkspace, useWorkspaces } from '@openmrs/esm-framework';
4
- import {
5
- clinicalFormsWorkspace,
6
- formEntryWorkspace,
7
- htmlFormEntryWorkspace,
8
- useLaunchWorkspaceRequiringVisit,
9
- } from '@openmrs/esm-patient-common-lib';
3
+ import { ActionMenuButton2, DocumentIcon } from '@openmrs/esm-framework';
4
+ import { type PatientChartWorkspaceActionButtonProps, useStartVisitIfNeeded } from '@openmrs/esm-patient-common-lib';
10
5
 
11
6
  /**
12
7
  * This button uses the patient chart store and MUST only be used
13
8
  * within the patient chart
14
9
  */
15
- const ClinicalFormActionButton: React.FC<{ patientUuid: string }> = ({ patientUuid }) => {
10
+ const ClinicalFormActionButton: React.FC<PatientChartWorkspaceActionButtonProps> = ({
11
+ groupProps: { patientUuid },
12
+ }) => {
16
13
  const { t } = useTranslation();
17
- const { workspaces } = useWorkspaces();
18
- const launchFormsWorkspace = useLaunchWorkspaceRequiringVisit(patientUuid, clinicalFormsWorkspace);
19
-
20
- const formEntryWorkspaces = workspaces.filter((w) => w.name === formEntryWorkspace);
21
- const recentlyOpenedForm = formEntryWorkspaces[0];
22
-
23
- const htmlFormEntryWorkspaces = workspaces.filter((w) => w.name === htmlFormEntryWorkspace);
24
- const recentlyOpenedHtmlForm = htmlFormEntryWorkspaces[0];
25
-
26
- const isFormOpen = formEntryWorkspaces?.length >= 1;
27
- const isHtmlFormOpen = htmlFormEntryWorkspaces?.length >= 1;
28
-
29
- const launchPatientWorkspaceCb = () => {
30
- if (isFormOpen) {
31
- launchWorkspace(formEntryWorkspace, {
32
- workspaceTitle: recentlyOpenedForm?.additionalProps?.['workspaceTitle'],
33
- });
34
- }
35
- // we aren't currently supporting keeping HTML Form workspaces open, but just in case
36
- else if (isHtmlFormOpen) {
37
- launchWorkspace(htmlFormEntryWorkspace, {
38
- workspaceTitle: recentlyOpenedHtmlForm?.additionalProps?.['workspaceTitle'],
39
- });
40
- } else {
41
- launchFormsWorkspace();
42
- }
43
- };
14
+ const startVisitIfNeeded = useStartVisitIfNeeded(patientUuid);
44
15
 
45
16
  return (
46
- <ActionMenuButton
47
- getIcon={(props: ComponentProps<typeof DocumentIcon>) => <DocumentIcon {...props} />}
17
+ <ActionMenuButton2
18
+ icon={(props: ComponentProps<typeof DocumentIcon>) => <DocumentIcon {...props} />}
48
19
  label={t('clinicalForms', 'Clinical forms')}
49
- iconDescription={t('clinicalForms', 'Clinical forms')}
50
- handler={launchPatientWorkspaceCb}
51
- type={'clinical-form'}
20
+ workspaceToLaunch={{
21
+ workspaceName: 'clinical-forms-workspace',
22
+ workspaceProps: {},
23
+ }}
24
+ onBeforeWorkspaceLaunch={startVisitIfNeeded}
52
25
  />
53
26
  );
54
27
  };
@@ -1,46 +1,47 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
- import { ActionMenuButton, useLayoutType, useWorkspaces } from '@openmrs/esm-framework';
3
+ import { ActionMenuButton2, useLayoutType } from '@openmrs/esm-framework';
4
4
  import ClinicalFormActionButton from './clinical-form-action-button.component';
5
+ import { mockPatient } from 'tools';
5
6
 
7
+ const mockActionMenuButton = jest.mocked(ActionMenuButton2);
6
8
  const mockUseLayoutType = jest.mocked(useLayoutType);
7
- const mockUseWorkspaces = useWorkspaces as jest.Mock;
8
- const mockActionMenuButton = jest.mocked(ActionMenuButton);
9
9
 
10
- mockActionMenuButton.mockImplementation(({ handler, label, tagContent }) => (
11
- <button onClick={handler}>
10
+ mockActionMenuButton.mockImplementation(({ label, tagContent }) => (
11
+ <button>
12
12
  {tagContent} {label}
13
13
  </button>
14
14
  ));
15
15
 
16
- mockUseWorkspaces.mockImplementation(() => ({
17
- active: true,
18
- windowState: 'normal',
19
- workspaces: [
20
- {
21
- canHide: false,
22
- name: 'clinical-forms-workspace',
23
- title: 'Clinical forms',
24
- preferredWindowSize: 'normal',
25
- type: 'form',
26
- },
27
- ],
28
- workspaceWindowState: 'normal',
29
- prompt: null,
30
- }));
16
+ jest.mock('@openmrs/esm-patient-common-lib', () => {
17
+ const originalModule = jest.requireActual('@openmrs/esm-patient-common-lib');
18
+
19
+ return {
20
+ ...originalModule,
21
+ useStartVisitIfNeeded: jest.fn(() => () => Promise.resolve(true)),
22
+ };
23
+ });
31
24
 
32
25
  describe('<ClinicalFormActionButton>', () => {
33
26
  test('should display clinical form action button on tablet view', () => {
34
27
  mockUseLayoutType.mockReturnValue('tablet');
35
28
 
36
- render(<ClinicalFormActionButton patientUuid={'some-uuid'} />);
29
+ render(
30
+ <ClinicalFormActionButton
31
+ groupProps={{ patientUuid: mockPatient.id, patient: mockPatient, visitContext: null, mutateVisitContext: null }}
32
+ />,
33
+ );
37
34
  expect(screen.getByRole('button', { name: /Clinical forms/i })).toBeInTheDocument();
38
35
  });
39
36
 
40
37
  test('should display clinical form action button on desktop view', () => {
41
38
  mockUseLayoutType.mockReturnValue('small-desktop');
42
39
 
43
- render(<ClinicalFormActionButton patientUuid={'some-uuid'} />);
40
+ render(
41
+ <ClinicalFormActionButton
42
+ groupProps={{ patientUuid: mockPatient.id, patient: mockPatient, visitContext: null, mutateVisitContext: null }}
43
+ />,
44
+ );
44
45
  const clinicalActionButton = screen.getByRole('button', { name: /Form/i });
45
46
  expect(clinicalActionButton).toBeInTheDocument();
46
47
  });
@@ -123,7 +123,7 @@ export interface FormsSection {
123
123
  forms: Array<string>;
124
124
  }
125
125
 
126
- export interface ConfigObject {
126
+ export interface FormEntryConfigSchema {
127
127
  htmlFormEntryForms: Array<HtmlFormEntryForm>;
128
128
  formSections: Array<FormsSection>;
129
129
  customFormsUrl: string;
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import { type Workspace2DefinitionProps } from '@openmrs/esm-framework';
3
+ import { type Form } from '@openmrs/esm-patient-common-lib';
4
+ import FormEntry from './form-entry.component';
5
+ import { type ExportedClinicalFormsWindowProps } from './exported-forms-dashboard.workspace';
6
+
7
+ interface FormEntryWorkspaceProps {
8
+ form: Form;
9
+ encounterUuid: string;
10
+ }
11
+
12
+ /**
13
+ * This workspace is meant for use outside the patient chart.
14
+ *
15
+ * @see form-entry.workspace.tsx
16
+ */
17
+ const ExportedFormEntryWorkspace: React.FC<
18
+ Workspace2DefinitionProps<FormEntryWorkspaceProps, ExportedClinicalFormsWindowProps, {}>
19
+ > = ({
20
+ closeWorkspace,
21
+ workspaceProps: { form, encounterUuid },
22
+ windowProps: { patient, patientUuid, visitContext, mutateVisitContext },
23
+ }) => {
24
+ return (
25
+ <FormEntry
26
+ form={form}
27
+ encounterUuid={encounterUuid}
28
+ patient={patient}
29
+ patientUuid={patientUuid}
30
+ visitContext={visitContext}
31
+ mutateVisitContext={mutateVisitContext}
32
+ closeWorkspace={closeWorkspace}
33
+ />
34
+ );
35
+ };
36
+
37
+ export default ExportedFormEntryWorkspace;
@@ -0,0 +1,43 @@
1
+ import React, { useCallback } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import FormsDashboard from './forms-dashboard.component';
4
+ import styles from './forms-dashboard-workspace.scss';
5
+ import { type Form } from '@openmrs/esm-patient-common-lib';
6
+ import { type Visit, Workspace2, type Workspace2DefinitionProps } from '@openmrs/esm-framework';
7
+
8
+ export interface ExportedClinicalFormsWindowProps {
9
+ formEntryWorkspaceName: string;
10
+ patient: fhir.Patient;
11
+ patientUuid: string;
12
+ visitContext: Visit;
13
+ mutateVisitContext: () => void;
14
+ }
15
+
16
+ /**
17
+ * This workspace is meant for use outside the patient chart.
18
+ * @see forms-dashboard.workspace.tsx
19
+ */
20
+ const ExportedFormsDashboardWorkspace: React.FC<
21
+ Workspace2DefinitionProps<{}, ExportedClinicalFormsWindowProps, {}>
22
+ > = ({ launchChildWorkspace, windowProps: { formEntryWorkspaceName, patient, visitContext } }) => {
23
+ const { t } = useTranslation();
24
+ const handleFormOpen = useCallback(
25
+ (form: Form, encounterUuid: string) => {
26
+ launchChildWorkspace(formEntryWorkspaceName, {
27
+ form,
28
+ encounterUuid,
29
+ });
30
+ },
31
+ [launchChildWorkspace, formEntryWorkspaceName],
32
+ );
33
+
34
+ return (
35
+ <Workspace2 title={t('clinicalForms', 'Clinical forms')} hasUnsavedChanges={false}>
36
+ <div className={styles.container}>
37
+ <FormsDashboard {...{ patient, visitContext, handleFormOpen }} />
38
+ </div>
39
+ </Workspace2>
40
+ );
41
+ };
42
+
43
+ export default ExportedFormsDashboardWorkspace;
@@ -0,0 +1,138 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import { useSWRConfig } from 'swr';
3
+ import {
4
+ ExtensionSlot,
5
+ useConfig,
6
+ useConnectivity,
7
+ Workspace2,
8
+ type Workspace2DefinitionProps,
9
+ } from '@openmrs/esm-framework';
10
+ import { type Form, type FormRendererProps, invalidateVisitAndEncounterData } from '@openmrs/esm-patient-common-lib';
11
+ import { useTranslation } from 'react-i18next';
12
+ import { type FormEntryConfigSchema } from '../config-schema';
13
+ import { toHtmlForm } from './form-entry.resources';
14
+ import HtmlFormEntryWrapper from '../htmlformentry/html-form-entry-wrapper.component';
15
+
16
+ export interface FormEntryProps {
17
+ form: Form;
18
+ encounterUuid: string;
19
+ patientUuid;
20
+ patient;
21
+ visitContext;
22
+ mutateVisitContext;
23
+ closeWorkspace: Workspace2DefinitionProps['closeWorkspace'];
24
+ }
25
+
26
+ const FormEntry: React.FC<FormEntryProps> = ({
27
+ form,
28
+ encounterUuid,
29
+ patientUuid,
30
+ patient,
31
+ visitContext,
32
+ mutateVisitContext,
33
+ closeWorkspace,
34
+ }) => {
35
+ const formUuid = form.uuid;
36
+ const visitStartDatetime = visitContext?.startDatetime;
37
+ const visitStopDatetime = visitContext?.stopDatetime;
38
+ const visitTypeUuid = visitContext?.visitType.uuid;
39
+ const visitUuid = visitContext?.uuid;
40
+ const { htmlFormEntryForms } = useConfig<FormEntryConfigSchema>();
41
+ const htmlForm = toHtmlForm(form, htmlFormEntryForms);
42
+ const isHtmlForm = htmlForm != null;
43
+ const isOnline = useConnectivity();
44
+ const { mutate: globalMutate } = useSWRConfig();
45
+ const { t } = useTranslation();
46
+ const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
47
+
48
+ const state = useMemo(
49
+ () => ({
50
+ view: 'form',
51
+ formUuid: formUuid ?? null,
52
+ visitUuid: visitUuid ?? visitContext?.uuid ?? null,
53
+ visitTypeUuid: visitTypeUuid ?? visitContext?.visitType?.uuid ?? null,
54
+ visitStartDatetime: visitStartDatetime ?? visitContext?.startDatetime ?? null,
55
+ visitStopDatetime: visitStopDatetime ?? visitContext?.stopDatetime ?? null,
56
+ isOffline: !isOnline,
57
+ patientUuid: patientUuid ?? null,
58
+ patient,
59
+ encounterUuid: encounterUuid ?? null,
60
+ closeWorkspace: () => {
61
+ return closeWorkspace();
62
+ },
63
+ closeWorkspaceWithSavedChanges: () => {
64
+ // Update current visit data for critical components
65
+ mutateVisitContext?.();
66
+
67
+ // Also invalidate visit history and encounter tables since form submission may create/update encounters
68
+ invalidateVisitAndEncounterData(globalMutate, patientUuid);
69
+
70
+ return closeWorkspace({ discardUnsavedChanges: true, closeWindow: true });
71
+ },
72
+ promptBeforeClosing: (func) => setHasUnsavedChanges(func()),
73
+ }),
74
+ [
75
+ closeWorkspace,
76
+ visitContext?.startDatetime,
77
+ visitContext?.stopDatetime,
78
+ visitContext?.uuid,
79
+ visitContext?.visitType?.uuid,
80
+ encounterUuid,
81
+ formUuid,
82
+ globalMutate,
83
+ isOnline,
84
+ mutateVisitContext,
85
+ patient,
86
+ patientUuid,
87
+ setHasUnsavedChanges,
88
+ visitStartDatetime,
89
+ visitStopDatetime,
90
+ visitTypeUuid,
91
+ visitUuid,
92
+ ],
93
+ ) satisfies FormRendererProps;
94
+
95
+ const htmlFormEntryUrl = useMemo(() => {
96
+ if (!htmlForm) {
97
+ return null;
98
+ }
99
+ const uiPage = encounterUuid ? htmlForm.formEditUiPage : htmlForm.formUiPage;
100
+ const url = `${window.openmrsBase}/htmlformentryui/htmlform/${uiPage}.page?`;
101
+ const searchParams = new URLSearchParams();
102
+ searchParams.append('patientId', patientUuid);
103
+ if (visitUuid) {
104
+ searchParams.append('visitId', visitUuid);
105
+ }
106
+ if (encounterUuid) {
107
+ searchParams.append('encounterId', encounterUuid);
108
+ }
109
+ if (htmlForm.formUiResource) {
110
+ searchParams.append('definitionUiResource', htmlForm.formUiResource);
111
+ } else {
112
+ searchParams.append('formUuid', htmlForm.formUuid);
113
+ }
114
+ searchParams.append('returnUrl', 'post-message:close-workspace');
115
+ return url + searchParams;
116
+ }, [encounterUuid, htmlForm, patientUuid, visitUuid]);
117
+
118
+ const showFormAndLoadedData = form && patientUuid;
119
+
120
+ return (
121
+ <Workspace2 title={form.display ?? t('clinicalForm', 'Clinical form')} hasUnsavedChanges={hasUnsavedChanges}>
122
+ <div>
123
+ <ExtensionSlot name="visit-context-header-slot" state={{ patientUuid }} />
124
+ {showFormAndLoadedData &&
125
+ (isHtmlForm ? (
126
+ <HtmlFormEntryWrapper
127
+ src={htmlFormEntryUrl}
128
+ closeWorkspaceWithSavedChanges={() => closeWorkspace({ discardUnsavedChanges: true })}
129
+ />
130
+ ) : (
131
+ <ExtensionSlot key={state.formUuid} name="form-widget-slot" state={state} />
132
+ ))}
133
+ </div>
134
+ </Workspace2>
135
+ );
136
+ };
137
+
138
+ export default FormEntry;
@@ -0,0 +1,37 @@
1
+ import { type HtmlFormEntryForm } from '@openmrs/esm-patient-common-lib';
2
+ import { type Form } from '../types';
3
+
4
+ const formEngineResourceName = 'formEngine';
5
+ const htmlformentryFormEngine = 'htmlformentry';
6
+ const uiStyleResourceName = 'uiStyle';
7
+ const uiStyleSimple = 'simple';
8
+
9
+ /**
10
+ * For a given form , check if it is an HTML form. If it is, return the HtmlFormEntryForm object,
11
+ * otherwise return null
12
+ * @param form
13
+ * @param htmlFormEntryForms A list of HTML forms configured in @esm-patient-forms-app's config
14
+ *
15
+ * @returns
16
+ */
17
+ export function toHtmlForm(form: Form, htmlFormEntryForms: Array<HtmlFormEntryForm>): HtmlFormEntryForm {
18
+ const isHtmlForm =
19
+ htmlFormEntryForms?.some((hfeForm) => hfeForm.formUuid === form.uuid) ||
20
+ form.resources?.some((resource) => {
21
+ return resource.name === formEngineResourceName && resource.valueReference === htmlformentryFormEngine;
22
+ });
23
+ if (isHtmlForm) {
24
+ const hfeForm = htmlFormEntryForms?.find((f) => f.formUuid === form.uuid);
25
+ const simple = form.resources?.some((r) => r.name === uiStyleResourceName && r.valueReference === uiStyleSimple);
26
+
27
+ return {
28
+ formUuid: form.uuid,
29
+ formName: hfeForm?.formName ?? form.display ?? form.name,
30
+ formUiResource: hfeForm?.formUiResource,
31
+ formUiPage: hfeForm?.formUiPage ?? (simple ? 'enterHtmlFormWithSimpleUi' : 'enterHtmlFormWithStandardUi'),
32
+ formEditUiPage: hfeForm?.formEditUiPage ?? (simple ? 'editHtmlFormWithSimpleUi' : 'editHtmlFormWithStandardUi'),
33
+ };
34
+ } else {
35
+ return null;
36
+ }
37
+ }
@@ -1,39 +1,25 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
3
  import { BehaviorSubject } from 'rxjs';
4
- import { ExtensionSlot, useConnectivity, useFeatureFlag } from '@openmrs/esm-framework';
4
+ import { ExtensionSlot, useConnectivity } from '@openmrs/esm-framework';
5
5
  import { mockPatient } from 'tools';
6
- import FormEntry from './form-entry.workspace';
6
+ import FormEntry, { type FormEntryProps } from './form-entry.component';
7
7
 
8
- const mockCurrentVisit = {
9
- uuid: '17f512b4-d264-4113-a6fe-160cb38cb46e',
10
- encounters: [],
11
- patient: { uuid: '8673ee4f-e2ab-4077-ba55-4980f408773e' },
12
- visitType: {
13
- uuid: '7b0f5697-27e3-40c4-8bae-f4049abfb4ed',
14
- display: 'Facility Visit',
8
+ const defaultProps: FormEntryProps = {
9
+ form: {
10
+ uuid: 'some-form-uuid',
11
+ name: '',
12
+ version: '',
13
+ published: false,
14
+ retired: false,
15
+ resources: [],
15
16
  },
16
- attributes: [],
17
- startDatetime: '2021-03-16T08:16:00.000+0000',
18
- stopDatetime: null,
19
- location: {
20
- uuid: '6351fcf4-e311-4a19-90f9-35667d99a8af',
21
- name: 'Registration Desk',
22
- display: 'Registration Desk',
23
- },
24
- };
25
-
26
- const testProps = {
27
- closeWorkspace: jest.fn(),
28
- closeWorkspaceWithSavedChanges: jest.fn(),
29
- promptBeforeClosing: jest.fn(),
17
+ encounterUuid: 'some-encounter-uuid',
30
18
  patientUuid: mockPatient.id,
31
19
  patient: mockPatient,
32
- formInfo: { formUuid: 'some-form-uuid' },
33
- mutateForm: jest.fn(),
34
- setTitle: jest.fn(),
35
- visitContext: mockCurrentVisit,
20
+ visitContext: null,
36
21
  mutateVisitContext: null,
22
+ closeWorkspace: jest.fn(),
37
23
  };
38
24
 
39
25
  const mockFormEntrySub = jest.fn();
@@ -49,7 +35,7 @@ describe('FormEntry', () => {
49
35
  );
50
36
  mockExtensionSlot.mockImplementation((ext) => ext.name as any);
51
37
 
52
- render(<FormEntry {...testProps} />);
38
+ render(<FormEntry {...defaultProps} />);
53
39
 
54
40
  await screen.findByText(/form-widget-slot/);
55
41
  expect(screen.getByText(/form-widget-slot/)).toBeInTheDocument();
@@ -1,108 +1,34 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
2
- import { useSWRConfig } from 'swr';
3
- import { ExtensionSlot, useConnectivity } from '@openmrs/esm-framework';
4
- import {
5
- clinicalFormsWorkspace,
6
- invalidateVisitAndEncounterData,
7
- type DefaultPatientWorkspaceProps,
8
- type FormEntryProps,
9
- } from '@openmrs/esm-patient-common-lib';
1
+ import React from 'react';
2
+ import { type Form, type PatientWorkspace2DefinitionProps } from '@openmrs/esm-patient-common-lib';
3
+ import FormEntry from './form-entry.component';
10
4
 
11
- interface FormEntryComponentProps extends DefaultPatientWorkspaceProps {
12
- mutateForm: () => void;
13
- formInfo: FormEntryProps;
14
- clinicalFormsWorkspaceName?: string;
5
+ interface FormEntryWorkspaceProps {
6
+ form: Form;
7
+ encounterUuid: string;
15
8
  }
16
9
 
17
- const FormEntry: React.FC<FormEntryComponentProps> = ({
18
- patientUuid,
19
- patient,
20
- clinicalFormsWorkspaceName = clinicalFormsWorkspace,
10
+ /**
11
+ * This workspace renders a React or HTML form to be filled out for a given patient.
12
+ *
13
+ * This workspace must only be used within the patient chart.
14
+ * @see exported-form-entry.workspace.tsx
15
+ */
16
+ const FormEntryWorkspace: React.FC<PatientWorkspace2DefinitionProps<FormEntryWorkspaceProps, {}>> = ({
21
17
  closeWorkspace,
22
- closeWorkspaceWithSavedChanges,
23
- promptBeforeClosing,
24
- mutateForm,
25
- formInfo,
26
- visitContext,
27
- mutateVisitContext,
18
+ workspaceProps: { form, encounterUuid },
19
+ groupProps: { patientUuid, patient, visitContext, mutateVisitContext },
28
20
  }) => {
29
- const { encounterUuid, formUuid, visitStartDatetime, visitStopDatetime, visitTypeUuid, visitUuid, additionalProps } =
30
- formInfo || {};
31
- const [showForm, setShowForm] = useState(true);
32
- const isOnline = useConnectivity();
33
- const { mutate: globalMutate } = useSWRConfig();
34
-
35
- const state = useMemo(
36
- () => ({
37
- view: 'form',
38
- formUuid: formUuid ?? null,
39
- visitUuid: visitUuid ?? visitContext?.uuid ?? null,
40
- visitTypeUuid: visitTypeUuid ?? visitContext?.visitType?.uuid ?? null,
41
- visitStartDatetime: visitStartDatetime ?? visitContext?.startDatetime ?? null,
42
- visitStopDatetime: visitStopDatetime ?? visitContext?.stopDatetime ?? null,
43
- isOffline: !isOnline,
44
- patientUuid: patientUuid ?? null,
45
- patient,
46
- encounterUuid: encounterUuid ?? null,
47
- closeWorkspace: () => {
48
- typeof mutateForm === 'function' && mutateForm();
49
- closeWorkspace();
50
- },
51
- closeWorkspaceWithSavedChanges: () => {
52
- typeof mutateForm === 'function' && mutateForm();
53
- // Update current visit data for critical components
54
- mutateVisitContext?.();
55
-
56
- // Also invalidate visit history and encounter tables since form submission may create/update encounters
57
- invalidateVisitAndEncounterData(globalMutate, patientUuid);
58
-
59
- closeWorkspaceWithSavedChanges();
60
- },
61
- promptBeforeClosing,
62
- additionalProps,
63
- clinicalFormsWorkspaceName,
64
- }),
65
- [
66
- additionalProps,
67
- clinicalFormsWorkspaceName,
68
- closeWorkspace,
69
- closeWorkspaceWithSavedChanges,
70
- visitContext?.startDatetime,
71
- visitContext?.stopDatetime,
72
- visitContext?.uuid,
73
- visitContext?.visitType?.uuid,
74
- encounterUuid,
75
- formUuid,
76
- globalMutate,
77
- isOnline,
78
- mutateVisitContext,
79
- mutateForm,
80
- patient,
81
- patientUuid,
82
- promptBeforeClosing,
83
- visitStartDatetime,
84
- visitStopDatetime,
85
- visitTypeUuid,
86
- visitUuid,
87
- ],
88
- );
89
-
90
- // FIXME: This logic triggers a reload of the form when the formUuid changes. It's a workaround for the fact that the form doesn't reload when the formUuid changes.
91
- useEffect(() => {
92
- if (state.formUuid) {
93
- setShowForm(false);
94
- setTimeout(() => {
95
- setShowForm(true);
96
- });
97
- }
98
- }, [state]);
99
-
100
21
  return (
101
- <div>
102
- <ExtensionSlot name="visit-context-header-slot" state={{ patientUuid }} />
103
- {showForm && formInfo && patientUuid && patient && <ExtensionSlot name="form-widget-slot" state={state} />}
104
- </div>
22
+ <FormEntry
23
+ form={form}
24
+ encounterUuid={encounterUuid}
25
+ patient={patient}
26
+ patientUuid={patientUuid}
27
+ visitContext={visitContext}
28
+ mutateVisitContext={mutateVisitContext}
29
+ closeWorkspace={closeWorkspace}
30
+ />
105
31
  );
106
32
  };
107
33
 
108
- export default FormEntry;
34
+ export default FormEntryWorkspace;