From c0e28999c005026d1fea000d64c18edc196fa6ac Mon Sep 17 00:00:00 2001 From: mherman22 Date: Wed, 20 Nov 2024 11:05:03 +0300 Subject: [PATCH 01/16] Ensure there are no duplicates in the returned patient results from open client registry --- .../provider/PatientSearchRestController.java | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/openelisglobal/common/rest/provider/PatientSearchRestController.java b/src/main/java/org/openelisglobal/common/rest/provider/PatientSearchRestController.java index 52d02541dc..cdec05185e 100644 --- a/src/main/java/org/openelisglobal/common/rest/provider/PatientSearchRestController.java +++ b/src/main/java/org/openelisglobal/common/rest/provider/PatientSearchRestController.java @@ -205,8 +205,8 @@ private List searchPatientInClientRegistry(String lastName // convert fhir object to patient search result PatientSearchResults transformedPatientSearchResult = SpringContext.getBean(FhirTransformService.class) .transformToOpenElisPatientSearchResults(externalPatient); - // in case the patient object has no NationalId , - // we can construct a dynamic National ID like "NID-{gender}-{dob}-{initials}" + + // Check for null NationalId and generate if needed if (transformedPatientSearchResult.getNationalId() == null || transformedPatientSearchResult.getNationalId().isEmpty()) { String nationalId = generateDynamicID(transformedPatientSearchResult); @@ -214,8 +214,17 @@ private List searchPatientInClientRegistry(String lastName transformedPatientSearchResult.setNationalId(nationalId); } - transformedPatientSearchResult.setDataSourceName(MessageUtil.getMessage("patient.cr.source")); - finalResults.add(transformedPatientSearchResult); + // Skip this patient if it's already in the local database + if (!isPatientDuplicate(transformedPatientSearchResult)) { + transformedPatientSearchResult.setDataSourceName(MessageUtil.getMessage("patient.cr.source")); + finalResults.add(transformedPatientSearchResult); + } else { + LogEvent.logInfo("PatientSearchRestController", "searchPatientInClientRegistry", + String.format("Skipped duplicate patient with NationalId: %s, Name: %s %s", + transformedPatientSearchResult.getNationalId(), + transformedPatientSearchResult.getFirstName(), + transformedPatientSearchResult.getLastName())); + } } return finalResults; @@ -333,4 +342,29 @@ public IQuery buildPatientSearchQuery(IGenericClient clientRegistry return query; } + + private boolean isPatientDuplicate(PatientSearchResults externalPatient) { + List localResults = searchResultsService.getSearchResults(externalPatient.getLastName(), + externalPatient.getFirstName(), null, null, externalPatient.getNationalId(), null, null, null, null, + null); + for (PatientSearchResults localPatient : localResults) { + if (isMatchingPatient(localPatient, externalPatient)) { + return true; + } + } + return false; + } + + private boolean isMatchingPatient(PatientSearchResults local, PatientSearchResults external) { + boolean nationalIdMatch = (local.getNationalId() != null && external.getNationalId() != null) + && local.getNationalId().equalsIgnoreCase(external.getNationalId()); + + boolean firstNameMatch = (local.getFirstName() != null && external.getFirstName() != null) + && local.getFirstName().equalsIgnoreCase(external.getFirstName()); + + boolean lastNameMatch = (local.getLastName() != null && external.getLastName() != null) + && local.getLastName().equalsIgnoreCase(external.getLastName()); + + return nationalIdMatch && firstNameMatch && lastNameMatch; + } } From de5d9dfddb5071a66ce32c1944be60c415631834 Mon Sep 17 00:00:00 2001 From: Aayush Shrestha Date: Tue, 10 Dec 2024 11:05:43 -0800 Subject: [PATCH 02/16] 1339: Used 'isSubmitting' to track the state of the API call --- .../components/patient/CreatePatientForm.js | 23 +++++++++++++------ frontend/src/components/utils/Utils.js | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/patient/CreatePatientForm.js b/frontend/src/components/patient/CreatePatientForm.js index c7280ab03e..b83c4e0150 100644 --- a/frontend/src/components/patient/CreatePatientForm.js +++ b/frontend/src/components/patient/CreatePatientForm.js @@ -1,11 +1,7 @@ import React, { useState, useRef, useEffect, useContext } from "react"; import { FormattedMessage, injectIntl, useIntl } from "react-intl"; import "../Style.css"; -import { - getFromOpenElisServer, - getFromOpenElisServerSync, - postToOpenElisServer, -} from "../utils/Utils"; +import { getFromOpenElisServer, postToOpenElisServer } from "../utils/Utils"; import { nationalityList } from "../data/countries"; import format from "date-fns/format"; import { @@ -66,6 +62,9 @@ function CreatePatientForm(props) { const [subjectNo, setSubjectNo] = useState( props.selectedPatient.subjectNumber, ); + + const [isSubmitting, setIsSubmitting] = useState(false); + const handleNationalIdChange = (event) => { const newValue = event.target.value; setNationalId(newValue); @@ -308,6 +307,13 @@ function CreatePatientForm(props) { }; const handleSubmit = async (values, { resetForm }) => { + // Prevent multiple submissions. + if (isSubmitting) { + return; + } + + setIsSubmitting(true); + if ("years" in values) { delete values.years; } @@ -330,7 +336,9 @@ function CreatePatientForm(props) { days: "", }); }, - ); + ).then(() => { + setIsSubmitting(false); + }); }; const handlePost = (status) => { @@ -1007,7 +1015,7 @@ function CreatePatientForm(props) { {props.showActionsButton && ( <> - @@ -1015,6 +1023,7 @@ function CreatePatientForm(props) { - - - - - - ); -}; - -export default ActivityReport; From 57b6d499aec7113ed1a4764d07fb23f60f674e2e Mon Sep 17 00:00:00 2001 From: mozzy11 Date: Wed, 8 Jan 2025 08:26:02 +0300 Subject: [PATCH 07/16] use existing call back to disable submiting --- frontend/src/components/patient/CreatePatientForm.js | 5 ++--- frontend/src/components/utils/Utils.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/patient/CreatePatientForm.js b/frontend/src/components/patient/CreatePatientForm.js index b83c4e0150..eeec370eed 100644 --- a/frontend/src/components/patient/CreatePatientForm.js +++ b/frontend/src/components/patient/CreatePatientForm.js @@ -336,13 +336,12 @@ function CreatePatientForm(props) { days: "", }); }, - ).then(() => { - setIsSubmitting(false); - }); + ) }; const handlePost = (status) => { setNotificationVisible(true); + setIsSubmitting(false); if (status === 200) { addNotification({ title: intl.formatMessage({ id: "notification.title" }), diff --git a/frontend/src/components/utils/Utils.js b/frontend/src/components/utils/Utils.js index 5335d0daab..b59895d595 100644 --- a/frontend/src/components/utils/Utils.js +++ b/frontend/src/components/utils/Utils.js @@ -35,7 +35,7 @@ export const postToOpenElisServer = ( callback, extraParams, ) => { - return fetch( + fetch( config.serverBaseUrl + endPoint, { From f6471cd6229baf9cf16802756fdd3e10a50e751e Mon Sep 17 00:00:00 2001 From: mozzy11 Date: Wed, 8 Jan 2025 08:52:59 +0300 Subject: [PATCH 08/16] disbale multiple submition for Order entry --- frontend/src/components/addOrder/Index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/addOrder/Index.js b/frontend/src/components/addOrder/Index.js index 7eca6c5a1c..717dba1c1f 100755 --- a/frontend/src/components/addOrder/Index.js +++ b/frontend/src/components/addOrder/Index.js @@ -45,6 +45,7 @@ const Index = () => { const [orderFormValues, setOrderFormValues] = useState(SampleOrderFormValues); const [samples, setSamples] = useState([sampleObject]); const [errors, setErrors] = useState([]); + const [isSubmitting, setIsSubmitting] = useState(false); let SampleTypes = []; let sampleTypeMap = {}; @@ -536,6 +537,7 @@ const Index = () => { }; const handlePost = (status) => { + setIsSubmitting(false); if (status === 200) { showAlertMessage( , @@ -562,6 +564,11 @@ const Index = () => { const handleSubmitOrderForm = (e) => { e.preventDefault(); + // Prevent multiple submissions. + if (isSubmitting) { + return; + } + setIsSubmitting(true); if ("years" in orderFormValues.patientProperties) { delete orderFormValues.patientProperties.years; } @@ -802,7 +809,7 @@ const Index = () => { diff --git a/frontend/src/components/validation/Validation.js b/frontend/src/components/validation/Validation.js index cd7526fbb6..eb1190b237 100644 --- a/frontend/src/components/validation/Validation.js +++ b/frontend/src/components/validation/Validation.js @@ -35,6 +35,7 @@ const Validation = (props) => { const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(100); + const [isSubmitting, setIsSubmitting] = useState(false); useEffect(() => { componentMounted.current = true; @@ -114,6 +115,10 @@ const Validation = (props) => { ]; const handleSave = (values) => { + if (isSubmitting) { + return; + } + setIsSubmitting(true); postToOpenElisServer( "/rest/accessionValidationByRangeUpdate", JSON.stringify(props.results), @@ -123,6 +128,7 @@ const Validation = (props) => { const handleResponse = (status) => { let message = intl.formatMessage({ id: "validation.save.error" }); let kind = NotificationKinds.error; + setIsSubmitting(false); if (status == 200) { message = intl.formatMessage({ id: "validation.save.success" }); kind = NotificationKinds.success; @@ -464,6 +470,7 @@ const Validation = (props) => { onClick={() => handleSave(values)} id="submit" style={{ marginTop: "16px" }} + disabled={isSubmitting} > From 63fef9f1ae8ffdd2053fa27a0f61995d967801b5 Mon Sep 17 00:00:00 2001 From: mozzy11 Date: Wed, 8 Jan 2025 10:00:40 +0300 Subject: [PATCH 11/16] prevent multiple submisions on modify order --- frontend/src/components/modifyOrder/ModifyOrder.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/modifyOrder/ModifyOrder.js b/frontend/src/components/modifyOrder/ModifyOrder.js index 4ca33d6d8f..c71e1754e1 100644 --- a/frontend/src/components/modifyOrder/ModifyOrder.js +++ b/frontend/src/components/modifyOrder/ModifyOrder.js @@ -53,6 +53,7 @@ const ModifyOrder = () => { const [orderFormValues, setOrderFormValues] = useState(ModifyOrderFormValues); const [samples, setSamples] = useState([sampleObject]); const [errors, setErrors] = useState([]); + const [isSubmitting, setIsSubmitting] = useState(false); useEffect(() => { componentMounted.current = true; @@ -110,6 +111,7 @@ const ModifyOrder = () => { }; const handlePost = (status) => { + setIsSubmitting(false); if (status === 200) { showAlertMessage( , @@ -124,6 +126,10 @@ const ModifyOrder = () => { }; const handleSubmitOrderForm = (e) => { e.preventDefault(); + if (isSubmitting) { + return; + } + setIsSubmitting(true); setPage(page + 1); orderFormValues.sampleOrderItems.modified = true; //remove display Lists rom the form @@ -337,7 +343,7 @@ const ModifyOrder = () => { kind="primary" className="forwardButton" onClick={handleSubmitOrderForm} - disabled={errors?.errors?.length > 0 ? true : false} + disabled={isSubmitting || errors?.errors?.length > 0 ? true : false} > From 1e6882e2be792d16683af9c6ffb766f04060195d Mon Sep 17 00:00:00 2001 From: mozzy11 Date: Wed, 8 Jan 2025 10:13:49 +0300 Subject: [PATCH 12/16] prevent multiple submisiions for programms --- frontend/src/components/cytology/CytologyCaseView.js | 8 ++++++++ .../immunohistochemistry/ImmunohistochemistryCaseView.js | 8 ++++++++ frontend/src/components/modifyOrder/ModifyOrder.js | 4 +++- frontend/src/components/pathology/PathologyCaseView.js | 8 ++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/cytology/CytologyCaseView.js b/frontend/src/components/cytology/CytologyCaseView.js index 3c99a0986d..ae24938e41 100644 --- a/frontend/src/components/cytology/CytologyCaseView.js +++ b/frontend/src/components/cytology/CytologyCaseView.js @@ -87,6 +87,7 @@ function CytologyCaseView() { const [reportTypes, setReportTypes] = useState([]); const [slidesToAdd, setSlidesToAdd] = useState(1); const [isConfirmOpen, setConfirmOpen] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); const [reportParams, setReportParams] = useState({ 0: { submited: false, @@ -108,6 +109,7 @@ function CytologyCaseView() { async function displayStatus(response) { var body = await response.json(); console.debug(body); + setIsSubmitting(false); var status = response.status; setNotificationVisible(true); if (status == "200") { @@ -173,6 +175,10 @@ function CytologyCaseView() { }); const save = (e) => { + if (isSubmitting) { + return; + } + setIsSubmitting(true); let specimenAdequacy = null; if (pathologySampleInfo.specimenAdequacy) { specimenAdequacy = pathologySampleInfo.specimenAdequacy; @@ -418,6 +424,7 @@ function CytologyCaseView() { diff --git a/frontend/src/components/pathology/PathologyCaseView.js b/frontend/src/components/pathology/PathologyCaseView.js index 2a573fda2f..af659ed8b0 100644 --- a/frontend/src/components/pathology/PathologyCaseView.js +++ b/frontend/src/components/pathology/PathologyCaseView.js @@ -70,6 +70,7 @@ function PathologyCaseView() { const [pagination, setPagination] = useState(false); const [currentApiPage, setCurrentApiPage] = useState(null); const [totalApiPages, setTotalApiPages] = useState(null); + const [isSubmitting, setIsSubmitting] = useState(false); const [reportParams, setReportParams] = useState({ 0: { submited: false, @@ -80,6 +81,7 @@ function PathologyCaseView() { async function displayStatus(response) { var body = await response.json(); console.debug(body); + setIsSubmitting(false); var status = response.status; setNotificationVisible(true); if (status == "200") { @@ -145,6 +147,10 @@ function PathologyCaseView() { }); const save = (e) => { + if (isSubmitting) { + return; + } + setIsSubmitting(true); let submitValues = { assignedTechnicianId: pathologySampleInfo.assignedTechnicianId, assignedPathologistId: pathologySampleInfo.assignedPathologistId, @@ -375,6 +381,7 @@ function PathologyCaseView() { diff --git a/frontend/src/components/admin/reflexTests/ReflexRuleForm.js b/frontend/src/components/admin/reflexTests/ReflexRuleForm.js index 035ec8988c..d696a6b681 100644 --- a/frontend/src/components/admin/reflexTests/ReflexRuleForm.js +++ b/frontend/src/components/admin/reflexTests/ReflexRuleForm.js @@ -87,6 +87,7 @@ function ReflexRule() { }); //{field :{index :{field_index:[]}}} const [counter, setCounter] = useState(0); const [loading, setLoading] = useState(true); + const [isSubmitting, setIsSubmitting] = useState(false); const [errors, setErrors] = useState({}); const { notificationVisible, setNotificationVisible, addNotification } = useContext(NotificationContext); @@ -340,6 +341,7 @@ function ReflexRule() { }; const handleSubmited = (status, index) => { + setIsSubmitting(false); setNotificationVisible(true); if (status == "200") { const element = document.getElementById("submit_" + index); @@ -360,6 +362,10 @@ function ReflexRule() { const handleSubmit = (event, index) => { event.preventDefault(); + if (isSubmitting) { + return; + } + setIsSubmitting(true); console.debug(JSON.stringify(ruleList[index])); postToOpenElisServer( "/rest/reflexrule", @@ -737,7 +743,13 @@ function ReflexRule() { <>