@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.
- package/__mocks__/react-i18next.js +9 -14
- package/dist/12.js +1 -0
- package/dist/12.js.map +1 -0
- package/dist/132.js +1 -0
- package/dist/151.js +2 -0
- package/dist/151.js.map +1 -0
- package/dist/195.js +1 -0
- package/dist/195.js.map +1 -0
- package/dist/197.js +1 -0
- package/dist/221.js +1 -0
- package/dist/221.js.map +1 -0
- package/dist/259.js +1 -0
- package/dist/259.js.map +1 -0
- package/dist/265.js +1 -0
- package/dist/265.js.map +1 -0
- package/dist/269.js +1 -0
- package/dist/269.js.map +1 -0
- package/dist/{574.js → 300.js} +1 -1
- package/dist/335.js +1 -0
- package/dist/367.js +1 -0
- package/dist/367.js.map +1 -0
- package/dist/384.js +1 -0
- package/dist/384.js.map +1 -0
- package/dist/{294.js → 540.js} +2 -2
- package/dist/{294.js.map → 540.js.map} +1 -1
- package/dist/55.js +1 -0
- package/dist/579.js +1 -0
- package/dist/579.js.map +1 -0
- package/dist/595.js +2 -0
- package/dist/{409.js.LICENSE.txt → 595.js.LICENSE.txt} +14 -6
- package/dist/595.js.map +1 -0
- package/dist/602.js +1 -0
- package/dist/602.js.map +1 -0
- package/dist/616.js +1 -0
- package/dist/616.js.map +1 -0
- package/dist/626.js +2 -0
- package/dist/626.js.map +1 -0
- package/dist/652.js +1 -0
- package/dist/77.js +1 -0
- package/dist/77.js.map +1 -0
- package/dist/773.js +2 -0
- package/dist/{897.js.LICENSE.txt → 773.js.LICENSE.txt} +13 -2
- package/dist/773.js.map +1 -0
- package/dist/88.js +1 -0
- package/dist/88.js.map +1 -0
- package/dist/930.js +1 -0
- package/dist/930.js.map +1 -0
- package/dist/961.js +2 -0
- package/dist/961.js.map +1 -0
- package/dist/983.js +1 -0
- package/dist/983.js.map +1 -0
- package/dist/99.js +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +386 -154
- package/dist/openmrs-esm-fast-data-entry-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/jest.config.json +2 -1
- package/package.json +39 -36
- package/prettier.config.js +8 -0
- package/src/CancelModal.tsx +9 -15
- package/src/CompleteModal.tsx +7 -18
- package/src/FormBootstrap.tsx +31 -18
- package/src/Root.tsx +7 -12
- package/src/add-group-modal/AddGroupModal.tsx +73 -112
- package/src/add-group-modal/styles.scss +7 -3
- package/src/config-schema.ts +63 -24
- package/src/constant.ts +1 -1
- package/src/context/FormWorkflowContext.tsx +26 -39
- package/src/context/FormWorkflowReducer.ts +50 -74
- package/src/context/GroupFormWorkflowContext.tsx +40 -59
- package/src/context/GroupFormWorkflowReducer.ts +84 -109
- package/src/declarations.d.ts +3 -0
- package/src/empty-state/EmptyDataIllustration.tsx +4 -16
- package/src/empty-state/EmptyState.tsx +8 -13
- package/src/empty-state/styles.scss +14 -14
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +43 -55
- package/src/form-entry-workflow/form-review-card/FormReviewCard.tsx +7 -7
- package/src/form-entry-workflow/form-review-card/index.ts +1 -1
- package/src/form-entry-workflow/form-review-card/styles.scss +9 -11
- package/src/form-entry-workflow/index.ts +1 -1
- package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +5 -5
- package/src/form-entry-workflow/patient-banner/PatientBanner.tsx +14 -27
- package/src/form-entry-workflow/patient-banner/index.ts +1 -1
- package/src/form-entry-workflow/patient-banner/styles.scss +11 -12
- package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +19 -28
- package/src/form-entry-workflow/patient-search-header/index.ts +1 -1
- package/src/form-entry-workflow/patient-search-header/styles.scss +13 -10
- package/src/form-entry-workflow/styles.scss +11 -13
- package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +13 -11
- package/src/form-entry-workflow/workflow-review/index.ts +1 -1
- package/src/form-entry-workflow/workflow-review/styles.scss +0 -4
- package/src/forms-app-menu-link.tsx +4 -6
- package/src/forms-page/FormsPage.tsx +23 -51
- package/src/forms-page/forms-table/FormsTable.tsx +22 -42
- package/src/forms-page/forms-table/index.ts +1 -1
- package/src/forms-page/forms-table/styles.scss +4 -5
- package/src/forms-page/index.ts +1 -1
- package/src/forms-page/styles.scss +3 -5
- package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +9 -9
- package/src/group-form-entry-workflow/GroupSessionWorkspace.tsx +77 -117
- package/src/group-form-entry-workflow/SessionDetailsForm.tsx +73 -50
- package/src/group-form-entry-workflow/SessionMetaWorkspace.tsx +20 -28
- package/src/group-form-entry-workflow/attendance-table/AttendanceTable.tsx +15 -29
- package/src/group-form-entry-workflow/attendance-table/index.ts +1 -1
- package/src/group-form-entry-workflow/configurable-questions/ConfigurableQuestionsSection.tsx +45 -0
- package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.test.tsx +5 -5
- package/src/group-form-entry-workflow/group-display-header/GroupDisplayHeader.tsx +13 -21
- package/src/group-form-entry-workflow/group-display-header/index.ts +1 -1
- package/src/group-form-entry-workflow/group-display-header/styles.scss +20 -20
- package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +24 -35
- package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +13 -15
- package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +22 -38
- package/src/group-form-entry-workflow/group-search/compact-group-result.scss +16 -17
- package/src/group-form-entry-workflow/group-search/compact-group-search.scss +7 -8
- package/src/group-form-entry-workflow/group-search/group-search.scss +20 -23
- package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +20 -21
- package/src/group-form-entry-workflow/group-search-header/index.ts +1 -1
- package/src/group-form-entry-workflow/group-search-header/styles.scss +8 -8
- package/src/group-form-entry-workflow/index.ts +1 -1
- package/src/group-form-entry-workflow/styles.scss +13 -16
- package/src/hooks/index.ts +7 -6
- package/src/hooks/useFormState.ts +3 -3
- package/src/hooks/useGetAllForms.ts +7 -15
- package/src/hooks/useGetEncounter.ts +3 -3
- package/src/hooks/useGetPatient.ts +2 -2
- package/src/hooks/useGetPatients.ts +4 -6
- package/src/hooks/useGetSystemSetting.ts +3 -5
- package/src/hooks/useKeyPress.ts +5 -5
- package/src/hooks/usePostEndpoint.ts +10 -10
- package/src/hooks/useSearchEndpoint.ts +23 -40
- package/src/hooks/useSpecificQuestions.ts +75 -0
- package/src/hooks/useStartVisit.ts +18 -28
- package/src/index.ts +8 -20
- package/src/patient-card/PatientCard.tsx +8 -20
- package/src/patient-card/index.ts +1 -1
- package/src/patient-card/styles.scss +2 -4
- package/src/routes.json +2 -2
- package/src/setup-tests.ts +1 -1
- package/src/types.ts +25 -0
- package/tools/i18next-parser.config.js +19 -19
- package/translations/am.json +75 -0
- package/translations/ar.json +75 -0
- package/translations/en.json +7 -1
- package/translations/es.json +75 -0
- package/translations/fr.json +33 -8
- package/translations/he.json +75 -0
- package/translations/km.json +75 -0
- package/tsconfig.json +2 -1
- package/turbo.json +18 -0
- package/webpack.config.js +1 -1
- package/dist/136.js +0 -1
- package/dist/136.js.map +0 -1
- package/dist/141.js +0 -2
- package/dist/141.js.map +0 -1
- package/dist/233.js +0 -2
- package/dist/233.js.map +0 -1
- package/dist/242.js +0 -1
- package/dist/242.js.map +0 -1
- package/dist/327.js +0 -1
- package/dist/327.js.map +0 -1
- package/dist/387.js +0 -1
- package/dist/387.js.map +0 -1
- package/dist/405.js +0 -1
- package/dist/405.js.map +0 -1
- package/dist/409.js +0 -2
- package/dist/409.js.map +0 -1
- package/dist/431.js +0 -1
- package/dist/431.js.map +0 -1
- package/dist/559.js +0 -1
- package/dist/559.js.map +0 -1
- package/dist/757.js +0 -1
- package/dist/820.js +0 -1
- package/dist/820.js.map +0 -1
- package/dist/846.js +0 -1
- package/dist/846.js.map +0 -1
- package/dist/885.js +0 -1
- package/dist/885.js.map +0 -1
- package/dist/897.js +0 -2
- package/dist/897.js.map +0 -1
- package/dist/92.js +0 -1
- package/dist/92.js.map +0 -1
- package/dist/935.js +0 -2
- package/dist/935.js.map +0 -1
- package/src/declarations.d.tsx +0 -2
- /package/dist/{141.js.LICENSE.txt → 151.js.LICENSE.txt} +0 -0
- /package/dist/{294.js.LICENSE.txt → 540.js.LICENSE.txt} +0 -0
- /package/dist/{233.js.LICENSE.txt → 626.js.LICENSE.txt} +0 -0
- /package/dist/{935.js.LICENSE.txt → 961.js.LICENSE.txt} +0 -0
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
import { useConfig, useSession } from
|
|
2
|
-
import { Tab, Tabs, TabList, TabPanels, TabPanel } from
|
|
3
|
-
import React from
|
|
4
|
-
import { Config } from
|
|
5
|
-
import { useGetAllForms } from
|
|
6
|
-
import FormsTable from
|
|
7
|
-
import styles from
|
|
8
|
-
import { useTranslation } from
|
|
9
|
-
import {
|
|
10
|
-
|
|
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()
|
|
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
|
-
|
|
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(
|
|
103
|
-
{`${t(
|
|
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
|
|
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
|
|
16
|
-
import React from
|
|
17
|
-
import { useTranslation } from
|
|
18
|
-
import { Link } from
|
|
19
|
-
import EmptyState from
|
|
20
|
-
import styles from
|
|
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:
|
|
34
|
-
header: t(
|
|
27
|
+
key: 'display',
|
|
28
|
+
header: t('formName', 'Form Name'),
|
|
35
29
|
isSortable: true,
|
|
36
30
|
},
|
|
37
31
|
{
|
|
38
|
-
key:
|
|
39
|
-
header: t(
|
|
32
|
+
key: 'actions',
|
|
33
|
+
header: t('actions', 'Actions'),
|
|
40
34
|
},
|
|
41
35
|
{
|
|
42
|
-
key:
|
|
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(
|
|
60
|
-
: t(
|
|
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(
|
|
64
|
+
headerTitle={t('noFormsFound', 'No Forms To Show')}
|
|
78
65
|
displayText={t(
|
|
79
|
-
|
|
80
|
-
|
|
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,11 +1,10 @@
|
|
|
1
|
-
@
|
|
2
|
-
@
|
|
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:
|
|
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:
|
|
17
|
+
color: colors.$gray-40;
|
|
19
18
|
cursor: not-allowed;
|
|
20
19
|
}
|
package/src/forms-page/index.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
@use '@carbon/
|
|
2
|
-
// @use '@carbon/styles/scss/type';
|
|
3
|
-
// @import '~@openmrs/esm-styleguide/src/vars';
|
|
1
|
+
@use '@carbon/layout';
|
|
4
2
|
|
|
5
3
|
.mainContent {
|
|
6
|
-
padding:
|
|
4
|
+
padding: layout.$spacing-07;
|
|
7
5
|
}
|
|
8
6
|
|
|
9
7
|
.pageTitle {
|
|
10
|
-
margin-bottom:
|
|
8
|
+
margin-bottom: layout.$spacing-06;
|
|
11
9
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { ExtensionSlot } from
|
|
2
|
-
import React from
|
|
3
|
-
import GroupDisplayHeader from
|
|
4
|
-
import styles from
|
|
5
|
-
import { GroupFormWorkflowProvider } from
|
|
6
|
-
import GroupSearchHeader from
|
|
7
|
-
import SessionMetaWorkspace from
|
|
8
|
-
import GroupSessionWorkspace from
|
|
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
|
|
14
|
+
<ExtensionSlot name="breadcrumbs-slot" />
|
|
15
15
|
</div>
|
|
16
16
|
<GroupSearchHeader />
|
|
17
17
|
<GroupDisplayHeader />
|
|
@@ -1,48 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
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 !==
|
|
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
|
-
|
|
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(
|
|
41
|
+
{t('saveAndComplete', 'Save & Complete')}
|
|
64
42
|
</Button>
|
|
65
43
|
<Button kind="tertiary" onClick={() => setCancelModalOpen(true)}>
|
|
66
|
-
{t(
|
|
44
|
+
{t('cancel', 'Cancel')}
|
|
67
45
|
</Button>
|
|
68
46
|
</div>
|
|
69
|
-
<CancelModal
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
97
|
+
const visitUuid = activeVisitUuid ? activeVisitUuid : uuid();
|
|
162
98
|
if (!activeVisitUuid) {
|
|
163
99
|
Object.entries(groupSessionConcepts).forEach(([field, uuid]) => {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
]
|
|
148
|
+
updateVisitUuid,
|
|
149
|
+
],
|
|
182
150
|
);
|
|
183
151
|
|
|
184
|
-
//
|
|
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 ===
|
|
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(
|
|
186
|
+
<h4>{t('formsFilled', 'Forms filled')}</h4>
|
|
227
187
|
<div className={styles.patientCardsSection}>
|
|
228
188
|
{patientUuids?.map((patientUuid) => (
|
|
229
189
|
<PatientCard
|