@openmrs/esm-fast-data-entry-app 1.0.0-pre.21 → 1.0.0-pre.29
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/dist/508.js +1 -0
- package/dist/574.js +1 -1
- package/dist/804.js +1 -1
- package/dist/954.js +1 -0
- package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +34 -34
- package/dist/openmrs-esm-fast-data-entry-app.old +1 -1
- package/package.json +1 -1
- package/src/FormBootstrap.tsx +142 -0
- package/src/Root.tsx +11 -8
- package/src/context/FormWorkflowContext.tsx +40 -0
- package/src/context/FormWorkflowReducer.ts +38 -0
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +88 -0
- package/src/form-entry-workflow/index.ts +3 -0
- package/src/form-entry-workflow/styles.scss +59 -0
- package/src/forms-page/FormsPage.tsx +76 -0
- package/src/forms-page/index.ts +3 -0
- package/src/forms-page/styles.scss +11 -0
- package/src/{forms → forms-table}/FormsTable.tsx +37 -26
- package/src/forms-table/index.ts +3 -0
- package/src/forms-table/styles.scss +20 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useGetAllForms.ts +45 -0
- package/src/{forms → hooks}/useGetPatient.ts +0 -0
- package/src/{forms/PatientInfo.test.tsx → patient-banner/PatientBanner.test.tsx} +3 -3
- package/src/{forms/PatientInfo.tsx → patient-banner/PatientBanner.tsx} +2 -2
- package/src/patient-banner/index.ts +3 -0
- package/src/{forms/patient-info.scss → patient-banner/styles.scss} +0 -0
- package/src/patient-card/PatientCard.tsx +51 -0
- package/src/patient-card/index.ts +3 -0
- package/src/patient-card/styles.scss +30 -0
- package/src/patient-search-header/PatientSearchHeader.tsx +47 -0
- package/src/patient-search-header/index.ts +3 -0
- package/src/patient-search-header/styles.scss +17 -0
- package/translations/en.json +13 -4
- package/dist/852.js +0 -1
- package/dist/947.js +0 -1
- package/src/FormEntry.tsx +0 -42
- package/src/Loader.tsx +0 -16
- package/src/forms/FormWorkflow.tsx +0 -135
- package/src/forms/FormsRoot.tsx +0 -79
- package/src/forms/PatientCard.tsx +0 -37
- package/src/forms/mockData.ts +0 -20
- package/src/forms/styles.scss +0 -13
- package/src/loader.scss +0 -9
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ExtensionSlot } from "@openmrs/esm-framework";
|
|
2
|
+
import { Button } from "carbon-components-react";
|
|
3
|
+
import React, { useContext, useState } from "react";
|
|
4
|
+
import { useHistory, useParams } from "react-router-dom";
|
|
5
|
+
import FormBootstrap from "../FormBootstrap";
|
|
6
|
+
import PatientCard from "../patient-card/PatientCard";
|
|
7
|
+
import PatientBanner from "../patient-banner";
|
|
8
|
+
import styles from "./styles.scss";
|
|
9
|
+
import PatientSearchHeader from "../patient-search-header";
|
|
10
|
+
import { useTranslation } from "react-i18next";
|
|
11
|
+
import FormWorkflowContext from "../context/FormWorkflowContext";
|
|
12
|
+
|
|
13
|
+
interface ParamTypes {
|
|
14
|
+
formUuid: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const FormEntryWorkflow = () => {
|
|
18
|
+
const { formUuid } = useParams() as ParamTypes;
|
|
19
|
+
const history = useHistory();
|
|
20
|
+
const {
|
|
21
|
+
patientUuids,
|
|
22
|
+
activePatientUuid,
|
|
23
|
+
activeEncounterUuid,
|
|
24
|
+
openPatientSearch,
|
|
25
|
+
saveEncounter,
|
|
26
|
+
} = useContext(FormWorkflowContext);
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
|
|
29
|
+
const handlePostResponse = (encounter) => {
|
|
30
|
+
if (encounter && encounter.uuid) {
|
|
31
|
+
saveEncounter(encounter.uuid);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div>
|
|
37
|
+
<div className={styles.breadcrumbsContainer}>
|
|
38
|
+
<ExtensionSlot extensionSlotName="breadcrumbs-slot" />
|
|
39
|
+
</div>
|
|
40
|
+
{!activePatientUuid && <PatientSearchHeader />}
|
|
41
|
+
{activePatientUuid && <PatientBanner patientUuid={activePatientUuid} />}
|
|
42
|
+
<div className={styles.workspaceWrapper}>
|
|
43
|
+
<div className={styles.workspace}>
|
|
44
|
+
{!patientUuids.length && (
|
|
45
|
+
<div className={styles.selectPatientMessage}>
|
|
46
|
+
{t("selectPatientFirst", "Please select a patient first")}
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
{!!patientUuids.length && (
|
|
50
|
+
<div className={styles.formMainContent}>
|
|
51
|
+
<div className={styles.formContainer}>
|
|
52
|
+
<FormBootstrap
|
|
53
|
+
patientUuid={activePatientUuid}
|
|
54
|
+
encounterUuid={activeEncounterUuid}
|
|
55
|
+
{...{
|
|
56
|
+
formUuid,
|
|
57
|
+
handlePostResponse,
|
|
58
|
+
}}
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
<div className={styles.rightPanel}>
|
|
62
|
+
<h4>Forms filled</h4>
|
|
63
|
+
<div className={styles.patientCardsSection}>
|
|
64
|
+
{patientUuids.map((patientUuid) => (
|
|
65
|
+
<PatientCard patientUuid={patientUuid} key={patientUuid} />
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
<div className={styles.rightPanelActionButtons}>
|
|
69
|
+
<Button kind="primary" onClick={() => openPatientSearch()}>
|
|
70
|
+
{t("nextPatient", "Next Patient")}
|
|
71
|
+
</Button>
|
|
72
|
+
<Button kind="secondary" disabled>
|
|
73
|
+
{t("reviewSave", "Review & Save")}
|
|
74
|
+
</Button>
|
|
75
|
+
<Button kind="tertiary" onClick={() => history.push("/")}>
|
|
76
|
+
{t("cancel", "Cancel")}
|
|
77
|
+
</Button>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export default FormEntryWorkflow;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
@import "~@openmrs/esm-styleguide/src/vars";
|
|
2
|
+
@import "~carbon-components/src/globals/scss/vars";
|
|
3
|
+
@import "~carbon-components/src/globals/scss/mixins";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
.breadcrumbsContainer > div > div > nav {
|
|
7
|
+
background-color: white;
|
|
8
|
+
padding: 0.5rem;
|
|
9
|
+
border-bottom: 1px solid $openmrs-background-grey;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.workspaceWrapper {
|
|
13
|
+
display: flex;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.workspace {
|
|
18
|
+
width: 1100px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.selectPatientMessage {
|
|
22
|
+
@include carbon--type-style('productive-heading-03');
|
|
23
|
+
margin: $spacing-07;
|
|
24
|
+
text-align: center;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.formMainContent {
|
|
28
|
+
display: flex;
|
|
29
|
+
text-align: center;
|
|
30
|
+
margin-top: 1rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.formContainer {
|
|
34
|
+
flex-grow: 1;
|
|
35
|
+
max-height: calc(100vh - 14rem);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.rightPanel {
|
|
39
|
+
width: 13rem;
|
|
40
|
+
text-align: left;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.patientCardsSection {
|
|
44
|
+
margin: 1rem 0;
|
|
45
|
+
border-bottom: 1px solid $carbon--gray-10;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.rightPanelActionButtons {
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
row-gap: 0.5rem;
|
|
52
|
+
& button {
|
|
53
|
+
width: 100%;
|
|
54
|
+
text-decoration: "none";
|
|
55
|
+
& :hover {
|
|
56
|
+
background-color: $carbon--gray-30;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { useConfig } from "@openmrs/esm-framework";
|
|
2
|
+
import { Tab, Tabs } from "carbon-components-react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Config } from "../config-schema";
|
|
5
|
+
import { useGetAllForms } from "../hooks";
|
|
6
|
+
import FormsTable from "../forms-table";
|
|
7
|
+
import styles from "./styles.scss";
|
|
8
|
+
import { useTranslation } from "react-i18next";
|
|
9
|
+
|
|
10
|
+
// helper function useful for debugging
|
|
11
|
+
// given a list of forms, it will organize into permissions
|
|
12
|
+
// and list which forms are associated with that permission
|
|
13
|
+
const getFormPermissions = (forms) => {
|
|
14
|
+
const output = {};
|
|
15
|
+
forms?.forEach(
|
|
16
|
+
(form) =>
|
|
17
|
+
(output[form.encounterType.editPrivilege.display] = [
|
|
18
|
+
...(output[form.encounterType.editPrivilege.display] || []),
|
|
19
|
+
form.display,
|
|
20
|
+
])
|
|
21
|
+
);
|
|
22
|
+
return output;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Function adds `id` field to rows so they will be accepted by DataTable
|
|
26
|
+
// "display" is prefered for display name if present, otherwise fall back on "name'"
|
|
27
|
+
const prepareRowsForTable = (rawFormData) => {
|
|
28
|
+
if (rawFormData) {
|
|
29
|
+
return rawFormData?.map((form) => ({
|
|
30
|
+
...form,
|
|
31
|
+
id: form.uuid,
|
|
32
|
+
display: form.display || form.name,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const FormsPage = () => {
|
|
39
|
+
const config = useConfig() as Config;
|
|
40
|
+
const { t } = useTranslation();
|
|
41
|
+
const { formCategories, formCategoriesToShow } = config;
|
|
42
|
+
const { forms, isLoading, error } = useGetAllForms();
|
|
43
|
+
const cleanRows = prepareRowsForTable(forms);
|
|
44
|
+
|
|
45
|
+
const categoryRows = formCategoriesToShow.map((name) => {
|
|
46
|
+
const category = formCategories.find((category) => category.name === name);
|
|
47
|
+
let rows = [];
|
|
48
|
+
if (category && cleanRows && cleanRows.length) {
|
|
49
|
+
const uuids = category.forms?.map((form) => form.formUUID);
|
|
50
|
+
rows = cleanRows.filter((row) => uuids.includes(row.uuid));
|
|
51
|
+
}
|
|
52
|
+
return { ...{ name, rows } };
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className={styles.mainContent}>
|
|
57
|
+
<h3 className={styles.pageTitle}>{t("forms", "Forms")}</h3>
|
|
58
|
+
<Tabs type="container">
|
|
59
|
+
<Tab
|
|
60
|
+
label={`${t("allForms", "All Forms")} (${
|
|
61
|
+
cleanRows ? cleanRows?.length : "??"
|
|
62
|
+
})`}
|
|
63
|
+
>
|
|
64
|
+
<FormsTable rows={cleanRows} {...{ error, isLoading }} />
|
|
65
|
+
</Tab>
|
|
66
|
+
{categoryRows?.map((category, index) => (
|
|
67
|
+
<Tab label={`${category.name} (${category.rows.length})`} key={index}>
|
|
68
|
+
<FormsTable rows={category.rows} {...{ error, isLoading }} />
|
|
69
|
+
</Tab>
|
|
70
|
+
))}
|
|
71
|
+
</Tabs>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export default FormsPage;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ErrorState } from "@openmrs/esm-framework";
|
|
2
1
|
import {
|
|
3
2
|
DataTable,
|
|
4
3
|
DataTableSkeleton,
|
|
@@ -14,40 +13,59 @@ import {
|
|
|
14
13
|
TableToolbarSearch,
|
|
15
14
|
} from "carbon-components-react";
|
|
16
15
|
import React from "react";
|
|
16
|
+
import { useTranslation } from "react-i18next";
|
|
17
17
|
import { Link } from "react-router-dom";
|
|
18
18
|
import EmptyState from "../empty-state/EmptyState";
|
|
19
|
-
|
|
20
|
-
const formsHeader = [
|
|
21
|
-
{
|
|
22
|
-
key: "name",
|
|
23
|
-
header: "Form name",
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
key: "actions",
|
|
27
|
-
header: "Actions",
|
|
28
|
-
},
|
|
29
|
-
];
|
|
19
|
+
import styles from "./styles.scss";
|
|
30
20
|
|
|
31
21
|
const FormsTable = ({ rows, error, isLoading }) => {
|
|
22
|
+
const { t } = useTranslation();
|
|
23
|
+
|
|
24
|
+
const formsHeader = [
|
|
25
|
+
{
|
|
26
|
+
key: "display",
|
|
27
|
+
header: t("formName", "Form Name"),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: "actions",
|
|
31
|
+
header: t("actions", "Actions"),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: "actions2",
|
|
35
|
+
header: "",
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
32
39
|
const augmenteRows = rows?.map((row) => ({
|
|
33
40
|
...row,
|
|
34
|
-
actions: <Link to={row.uuid}>Fill Form</Link>,
|
|
41
|
+
actions: <Link to={row.uuid}>{t("fillForm", "Fill Form")}</Link>,
|
|
42
|
+
actions2: (
|
|
43
|
+
<Link to="#" className={styles.inactiveLink}>
|
|
44
|
+
{t("startGroupSession", "Start Group Session")}
|
|
45
|
+
</Link>
|
|
46
|
+
),
|
|
35
47
|
}));
|
|
36
48
|
|
|
37
49
|
if (isLoading) return <DataTableSkeleton />;
|
|
38
50
|
if (error) {
|
|
39
51
|
return (
|
|
40
52
|
<EmptyState
|
|
41
|
-
headerTitle="Error Loading Data"
|
|
42
|
-
displayText={
|
|
53
|
+
headerTitle={t("errorLoadingData", "Error Loading Data")}
|
|
54
|
+
displayText={`${t(
|
|
55
|
+
"dataErrorMessage",
|
|
56
|
+
"Something went wrong loading data from the server."
|
|
57
|
+
)} "${error?.response?.status}: ${error?.response?.statusText}"`}
|
|
43
58
|
/>
|
|
44
59
|
);
|
|
45
60
|
}
|
|
46
61
|
if (augmenteRows.length === 0) {
|
|
47
62
|
return (
|
|
48
63
|
<EmptyState
|
|
49
|
-
headerTitle="No Forms To Show"
|
|
50
|
-
displayText=
|
|
64
|
+
headerTitle={t("noFormsFound", "No Forms To Show")}
|
|
65
|
+
displayText={t(
|
|
66
|
+
"noFormsFoundMessage",
|
|
67
|
+
"No forms could be found for this category. Please double check the form concept uuids and access permissions."
|
|
68
|
+
)}
|
|
51
69
|
/>
|
|
52
70
|
);
|
|
53
71
|
}
|
|
@@ -63,15 +81,8 @@ const FormsTable = ({ rows, error, isLoading }) => {
|
|
|
63
81
|
}) => {
|
|
64
82
|
return (
|
|
65
83
|
<TableContainer>
|
|
66
|
-
<div
|
|
67
|
-
|
|
68
|
-
position: "relative",
|
|
69
|
-
display: "flex",
|
|
70
|
-
height: "3rem",
|
|
71
|
-
justifyContent: "flex-end",
|
|
72
|
-
}}
|
|
73
|
-
>
|
|
74
|
-
<TableToolbar style={{ width: "20%", minWidth: "200px" }}>
|
|
84
|
+
<div className={styles.toolbarWrapper}>
|
|
85
|
+
<TableToolbar className={styles.tableToolbar}>
|
|
75
86
|
<TableToolbarContent>
|
|
76
87
|
<TableToolbarSearch onChange={onInputChange} />
|
|
77
88
|
</TableToolbarContent>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
@import "~@openmrs/esm-styleguide/src/vars";
|
|
2
|
+
@import "~carbon-components/src/globals/scss/vars";
|
|
3
|
+
@import "~carbon-components/src/globals/scss/mixins";
|
|
4
|
+
|
|
5
|
+
.toolbarWrapper {
|
|
6
|
+
position: relative;
|
|
7
|
+
display: flex;
|
|
8
|
+
height: $spacing-09;
|
|
9
|
+
justify-content: flex-end;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.tableToolbar {
|
|
13
|
+
width: 20%;
|
|
14
|
+
min-width: 12.5rem;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.inactiveLink {
|
|
18
|
+
color: $carbon--gray-40;
|
|
19
|
+
cursor: not-allowed;
|
|
20
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
openmrsFetch,
|
|
3
|
+
userHasAccess,
|
|
4
|
+
useSession,
|
|
5
|
+
} from "@openmrs/esm-framework";
|
|
6
|
+
import useSWR from "swr";
|
|
7
|
+
|
|
8
|
+
const customFormRepresentation =
|
|
9
|
+
"(uuid,name,display,encounterType:(uuid,name,viewPrivilege,editPrivilege),version,published,retired,resources:(uuid,name,dataType,valueReference))";
|
|
10
|
+
|
|
11
|
+
const formEncounterUrl = `/ws/rest/v1/form?v=custom:${customFormRepresentation}`;
|
|
12
|
+
const formEncounterUrlPoc = `/ws/rest/v1/form?v=custom:${customFormRepresentation}&q=poc`;
|
|
13
|
+
|
|
14
|
+
export function useGetAllForms(cachedOfflineFormsOnly = false) {
|
|
15
|
+
const session = useSession();
|
|
16
|
+
const showHtmlFormEntryForms = true;
|
|
17
|
+
const url = showHtmlFormEntryForms ? formEncounterUrl : formEncounterUrlPoc;
|
|
18
|
+
const { data, error } = useSWR([url, cachedOfflineFormsOnly], async () => {
|
|
19
|
+
const res = await openmrsFetch(url);
|
|
20
|
+
// show published forms, and hide component forms, and filter based on privileges
|
|
21
|
+
const forms =
|
|
22
|
+
res.data?.results?.filter(
|
|
23
|
+
(form) =>
|
|
24
|
+
// forms should be published
|
|
25
|
+
form.published &&
|
|
26
|
+
// forms should not be component forms
|
|
27
|
+
!/component/i.test(form.name)
|
|
28
|
+
// user should have privileges to edit forms
|
|
29
|
+
) ?? [];
|
|
30
|
+
|
|
31
|
+
return forms;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
forms: data?.filter((form) =>
|
|
36
|
+
Boolean(
|
|
37
|
+
userHasAccess(form.encounterType?.editPrivilege?.display, session?.user)
|
|
38
|
+
)
|
|
39
|
+
),
|
|
40
|
+
isLoading: !error && !data,
|
|
41
|
+
error,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default useGetAllForms;
|
|
File without changes
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { render } from "@testing-library/react";
|
|
3
|
-
import
|
|
3
|
+
import PatientBanner from "./PatientBanner";
|
|
4
4
|
|
|
5
|
-
describe("
|
|
5
|
+
describe("PatientBanner", () => {
|
|
6
6
|
it("renders placeholder information when no data is present", () => {
|
|
7
|
-
render(<
|
|
7
|
+
render(<PatientBanner patientUuid={null} />);
|
|
8
8
|
});
|
|
9
9
|
});
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
SkeletonText,
|
|
11
11
|
} from "carbon-components-react";
|
|
12
12
|
import React, { useState } from "react";
|
|
13
|
-
import styles from "./
|
|
13
|
+
import styles from "./styles.scss";
|
|
14
14
|
import ChevronDown16 from "@carbon/icons-react/es/chevron--down/16";
|
|
15
15
|
import ChevronUp16 from "@carbon/icons-react/es/chevron--up/16";
|
|
16
16
|
import { useTranslation } from "react-i18next";
|
|
17
|
-
import useGetPatient from "
|
|
17
|
+
import useGetPatient from "../hooks/useGetPatient";
|
|
18
18
|
interface PatientInfoProps {
|
|
19
19
|
patientUuid: string;
|
|
20
20
|
}
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { SkeletonText } from "carbon-components-react";
|
|
2
|
+
import React, { useContext } from "react";
|
|
3
|
+
import FormWorkflowContext from "../context/FormWorkflowContext";
|
|
4
|
+
import useGetPatient from "../hooks/useGetPatient";
|
|
5
|
+
import styles from "./styles.scss";
|
|
6
|
+
|
|
7
|
+
const CardContainer = ({ active, onClick, children }) => {
|
|
8
|
+
return (
|
|
9
|
+
<div
|
|
10
|
+
className={`${styles.cardContainer} ${!active && styles.hoverable}`}
|
|
11
|
+
onClick={onClick}
|
|
12
|
+
role="button"
|
|
13
|
+
tabIndex={0}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const PatientCard = ({ patientUuid }) => {
|
|
21
|
+
const { activePatientUuid, editEncounter } = useContext(FormWorkflowContext);
|
|
22
|
+
const patient = useGetPatient(patientUuid);
|
|
23
|
+
const givenName = patient?.name?.[0]?.given?.[0];
|
|
24
|
+
const familyName = patient?.name?.[0]?.family;
|
|
25
|
+
const identifier = patient?.identifier?.[0]?.value;
|
|
26
|
+
|
|
27
|
+
if (!patient) {
|
|
28
|
+
return (
|
|
29
|
+
<CardContainer onClick={() => {}} active={true}>
|
|
30
|
+
<SkeletonText className={styles.skeletonText} />
|
|
31
|
+
</CardContainer>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const active = activePatientUuid === patientUuid;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<CardContainer onClick={() => editEncounter(patientUuid)} active={active}>
|
|
39
|
+
<div className={styles.identifier}>{identifier}</div>
|
|
40
|
+
<div
|
|
41
|
+
className={`${styles.displayName} ${
|
|
42
|
+
active && styles.activeDisplayName
|
|
43
|
+
}`}
|
|
44
|
+
>
|
|
45
|
+
{givenName} {familyName}
|
|
46
|
+
</div>
|
|
47
|
+
</CardContainer>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default PatientCard;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
@import "~@openmrs/esm-styleguide/src/vars";
|
|
2
|
+
@import "~carbon-components/src/globals/scss/vars";
|
|
3
|
+
@import "~carbon-components/src/globals/scss/mixins";
|
|
4
|
+
|
|
5
|
+
.cardContainer {
|
|
6
|
+
padding: $spacing-05;
|
|
7
|
+
&:hover {
|
|
8
|
+
background-color: $carbon--gray-40;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
.skeletonText {
|
|
15
|
+
max-width: 8rem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.identifier {
|
|
19
|
+
font-weight: 300;
|
|
20
|
+
font-size: 0.8rem;
|
|
21
|
+
line-height: 0.9rem;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.displayName {
|
|
25
|
+
font-weight: bold;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.activeDisplayName {
|
|
29
|
+
color: $carbon--blue-50;
|
|
30
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Add20, Close20 } from "@carbon/icons-react";
|
|
2
|
+
import { ExtensionSlot } from "@openmrs/esm-framework";
|
|
3
|
+
import { Button } from "carbon-components-react";
|
|
4
|
+
import React, { useContext } from "react";
|
|
5
|
+
import { Link } from "react-router-dom";
|
|
6
|
+
import FormWorkflowContext from "../context/FormWorkflowContext";
|
|
7
|
+
import styles from "./styles.scss";
|
|
8
|
+
|
|
9
|
+
const PatientSearchHeader = () => {
|
|
10
|
+
const { addPatient } = useContext(FormWorkflowContext);
|
|
11
|
+
const handleSelectPatient = (uuid) => {
|
|
12
|
+
addPatient(uuid);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className={styles.searchHeaderContainer}>
|
|
17
|
+
<span className={styles.padded}>Next patient:</span>
|
|
18
|
+
<span className={styles.searchBarWrapper}>
|
|
19
|
+
<ExtensionSlot
|
|
20
|
+
extensionSlotName="patient-search-bar-slot"
|
|
21
|
+
state={{
|
|
22
|
+
selectPatientAction: handleSelectPatient,
|
|
23
|
+
buttonProps: {
|
|
24
|
+
kind: "primary",
|
|
25
|
+
},
|
|
26
|
+
}}
|
|
27
|
+
/>
|
|
28
|
+
</span>
|
|
29
|
+
<span className={styles.padded}>or</span>
|
|
30
|
+
<span>
|
|
31
|
+
<Button disabled>
|
|
32
|
+
Create new patient <Add20 />
|
|
33
|
+
</Button>
|
|
34
|
+
</span>
|
|
35
|
+
<span style={{ flexGrow: 1 }} />
|
|
36
|
+
<span>
|
|
37
|
+
<Link to="">
|
|
38
|
+
<Button kind="ghost">
|
|
39
|
+
Cancel <Close20 />
|
|
40
|
+
</Button>
|
|
41
|
+
</Link>
|
|
42
|
+
</span>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default PatientSearchHeader;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
@import "~@openmrs/esm-styleguide/src/vars";
|
|
2
|
+
@import "~carbon-components/src/globals/scss/vars";
|
|
3
|
+
@import "~carbon-components/src/globals/scss/mixins";
|
|
4
|
+
|
|
5
|
+
.searchHeaderContainer {
|
|
6
|
+
display: flex;
|
|
7
|
+
background-color: white;
|
|
8
|
+
padding: $spacing-07 $spacing-05;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.searchBarWrapper {
|
|
12
|
+
min-width: 35rem;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.padded {
|
|
16
|
+
padding: $spacing-05;
|
|
17
|
+
}
|
package/translations/en.json
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
|
|
1
|
+
{
|
|
2
|
+
"actions": "Actions",
|
|
3
|
+
"casualGreeting": "hey",
|
|
4
|
+
"dataErrorMessage": "Something went wrong loading data from the server.",
|
|
5
|
+
"errorLoadingData": "Error Loading Data",
|
|
6
|
+
"fillForm": "Fill Form",
|
|
7
|
+
"formalGreeting": "hello",
|
|
8
|
+
"formName": "Form Name",
|
|
9
|
+
"noFormsFound": "No Forms To Show",
|
|
10
|
+
"noFormsFoundMessage": "No forms could be found for this category. Please double check the form concept uuids and access permissions.",
|
|
11
|
+
"selectPatientFirst": "Please select a patient first",
|
|
12
|
+
"startGroupSession": "Start Group Session"
|
|
13
|
+
}
|