Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feature) Query the Client Registry to retrieve patient data and import it into OpenELIS #1219

Merged
merged 24 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7614a39
Query the CR to retrieve patient data into OpenELIS
mherman22 Aug 6, 2024
48b0427
make searching work well
mherman22 Aug 16, 2024
e446a11
fix
mherman22 Aug 18, 2024
5861e7b
fixx
mherman22 Aug 18, 2024
4e4c002
ensures the patient is correctly searched and results got
mherman22 Aug 29, 2024
023a7ea
format
mherman22 Aug 30, 2024
37a2f55
add cr result to ui
mherman22 Aug 31, 2024
6ba8eb3
add fix
mherman22 Aug 31, 2024
0e835ac
fix url when crResult is toggled off
mherman22 Aug 31, 2024
6ec9795
transfer logic to fhirtransform
mherman22 Sep 2, 2024
da101d3
ensure search by other attributes aswell
mherman22 Sep 2, 2024
b65c9f9
add
mherman22 Sep 12, 2024
13fb06e
fix search to query opencr for unavailable patient(s) in openelis
mherman22 Sep 17, 2024
2328e3c
fix
mherman22 Sep 17, 2024
007dcc3
ensure results are not persisted until a user clicks the import button
mherman22 Sep 20, 2024
677aad0
ensure button is only available for opencr result
mherman22 Sep 20, 2024
eca8151
change button from ghost to tertiary
mherman22 Sep 20, 2024
ddf629a
format
mherman22 Sep 20, 2024
88cf0dc
Ensure import from opencr works perfectly
mherman22 Sep 22, 2024
1533fce
generate a dynamic national id for those who don't have them from the CR
mherman22 Sep 28, 2024
02bd0ba
make client registry search configurable
mherman22 Sep 29, 2024
b0fbac3
fix the nationalid generation
mherman22 Sep 29, 2024
94c4504
Add modifications according to reviews
mherman22 Oct 1, 2024
842c80e
minor fix
mozzy11 Oct 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions frontend/src/components/data/PatientResultsTableHeaders.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ export const patientSearchHeaderData = [
key: "nationalId",
header: <FormattedMessage id="patient.natioanalid" />,
},
{
key: "dataSourceName",
header: <FormattedMessage id="patient.dataSourceName" />,
},
];
207 changes: 187 additions & 20 deletions frontend/src/components/patient/SearchPatientForm.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useContext, useState, useEffect } from "react";
import { FormattedMessage, injectIntl, useIntl } from "react-intl";
import "../Style.css";
import { getFromOpenElisServer } from "../utils/Utils";
import { getFromOpenElisServer, postToOpenElisServer } from "../utils/Utils";
import {
Form,
TextInput,
Expand All @@ -20,7 +20,10 @@ import {
TableCell,
Pagination,
Loading,
Toggle,
Tag,
} from "@carbon/react";
import { Person } from "@carbon/react/icons";
import CustomLabNumberInput from "../common/CustomLabNumberInput";
import { patientSearchHeaderData } from "../data/PatientResultsTableHeaders";
import { Formik, Field } from "formik";
Expand All @@ -29,6 +32,7 @@ import { NotificationContext } from "../layout/Layout";
import { AlertDialog, NotificationKinds } from "../common/CustomNotification";
import CustomDatePicker from "../common/CustomDatePicker";
import { ConfigurationContext } from "../layout/Layout";
import CreatePatientFormValues from "../formModel/innitialValues/CreatePatientFormValues";

function SearchPatientForm(props) {
const { notificationVisible, setNotificationVisible, addNotification } =
Expand All @@ -39,20 +43,101 @@ function SearchPatientForm(props) {

const [dob, setDob] = useState("");
const [patientSearchResults, setPatientSearchResults] = useState([]);
const [importStatus, setImportStatus] = useState({});
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(5);
const [loading, setLoading] = useState(false);
const [nextPage, setNextPage] = useState(null);
const [isToggled, setIsToggled] = useState(false);
const [previousPage, setPreviousPage] = useState(null);
const [pagination, setPagination] = useState(false);
const [url, setUrl] = useState("");
const [searchFormValues, setSearchFormValues] = useState(
SearchPatientFormValues,
);

const handlePatientImport = (patientId) => {
console.log("Import button clicked, patientId:", patientId);

const patientSelected = patientSearchResults.find(
(patient) => patient.patientID === patientId,
);
console.log("Patient selected:", patientSelected);

if (!patientSelected) {
addNotification({
title: intl.formatMessage({ id: "notification.title" }),
message: intl.formatMessage({ id: "error.no.patient.data" }),
kind: NotificationKinds.error,
});
return;
}

const dataToSend = {
...CreatePatientFormValues,
patientPK: "",
nationalId: patientSelected.nationalId || "",
subjectNumber: "",
lastName: patientSelected.lastName || "",
firstName: patientSelected.firstName || "",
streetAddress: patientSelected.address?.street || "",
city: patientSelected.address?.city || "",
primaryPhone: patientSelected.contactPhone || "",
gender: patientSelected.gender || "",
birthDateForDisplay: patientSelected.birthdate || "",
commune: patientSelected.commune || "",
education: patientSelected.education || "",
maritialStatus: patientSelected.maritalStatus || "",
nationality: patientSelected.nationality || "",
healthDistrict: patientSelected.healthDistrict || "",
healthRegion: patientSelected.healthRegion || "",
otherNationality: patientSelected.otherNationality || "",
patientContact: {
person: {
firstName: patientSelected.contact?.firstName || "",
lastName: patientSelected.contact?.lastName || "",
primaryPhone: patientSelected.contact?.primaryPhone || "",
email: patientSelected.contact?.email || "",
},
},
};

console.log("Data to send:", dataToSend);

postToOpenElisServer(
"/rest/patient-management",
JSON.stringify(dataToSend),
(status) => {
handlePost(status, patientId);
},
);
};

const handlePost = (status, patientId) => {
setNotificationVisible(true);
if (status === 200) {
addNotification({
title: intl.formatMessage({ id: "notification.title" }),
message: intl.formatMessage({ id: "success.import.patient" }),
kind: NotificationKinds.success,
});
setImportStatus((prevStatus) => ({
...prevStatus,
[patientId]: true,
}));
} else {
addNotification({
title: intl.formatMessage({ id: "notification.title" }),
message: intl.formatMessage({ id: "error.import.patient" }),
kind: NotificationKinds.error,
});
}
};

const handleSubmit = (values) => {
setLoading(true);
values.dateOfBirth = dob;
const searchEndPoint =
let searchEndPoint =
"/rest/patient-search-results?" +
"lastName=" +
values.lastName +
Expand All @@ -74,9 +159,15 @@ function SearchPatientForm(props) {
values.gender +
"&suppressExternalSearch=" +
values.suppressExternalSearch;

if (values.crSearch === true) {
searchEndPoint += "&crSearch=true";
}

getFromOpenElisServer(searchEndPoint, fetchPatientResults);
setUrl(searchEndPoint);
};

const loadNextResultsPage = () => {
setLoading(true);
getFromOpenElisServer(url + "&page=" + nextPage, fetchPatientResults);
Expand All @@ -87,11 +178,24 @@ function SearchPatientForm(props) {
getFromOpenElisServer(url + "&page=" + previousPage, fetchPatientResults);
};

const toggle = () => {
setIsToggled((prev) => !prev);
};

const fetchPatientResults = (res) => {
let patientsResults = res.patientSearchResults;
if (patientsResults.length > 0) {
patientsResults.forEach((item) => (item.id = item.patientID));
setPatientSearchResults(patientsResults);
const openClientRegistryResults = patientsResults.filter(
(item) => item.dataSourceName === "Open Client Registry",
);

if (openClientRegistryResults.length > 0) {
openClientRegistryResults.forEach((item) => (item.id = item.patientID));
setPatientSearchResults(openClientRegistryResults);
} else {
patientsResults.forEach((item) => (item.id = item.patientID));
setPatientSearchResults(patientsResults);
}
} else {
setPatientSearchResults([]);
addNotification({
Expand Down Expand Up @@ -351,6 +455,22 @@ function SearchPatientForm(props) {
/>
</Button>
</Column>
{configurationProperties.MAKE_CLIENT_REGISTRY_CONFIGURABLE ===
mozzy11 marked this conversation as resolved.
Show resolved Hide resolved
"true" && (
<Column lg={4} md={4} sm={2}>
<Toggle
labelText="Client Registry Search"
labelA="false"
labelB="true"
id="toggle-cr"
toggled={isToggled}
onClick={() => {
toggle();
setFieldValue("crSearch", !isToggled);
}}
/>
</Column>
)}
</Grid>
</Form>
)}
Expand Down Expand Up @@ -396,7 +516,7 @@ function SearchPatientForm(props) {
<Table {...getTableProps()}>
<TableHead>
<TableRow>
<TableHeader></TableHeader>
<TableHeader />
{headers.map((header) => (
<TableHeader
key={header.key}
Expand All @@ -408,27 +528,74 @@ function SearchPatientForm(props) {
</TableRow>
</TableHead>
<TableBody>
<>
{rows
.slice((page - 1) * pageSize)
.slice(0, pageSize)
.map((row) => (
{rows
.slice((page - 1) * pageSize, page * pageSize)
.map((row) => {
const dataSourceName = row.cells.find(
(cell) => cell.info.header === "dataSourceName",
)?.value;

return (
<TableRow key={row.id}>
<TableCell>
{" "}
<RadioButton
name="radio-group"
onClick={patientSelected}
labelText=""
id={row.id}
/>
{dataSourceName === "OpenElis" ? (
<RadioButton
name="radio-group"
onClick={patientSelected}
labelText=""
id={row.id}
/>
) : (
<span></span>
)}
</TableCell>

{row.cells.map((cell) => (
<TableCell key={cell.id}>{cell.value}</TableCell>
<TableCell key={cell.id}>
{cell.info.header === "dataSourceName" ? (
<>
<Tag
type={
cell.value === "OpenElis"
? "red"
: cell.value === "Open Client Registry"
? "green"
: "gray"
}
>
{cell.value}
</Tag>
&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
{dataSourceName === "Open Client Registry" ? (
<Button
id={row.id}
kind="tertiary"
onClick={() => handlePatientImport(row.id)}
size="md"
disabled={importStatus[row.id]}
>
<Person size={16} />
{importStatus[row.id] ? (
<span>
&nbsp;&nbsp;Patient Imported
Successfully
</span>
) : (
<span>&nbsp;&nbsp;Import Patient</span>
)}
</Button>
) : (
<span></span>
)}
</>
) : (
cell.value
)}
</TableCell>
))}
</TableRow>
))}
</>
);
})}
</TableBody>
</Table>
</TableContainer>
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@
"search.label.sample": "Select Sample Status",
"pathology.label.report": "Pathology Report",
"patient.natioanalid": "National ID",
"patient.dataSourceName": "Data Source Name",
"patient.label.additionalInfo": "Additional Information",
"sample.entry.available.tests": "Available Tests",
"sample.entry.panels": "Panels",
Expand Down Expand Up @@ -828,6 +829,9 @@
"rulebuilder.label.add.externaltrigger": "Add External `triggered by` message",
"error.duplicate.calculationname": "Duplicate Calculation Name or Error while saving",
"success.save.patient": "Patient Saved Successfully",
"success.import.patient": "Patient Succesfully Imported",
"error.no.patient.data": "No Patient Data to Import",
"error.import.patient": "Error While Importing Patient into OpenELIS",
"error.save.patient": "Error While Saving Patient",
"patient.search.nopatient": "No patients found matching search terms",
"result.search.noresult": "No results found",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package org.openelisglobal.common.provider.query;

import java.util.List;
import lombok.Getter;
import lombok.Setter;
import org.openelisglobal.common.form.IPagingForm;
import org.openelisglobal.common.paging.PagingBean;

public class PatientSearchResultsForm implements IPagingForm {

private PagingBean paging;

@Getter
@Setter
private List<PatientSearchResults> patientSearchResults;

public List<PatientSearchResults> getPatientSearchResults() {
return patientSearchResults;
}

public void setPatientSearchResults(List<PatientSearchResults> patientSearchResults) {
this.patientSearchResults = patientSearchResults;
}

@Override
public void setPaging(PagingBean pagingBean) {
this.paging = pagingBean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ private Map<String, String> getOpenConfigurationProperties() {
ConfigurationProperties.getInstance().getPropertyValue(Property.configurationName));
configs.put(Property.REQUIRE_LAB_UNIT_AT_LOGIN.toString(),
ConfigurationProperties.getInstance().getPropertyValue(Property.REQUIRE_LAB_UNIT_AT_LOGIN));
configs.put(Property.MAKE_CLIENT_REGISTRY_CONFIGURABLE.toString(),
mozzy11 marked this conversation as resolved.
Show resolved Hide resolved
ConfigurationProperties.getInstance().getPropertyValue(Property.MAKE_CLIENT_REGISTRY_CONFIGURABLE));
return configs;
}

Expand Down
Loading
Loading