+
+ Gender :
{GENDER_TYPES.find((i) => i.id === patientData.gender)?.text}
-
+
Contact person :
{" "}
From 22f36fd6ba73ee2d8754564f090ad0b16f689079 Mon Sep 17 00:00:00 2001
From: Ashesh <3626859+Ashesh3@users.noreply.github.com>
Date: Thu, 28 Dec 2023 17:07:31 +0530
Subject: [PATCH 02/19] Add consciousness level options for normal daily round
type (#6935)
---
src/Common/constants.tsx | 13 ++++++++++++
.../Form/FormFields/RadioFormField.tsx | 3 ++-
.../Patient/DailyRoundListDetails.tsx | 16 +++++++++++++-
src/Components/Patient/DailyRounds.tsx | 21 +++++++++++++++++--
4 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx
index 23c02e389f3..f472e8b193c 100644
--- a/src/Common/constants.tsx
+++ b/src/Common/constants.tsx
@@ -300,6 +300,19 @@ export const DISCHARGE_REASONS = [
{ id: "LAMA", text: "LAMA" },
];
+export const CONSCIOUSNESS_LEVEL = [
+ { id: "UNRESPONSIVE", text: "Unresponsive" },
+ { id: "RESPONDS_TO_PAIN", text: "Responds to Pain" },
+ { id: "RESPONDS_TO_VOICE", text: "Responds to Voice" },
+ { id: "ALERT", text: "Alert" },
+ { id: "AGITATED_OR_CONFUSED", text: "Agitated or Confused" },
+ {
+ id: "Onset of Agitation and Confusion",
+ text: "Onset of Agitation and Confusion",
+ },
+ { id: "UNKNOWN", text: "Unknown" },
+];
+
export const LINES_CATHETER_CHOICES: Array = [
{ id: 1, text: "CVP catheter " },
{ id: 2, text: "Arterial Line" },
diff --git a/src/Components/Form/FormFields/RadioFormField.tsx b/src/Components/Form/FormFields/RadioFormField.tsx
index 3d1a9b7d8ac..905986d62af 100644
--- a/src/Components/Form/FormFields/RadioFormField.tsx
+++ b/src/Components/Form/FormFields/RadioFormField.tsx
@@ -5,13 +5,14 @@ type Props = FormFieldBaseProps & {
options: T[];
optionDisplay: (option: T) => React.ReactNode;
optionValue: (option: T) => string;
+ containerClassName?: string;
};
const RadioFormField = (props: Props) => {
const field = useFormFieldPropsResolver(props);
return (
-
+
{props.options.map((option, idx) => {
const value = props.optionValue(option);
const optionId = `${props.name}-${idx}`;
diff --git a/src/Components/Patient/DailyRoundListDetails.tsx b/src/Components/Patient/DailyRoundListDetails.tsx
index 9ac68a20ca7..8f313c0a51d 100644
--- a/src/Components/Patient/DailyRoundListDetails.tsx
+++ b/src/Components/Patient/DailyRoundListDetails.tsx
@@ -1,6 +1,10 @@
import { lazy, useCallback, useState } from "react";
import { useDispatch } from "react-redux";
-import { CURRENT_HEALTH_CHANGE, SYMPTOM_CHOICES } from "../../Common/constants";
+import {
+ CONSCIOUSNESS_LEVEL,
+ CURRENT_HEALTH_CHANGE,
+ SYMPTOM_CHOICES,
+} from "../../Common/constants";
import { statusType, useAbortableEffect } from "../../Common/utils";
import { getConsultationDailyRoundsDetails } from "../../Redux/actions";
import { DailyRoundsModel } from "./models";
@@ -183,6 +187,16 @@ export const DailyRoundListDetails = (props: any) => {
{dailyRoundListDetailsData.rhythm_detail ?? "-"}
+
+
+ Level Of Consciousness:{" "}
+
+ {dailyRoundListDetailsData.consciousness_level
+ ? CONSCIOUSNESS_LEVEL.find(
+ (i) => i.id === dailyRoundListDetailsData.consciousness_level
+ )?.text
+ : "-"}
+
Recommend Discharge:{" "}
diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx
index a9a31f2aa14..2b8bec1a75f 100644
--- a/src/Components/Patient/DailyRounds.tsx
+++ b/src/Components/Patient/DailyRounds.tsx
@@ -4,6 +4,7 @@ import dayjs from "dayjs";
import { lazy, useCallback, useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import {
+ CONSCIOUSNESS_LEVEL,
PATIENT_CATEGORIES,
REVIEW_AT_CHOICES,
RHYTHM_CHOICES,
@@ -35,6 +36,7 @@ import TextAreaFormField from "../Form/FormFields/TextAreaFormField";
import TextFormField from "../Form/FormFields/TextFormField";
import { FieldChangeEvent } from "../Form/FormFields/Utils";
import PatientCategorySelect from "./PatientCategorySelect";
+import RadioFormField from "../Form/FormFields/RadioFormField";
const Loading = lazy(() => import("../Common/Loading"));
const initForm: any = {
@@ -59,6 +61,7 @@ const initForm: any = {
rhythm: "0",
rhythm_detail: "",
ventilator_spo2: null,
+ consciousness_level: "Unknown",
// bed: null,
};
@@ -129,6 +132,7 @@ export const DailyRounds = (props: any) => {
"ventilator_spo2",
"rhythm",
"rhythm_detail",
+ "consciousness_level",
];
useEffect(() => {
@@ -312,6 +316,7 @@ export const DailyRounds = (props: any) => {
rhythm: Number(state.form.rhythm) || 0,
rhythm_detail: state.form.rhythm_detail,
ventilator_spo2: state.form.ventilator_spo2,
+ consciousness_level: state.form.consciousness_level,
};
}
} else {
@@ -637,9 +642,21 @@ export const DailyRounds = (props: any) => {
+
+ ({
+ label: level.text,
+ value: level.id,
+ }))}
+ optionDisplay={(option) => option.label}
+ optionValue={(option) => option.value}
+ containerClassName="grid gap-1 grid-cols-1"
/>
>
)}
From 8197f29b3109b653d09cd131614ebd7f442becdb Mon Sep 17 00:00:00 2001
From: Ashesh <3626859+Ashesh3@users.noreply.github.com>
Date: Fri, 29 Dec 2023 17:57:03 +0530
Subject: [PATCH 03/19] Fix empty state in LocationManagement and BedManagement
(#6937)
* Fix empty state in LocationManagement
* Refactor BedManagement component
---
src/CAREUI/misc/PaginatedList.tsx | 2 +-
src/Components/Facility/BedManagement.tsx | 24 +++++++++----------
.../Facility/LocationManagement.tsx | 14 +++++------
3 files changed, 19 insertions(+), 21 deletions(-)
diff --git a/src/CAREUI/misc/PaginatedList.tsx b/src/CAREUI/misc/PaginatedList.tsx
index 61c67f97ae2..1487d69e4fa 100644
--- a/src/CAREUI/misc/PaginatedList.tsx
+++ b/src/CAREUI/misc/PaginatedList.tsx
@@ -130,7 +130,7 @@ interface ItemsProps {
const Items = (props: ItemsProps) => {
const { loading, items } = useContextualized();
- if (loading) {
+ if (loading || items.length === 0) {
return null;
}
diff --git a/src/Components/Facility/BedManagement.tsx b/src/Components/Facility/BedManagement.tsx
index 68e9fade43d..d8799f1fbc5 100644
--- a/src/Components/Facility/BedManagement.tsx
+++ b/src/Components/Facility/BedManagement.tsx
@@ -182,24 +182,22 @@ export const BedManagement = (props: BedManagementProps) => {
));
} else if (data?.results.length === 0) {
BedList = (
-
+
No beds available in this location
);
}
- if (data?.results.length) {
- bed = (
- <>
- {BedList}
- {data.count && (
-
- )}
- >
- );
- }
+ bed = (
+ <>
+ {BedList}
+ {Boolean(data?.count && data.count > 0) && (
+
+ )}
+ >
+ );
if (loading) {
return ;
diff --git a/src/Components/Facility/LocationManagement.tsx b/src/Components/Facility/LocationManagement.tsx
index b7a758c5055..93a08794c82 100644
--- a/src/Components/Facility/LocationManagement.tsx
+++ b/src/Components/Facility/LocationManagement.tsx
@@ -46,14 +46,14 @@ export default function LocationManagement({ facilityId }: Props) {
Add New Location
-
- No locations available
-
-
-
-
-
+
+ No locations available
+
+
+
+
+
className="my-8 grid gap-3 @4xl:grid-cols-2 @6xl:grid-cols-3 @[100rem]:grid-cols-4 lg:mx-8">
{(item) => }
From 096905d645fa4c0b4fef9e14537961f1639e1502 Mon Sep 17 00:00:00 2001
From: Rithvik Nishad
Date: Fri, 29 Dec 2023 23:20:27 +0530
Subject: [PATCH 04/19] fixes not found errors in investigation and other type
errors (#6948)
---
src/Components/Facility/ConsultationDetails/index.tsx | 4 ++++
src/Components/Facility/models.tsx | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx
index abc7305a00b..c6cc9e02275 100644
--- a/src/Components/Facility/ConsultationDetails/index.tsx
+++ b/src/Components/Facility/ConsultationDetails/index.tsx
@@ -46,6 +46,8 @@ const symptomChoices = [...SYMPTOM_CHOICES];
export interface ConsultationTabProps {
consultationId: string;
+ facilityId: string;
+ patientId: string;
consultationData: ConsultationModel;
patientData: PatientModel;
}
@@ -189,6 +191,8 @@ export const ConsultationDetails = (props: any) => {
const consultationTabProps: ConsultationTabProps = {
consultationId,
consultationData,
+ patientId: consultationData.patient,
+ facilityId: consultationData.facility,
patientData,
};
diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx
index 90191e3321f..c3ac910970c 100644
--- a/src/Components/Facility/models.tsx
+++ b/src/Components/Facility/models.tsx
@@ -109,12 +109,12 @@ export interface ConsultationModel {
discharge_notes?: string;
examination_details?: string;
history_of_present_illness?: string;
- facility?: number;
+ facility: string;
facility_name?: string;
id: string;
modified_date?: string;
other_symptoms?: string;
- patient?: string;
+ patient: string;
treatment_plan?: string;
referred_to?: FacilityModel["id"];
referred_to_object?: FacilityModel;
From 06a2afdbc875ab63e691900c23f039e8d64cc759 Mon Sep 17 00:00:00 2001
From: Ashesh <3626859+Ashesh3@users.noreply.github.com>
Date: Fri, 29 Dec 2023 23:20:57 +0530
Subject: [PATCH 05/19] Update consciousness level constants (#6947)
---
src/Common/constants.tsx | 2 +-
src/Components/Patient/DailyRounds.tsx | 103 +++++++++++--------------
2 files changed, 45 insertions(+), 60 deletions(-)
diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx
index f472e8b193c..647c77ecf57 100644
--- a/src/Common/constants.tsx
+++ b/src/Common/constants.tsx
@@ -307,7 +307,7 @@ export const CONSCIOUSNESS_LEVEL = [
{ id: "ALERT", text: "Alert" },
{ id: "AGITATED_OR_CONFUSED", text: "Agitated or Confused" },
{
- id: "Onset of Agitation and Confusion",
+ id: "ONSET_OF_AGITATION_AND_CONFUSION",
text: "Onset of Agitation and Confusion",
},
{ id: "UNKNOWN", text: "Unknown" },
diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx
index 2b8bec1a75f..4def8ed74eb 100644
--- a/src/Components/Patient/DailyRounds.tsx
+++ b/src/Components/Patient/DailyRounds.tsx
@@ -1,7 +1,7 @@
import { navigate } from "raviger";
import dayjs from "dayjs";
-import { lazy, useCallback, useEffect, useState } from "react";
+import { lazy, useCallback, useState } from "react";
import { useDispatch } from "react-redux";
import {
CONSCIOUSNESS_LEVEL,
@@ -61,7 +61,7 @@ const initForm: any = {
rhythm: "0",
rhythm_detail: "",
ventilator_spo2: null,
- consciousness_level: "Unknown",
+ consciousness_level: "UNKNOWN",
// bed: null,
};
@@ -135,40 +135,6 @@ export const DailyRounds = (props: any) => {
"consciousness_level",
];
- useEffect(() => {
- (async () => {
- if (patientId) {
- const res = await dispatchAction(getPatient({ id: patientId }));
- if (res.data) {
- setPatientName(res.data.name);
- setFacilityName(res.data.facility_object.name);
- setConsultationSuggestion(res.data.last_consultation?.suggestion);
- setPreviousReviewInterval(
- Number(res.data.last_consultation.review_interval)
- );
- const getAction =
- TELEMEDICINE_ACTIONS.find((action) => action.id === res.data.action)
- ?.text || "NO_ACTION";
- setPreviousAction(getAction);
- setInitialData({
- ...initialData,
- action: getAction,
- });
- dispatch({
- type: "set_form",
- form: {
- ...state.form,
- action: getAction,
- },
- });
- }
- } else {
- setPatientName("");
- setFacilityName("");
- }
- })();
- }, [dispatchAction, patientId]);
-
const fetchRoundDetails = useCallback(
async (status: statusType) => {
setIsLoading(true);
@@ -176,6 +142,8 @@ export const DailyRounds = (props: any) => {
getConsultationDailyRoundsDetails({ consultationId, id })
);
+ let formData: any = {};
+
if (!status.aborted) {
if (res?.data) {
const data = {
@@ -191,34 +159,41 @@ export const DailyRounds = (props: any) => {
"0",
admitted_to: res.data.admitted_to ? res.data.admitted_to : "Select",
};
- dispatch({ type: "set_form", form: data });
- setInitialData(data);
+ formData = { ...formData, ...data };
}
setIsLoading(false);
}
- },
- [consultationId, id, dispatchAction]
- );
- useAbortableEffect(
- (status: statusType) => {
- if (id) {
- fetchRoundDetails(status);
+ if (patientId) {
+ const res = await dispatchAction(getPatient({ id: patientId }));
+ if (res.data) {
+ setPatientName(res.data.name);
+ setFacilityName(res.data.facility_object.name);
+ setConsultationSuggestion(res.data.last_consultation?.suggestion);
+ setPreviousReviewInterval(
+ Number(res.data.last_consultation.review_interval)
+ );
+ const getAction =
+ TELEMEDICINE_ACTIONS.find((action) => action.id === res.data.action)
+ ?.text || "NO_ACTION";
+ setPreviousAction(getAction);
+ setInitialData({
+ ...initialData,
+ action: getAction,
+ });
+ formData = { ...formData, ...{ action: getAction } };
+ }
+ } else {
+ setPatientName("");
+ setFacilityName("");
}
- },
- [dispatchAction, fetchRoundDetails]
- );
-
- useEffect(() => {
- (async () => {
if (consultationId && !id) {
const res = await dispatchAction(
getDailyReport({ limit: 1, offset: 0 }, { consultationId })
);
setHasPreviousLog(res.data.count > 0);
- dispatch({
- type: "set_form",
- form: {
- ...state.form,
+ formData = {
+ ...formData,
+ ...{
patient_category: res.data.patient_category
? PATIENT_CATEGORIES.find(
(i) => i.text === res.data.patient_category
@@ -229,12 +204,22 @@ export const DailyRounds = (props: any) => {
RHYTHM_CHOICES.find((i) => i.text === res.data.rhythm)?.id) ||
"0",
temperature: parseFloat(res.data.temperature),
- // clone_last: res.data.count > 0 ? true : false,
},
- });
+ };
+ }
+ dispatch({ type: "set_form", form: formData });
+ setInitialData(formData);
+ },
+ [consultationId, id, dispatchAction, patientId]
+ );
+ useAbortableEffect(
+ (status: statusType) => {
+ if (id) {
+ fetchRoundDetails(status);
}
- })();
- }, [dispatchAction, consultationId, id]);
+ },
+ [dispatchAction, fetchRoundDetails]
+ );
const validateForm = () => {
const errors = { ...initError };
From 1085e0f083125a466170df5470eb3ad33d2e4285 Mon Sep 17 00:00:00 2001
From: Rithvik Nishad
Date: Fri, 29 Dec 2023 23:47:55 +0530
Subject: [PATCH 06/19] fix resp. rate from being 0 instead of null when unset
(#6949)
* fix resp. rate from being 0 instead of null
* fix relative time alignment
---
src/CAREUI/display/RecordMeta.tsx | 8 +++++---
src/Components/Patient/DailyRounds.tsx | 4 ++--
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/CAREUI/display/RecordMeta.tsx b/src/CAREUI/display/RecordMeta.tsx
index d4d32e437c8..5e1e117f9d6 100644
--- a/src/CAREUI/display/RecordMeta.tsx
+++ b/src/CAREUI/display/RecordMeta.tsx
@@ -1,7 +1,8 @@
import CareIcon from "../icons/CareIcon";
import {
- formatDateTime,
+ formatDate,
formatName,
+ formatTime,
isUserOnline,
relativeTime,
} from "../../Utils/utils";
@@ -37,8 +38,9 @@ const RecordMeta = ({
let child = (
{relativeTime(time)}
-
- {formatDateTime(time)}
+
+ {formatTime(time)}
+ {formatDate(time)}
{user && !inlineUser && (
by
diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx
index 4def8ed74eb..06431457b0e 100644
--- a/src/Components/Patient/DailyRounds.tsx
+++ b/src/Components/Patient/DailyRounds.tsx
@@ -296,9 +296,9 @@ export const DailyRounds = (props: any) => {
}
: undefined,
pulse: state.form.pulse,
- resp: Number(state.form.resp),
+ resp: state.form.resp,
temperature: state.form.temperature,
- rhythm: Number(state.form.rhythm) || 0,
+ rhythm: state.form.rhythm || 0,
rhythm_detail: state.form.rhythm_detail,
ventilator_spo2: state.form.ventilator_spo2,
consciousness_level: state.form.consciousness_level,
From 8aea0cc9139c507b83784986d9d2c4eec7a7baf6 Mon Sep 17 00:00:00 2001
From: Rithvik Nishad
Date: Sat, 30 Dec 2023 15:41:36 +0530
Subject: [PATCH 07/19] fix has previous log update not being filled (#6951)
---
src/Components/Patient/DailyRounds.tsx | 51 +++++++++++++-------------
1 file changed, 26 insertions(+), 25 deletions(-)
diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx
index 06431457b0e..ec2f070aa20 100644
--- a/src/Components/Patient/DailyRounds.tsx
+++ b/src/Components/Patient/DailyRounds.tsx
@@ -138,31 +138,34 @@ export const DailyRounds = (props: any) => {
const fetchRoundDetails = useCallback(
async (status: statusType) => {
setIsLoading(true);
- const res = await dispatchAction(
- getConsultationDailyRoundsDetails({ consultationId, id })
- );
-
- let formData: any = {};
+ let formData: any = initialData;
+ if (id) {
+ const res = await dispatchAction(
+ getConsultationDailyRoundsDetails({ consultationId, id })
+ );
- if (!status.aborted) {
- if (res?.data) {
- const data = {
- ...res.data,
- patient_category: res.data.patient_category
- ? PATIENT_CATEGORIES.find(
- (i) => i.text === res.data.patient_category
- )?.id ?? ""
- : "",
- rhythm:
- (res.data.rhythm &&
- RHYTHM_CHOICES.find((i) => i.text === res.data.rhythm)?.id) ||
- "0",
- admitted_to: res.data.admitted_to ? res.data.admitted_to : "Select",
- };
- formData = { ...formData, ...data };
+ if (!status.aborted) {
+ if (res?.data) {
+ const data = {
+ ...res.data,
+ patient_category: res.data.patient_category
+ ? PATIENT_CATEGORIES.find(
+ (i) => i.text === res.data.patient_category
+ )?.id ?? ""
+ : "",
+ rhythm:
+ (res.data.rhythm &&
+ RHYTHM_CHOICES.find((i) => i.text === res.data.rhythm)?.id) ||
+ "0",
+ admitted_to: res.data.admitted_to
+ ? res.data.admitted_to
+ : "Select",
+ };
+ formData = { ...formData, ...data };
+ }
}
- setIsLoading(false);
}
+ setIsLoading(false);
if (patientId) {
const res = await dispatchAction(getPatient({ id: patientId }));
if (res.data) {
@@ -214,9 +217,7 @@ export const DailyRounds = (props: any) => {
);
useAbortableEffect(
(status: statusType) => {
- if (id) {
- fetchRoundDetails(status);
- }
+ fetchRoundDetails(status);
},
[dispatchAction, fetchRoundDetails]
);
From c5c86aa594e11e832b18cc6fa906ce04d7e041f7 Mon Sep 17 00:00:00 2001
From: Rithvik Nishad
Date: Sat, 30 Dec 2023 22:41:29 +0530
Subject: [PATCH 08/19] fix daily rounds vital fields not clearing (#6954)
* fix daily rounds vital fields not clearing
* Fix blood pressure form field and daily rounds component
* Fix default blood pressure values in DailyRounds component
* Fix handling of negative values in blood pressure
---------
Co-authored-by: Ashesh3 <3626859+Ashesh3@users.noreply.github.com>
---
.../Common/BloodPressureFormField.tsx | 9 ++--
.../Facility/Consultations/Mews.tsx | 1 +
.../Patient/DailyRoundListDetails.tsx | 10 +++-
src/Components/Patient/DailyRounds.tsx | 50 +++++++++++++++----
4 files changed, 53 insertions(+), 17 deletions(-)
diff --git a/src/Components/Common/BloodPressureFormField.tsx b/src/Components/Common/BloodPressureFormField.tsx
index ed0557ae8e3..3ff2774b900 100644
--- a/src/Components/Common/BloodPressureFormField.tsx
+++ b/src/Components/Common/BloodPressureFormField.tsx
@@ -21,7 +21,7 @@ export default function BloodPressureFormField(props: Props) {
name: field.name,
value: {
...field.value,
- [event.name]: event.value,
+ [event.name]: event.value ?? -1,
},
});
};
@@ -35,9 +35,10 @@ export default function BloodPressureFormField(props: Props) {
MAP: {map.toFixed(1)}
- ) : undefined,
+ labelSuffix:
+ map && map !== -1 ? (
+ MAP: {map.toFixed(1)}
+ ) : undefined,
}}
>
diff --git a/src/Components/Facility/Consultations/Mews.tsx b/src/Components/Facility/Consultations/Mews.tsx
index 6b8e7de806e..5160e42f9f2 100644
--- a/src/Components/Facility/Consultations/Mews.tsx
+++ b/src/Components/Facility/Consultations/Mews.tsx
@@ -26,6 +26,7 @@ const getHeartRateScore = (value?: number) => {
const getSystolicBPScore = (value?: number) => {
if (typeof value !== "number") return;
+ if (value === -1) return;
if (value <= 70) return 3;
if (value <= 80) return 2;
diff --git a/src/Components/Patient/DailyRoundListDetails.tsx b/src/Components/Patient/DailyRoundListDetails.tsx
index 8f313c0a51d..0a73607d688 100644
--- a/src/Components/Patient/DailyRoundListDetails.tsx
+++ b/src/Components/Patient/DailyRoundListDetails.tsx
@@ -158,14 +158,20 @@ export const DailyRoundListDetails = (props: any) => {
Systolic:{" "}
- {dailyRoundListDetailsData.bp?.systolic ?? "-"}
+ {dailyRoundListDetailsData.bp?.systolic &&
+ dailyRoundListDetailsData.bp?.systolic !== -1
+ ? dailyRoundListDetailsData.bp?.systolic
+ : "-"}
{" "}
Diastolic:
- {dailyRoundListDetailsData.bp?.diastolic ?? "-"}
+ {dailyRoundListDetailsData.bp?.diastolic &&
+ dailyRoundListDetailsData.bp?.diastolic !== -1
+ ? dailyRoundListDetailsData.bp?.diastolic
+ : "-"}
diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx
index ec2f070aa20..c12aea42bee 100644
--- a/src/Components/Patient/DailyRounds.tsx
+++ b/src/Components/Patient/DailyRounds.tsx
@@ -62,6 +62,11 @@ const initForm: any = {
rhythm_detail: "",
ventilator_spo2: null,
consciousness_level: "UNKNOWN",
+ bp: {
+ systolic: -1,
+ diastolic: -1,
+ mean: -1,
+ },
// bed: null,
};
@@ -242,6 +247,18 @@ export const DailyRounds = (props: any) => {
invalidForm = true;
}
return;
+ case "bp":
+ if (
+ (state.form.bp?.systolic &&
+ state.form.bp?.diastolic &&
+ state.form.bp.systolic !== -1 &&
+ state.form.bp.diastolic === -1) ||
+ (state.form.bp.systolic === -1 && state.form.bp.diastolic !== -1)
+ ) {
+ errors.bp = "Please enter both systolic and diastolic values";
+ invalidForm = true;
+ }
+ return;
default:
return;
}
@@ -287,21 +304,32 @@ export const DailyRounds = (props: any) => {
data = {
...data,
bp:
- state.form.bp && state.form.bp.systolic && state.form.bp.diastolic
+ state.form.bp?.systolic !== -1 && state.form.bp?.diastolic !== -1
? {
- systolic: Number(state.form.bp.systolic),
- diastolic: Number(state.form.bp.diastolic),
- mean: parseFloat(
- meanArterialPressure(state.form.bp).toFixed(2)
- ),
+ systolic: state.form.bp?.systolic
+ ? Number(state.form.bp?.systolic)
+ : -1,
+ diastolic: state.form.bp?.diastolic
+ ? Number(state.form.bp?.diastolic)
+ : -1,
+ mean:
+ state.form.bp?.systolic && state.form.bp?.diastolic
+ ? parseFloat(
+ meanArterialPressure(state.form.bp).toFixed(2)
+ )
+ : -1,
}
- : undefined,
- pulse: state.form.pulse,
- resp: state.form.resp,
- temperature: state.form.temperature,
+ : {
+ systolic: -1,
+ diastolic: -1,
+ mean: -1,
+ },
+ pulse: state.form.pulse ?? null,
+ resp: state.form.resp ?? null,
+ temperature: state.form.temperature ?? null,
rhythm: state.form.rhythm || 0,
rhythm_detail: state.form.rhythm_detail,
- ventilator_spo2: state.form.ventilator_spo2,
+ ventilator_spo2: state.form.ventilator_spo2 ?? null,
consciousness_level: state.form.consciousness_level,
};
}
From f066a3659beb2ba899a226a465b06922b2207d69 Mon Sep 17 00:00:00 2001
From: Ashesh <3626859+Ashesh3@users.noreply.github.com>
Date: Sat, 30 Dec 2023 22:57:23 +0530
Subject: [PATCH 09/19] Fix conditional logic in PatientInfoCard (#6955)
---
src/Components/Patient/PatientInfoCard.tsx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx
index c5087f13dda..eb589667ece 100644
--- a/src/Components/Patient/PatientInfoCard.tsx
+++ b/src/Components/Patient/PatientInfoCard.tsx
@@ -490,6 +490,7 @@ export default function PatientInfoCard(props: {
key={i}
className="dropdown-item-primary pointer-events-auto m-2 flex cursor-pointer items-center justify-start gap-2 rounded border-0 p-2 text-sm font-normal transition-all duration-200 ease-in-out"
href={
+ action[1] !== "Treatment Summary" &&
consultation?.admitted &&
!consultation?.current_bed &&
i === 1
@@ -498,6 +499,7 @@ export default function PatientInfoCard(props: {
}
onClick={() => {
if (
+ action[1] !== "Treatment Summary" &&
consultation?.admitted &&
!consultation?.current_bed &&
i === 1
From 15fd7fe0499478c7fdd34d925d3134290cb02758 Mon Sep 17 00:00:00 2001
From: SHRAMAN PAUL <110323017+shramanpaul@users.noreply.github.com>
Date: Thu, 4 Jan 2024 08:51:56 +0530
Subject: [PATCH 10/19] added the draft feature in the doctor's notes (#6932)
* added the draft feature in the doctor's note section
* added the draft feature in the doctor's note section
* made the draft specific to consultation
* Update src/Components/Facility/PatientNotesSlideover.tsx
made it consultation specific
Co-authored-by: Rithvik Nishad
---------
Co-authored-by: Rithvik Nishad
---
src/Components/Facility/PatientNotesSlideover.tsx | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/Components/Facility/PatientNotesSlideover.tsx b/src/Components/Facility/PatientNotesSlideover.tsx
index 4279e3c1877..5ecf30cfcdf 100644
--- a/src/Components/Facility/PatientNotesSlideover.tsx
+++ b/src/Components/Facility/PatientNotesSlideover.tsx
@@ -23,7 +23,6 @@ interface PatientNotesProps {
export default function PatientNotesSlideover(props: PatientNotesProps) {
const [show, setShow] = useState(true);
const [patientActive, setPatientActive] = useState(true);
- const [noteField, setNoteField] = useState("");
const [reload, setReload] = useState(false);
const [focused, setFocused] = useState(false);
@@ -37,6 +36,11 @@ export default function PatientNotesSlideover(props: PatientNotesProps) {
const { facilityId, patientId, consultationId, setShowPatientNotesPopup } =
props;
+ const localStorageKey = `patientNotesNoteField_${consultationId}`;
+ const [noteField, setNoteField] = useState(
+ localStorage.getItem(localStorageKey) || ""
+ );
+
const onAddNote = async () => {
const payload = {
note: noteField,
@@ -127,6 +131,10 @@ export default function PatientNotesSlideover(props: PatientNotesProps) {
);
+ useEffect(() => {
+ localStorage.setItem(localStorageKey, noteField);
+ }, [noteField, localStorageKey]);
+
return (
Date: Thu, 4 Jan 2024 08:53:10 +0530
Subject: [PATCH 11/19] Remove scroll bar when header text overflows in patient
details. (#6910)
* remove scroll bar
* add key to div
---
src/Components/Patient/PatientHome.tsx | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/src/Components/Patient/PatientHome.tsx b/src/Components/Patient/PatientHome.tsx
index dc400ddc79b..22edfb16192 100644
--- a/src/Components/Patient/PatientHome.tsx
+++ b/src/Components/Patient/PatientHome.tsx
@@ -311,20 +311,18 @@ export const PatientHome = (props: any) => {
patientData.medical_history.length
) {
const medHis = patientData.medical_history;
- patientMedHis = medHis.map((item: any, idx: number) => (
-
- {item?.disease !== "NO" && (
- <>
-
- {item.disease}
-
-
- {item.details}
-
- >
- )}
-
- ));
+ patientMedHis = medHis
+ .filter((item) => item.disease !== "NO")
+ .map((item, idx) => (
+
+
+ {item.disease}
+
+
+ {item.details}
+
+
+ ));
}
let consultationList, sampleList;
From 1a0bd2c0f53f984decfcd3a0a77c451d2f92785a Mon Sep 17 00:00:00 2001
From: Pranshu Aggarwal <70687348+Pranshu1902@users.noreply.github.com>
Date: Thu, 4 Jan 2024 08:53:57 +0530
Subject: [PATCH 12/19] Show icu admission date on consultations dashboard
(#6779)
* show icu admission date
* refactor
* handle case when data isn't present
* fix padding
* update variable to encounter_date
* show admission date in banner
* fix placement
---
src/Components/Patient/PatientInfoCard.tsx | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx
index eb589667ece..68555837d6e 100644
--- a/src/Components/Patient/PatientInfoCard.tsx
+++ b/src/Components/Patient/PatientInfoCard.tsx
@@ -320,7 +320,7 @@ export default function PatientInfoCard(props: {
);
})}
- {!!consultation?.discharge_date && (
+ {consultation?.discharge_date ? (
@@ -346,6 +346,23 @@ export default function PatientInfoCard(props: {
+ ) : (
+
+
+ {consultation?.encounter_date && (
+
+ Admission on{" "}
+ {formatDateTime(consultation?.encounter_date)}
+
+ )}
+ {consultation?.icu_admission_date && (
+
+ , ICU Admission on{" "}
+ {formatDateTime(consultation?.icu_admission_date)}
+
+ )}
+
+
)}
From 1244a2ac9498da606babfedec75a759e95cf64ad Mon Sep 17 00:00:00 2001
From: Ashraf Mohammed <98876115+AshrafMd-1@users.noreply.github.com>
Date: Thu, 4 Jan 2024 15:00:20 +0530
Subject: [PATCH 13/19] correct checkbox activity (#6946)
---
src/Components/Patient/PatientRegister.tsx | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/Components/Patient/PatientRegister.tsx b/src/Components/Patient/PatientRegister.tsx
index 77088ef57e7..546d35cc487 100644
--- a/src/Components/Patient/PatientRegister.tsx
+++ b/src/Components/Patient/PatientRegister.tsx
@@ -544,6 +544,7 @@ export const PatientRegister = (props: PatientRegisterProps) => {
setFacilityName("");
}
}
+
fetchFacilityName();
}, [dispatchAction, facilityId]);
@@ -953,6 +954,14 @@ export const PatientRegister = (props: PatientRegisterProps) => {
} else {
values.splice(values.indexOf(id), 1);
}
+
+ if (id !== 1 && values.includes(1)) {
+ values.splice(values.indexOf(1), 1);
+ } else if (id === 1) {
+ values.length = 0;
+ values.push(1);
+ }
+
field("medical_history").onChange({
name: "medical_history",
value: values,
From d366f644bd50491a603f5c5247da2a5a8256c238 Mon Sep 17 00:00:00 2001
From: Ashesh <3626859+Ashesh3@users.noreply.github.com>
Date: Thu, 4 Jan 2024 15:00:40 +0530
Subject: [PATCH 14/19] Redesign Bed Capacity Cards (#6925)
* Redesign Bed Capacity Cards
* useQuery/Request
* Remove reverse-spin animation and keyframes from tailwind.config.js
* Refactor BedTypeCard component to remove unnecessary code
---
cypress/e2e/facility_spec/locations.cy.ts | 1 -
src/Components/ExternalResult/models.ts | 3 +
src/Components/Facility/BedCapacity.tsx | 125 +++++-----
src/Components/Facility/BedTypeCard.tsx | 216 +++++++-----------
.../Facility/FacilityBedCapacity.tsx | 2 +-
src/Redux/actions.tsx | 23 --
src/Redux/api.tsx | 7 +-
7 files changed, 146 insertions(+), 231 deletions(-)
diff --git a/cypress/e2e/facility_spec/locations.cy.ts b/cypress/e2e/facility_spec/locations.cy.ts
index d6377ba97c3..d39464ce14b 100644
--- a/cypress/e2e/facility_spec/locations.cy.ts
+++ b/cypress/e2e/facility_spec/locations.cy.ts
@@ -6,7 +6,6 @@ import FacilityLocation from "../../pageobject/Facility/FacilityLocation";
import { AssetPagination } from "../../pageobject/Asset/AssetPagination";
import FacilityHome from "../../pageobject/Facility/FacilityHome";
-
describe("Location Management Section", () => {
const assetPage = new AssetPage();
const userCreationPage = new UserCreationPage();
diff --git a/src/Components/ExternalResult/models.ts b/src/Components/ExternalResult/models.ts
index 8ccaba04d05..7b136c76cef 100644
--- a/src/Components/ExternalResult/models.ts
+++ b/src/Components/ExternalResult/models.ts
@@ -53,6 +53,9 @@ export interface ILocalBodies {
export interface IDeleteExternalResult {
detail: string;
}
+export interface IDeleteBedCapacity {
+ detail: string;
+}
export interface IPartialUpdateExternalResult {
address: string;
diff --git a/src/Components/Facility/BedCapacity.tsx b/src/Components/Facility/BedCapacity.tsx
index dba563e5876..9416f5981f2 100644
--- a/src/Components/Facility/BedCapacity.tsx
+++ b/src/Components/Facility/BedCapacity.tsx
@@ -1,11 +1,4 @@
-import { useCallback, useEffect, useReducer, useState } from "react";
-import { useDispatch } from "react-redux";
-import { statusType, useAbortableEffect } from "../../Common/utils";
-import {
- createCapacity,
- listCapacity,
- getCapacityBed,
-} from "../../Redux/actions";
+import { useEffect, useReducer, useState } from "react";
import * as Notification from "../../Utils/Notifications.js";
import { CapacityModal, OptionsType } from "./models";
import TextFormField from "../Form/FormFields/TextFormField";
@@ -14,6 +7,8 @@ import { SelectFormField } from "../Form/FormFields/SelectFormField";
import { FieldChangeEvent } from "../Form/FormFields/Utils";
import useConfig from "../../Common/hooks/useConfig";
import { getBedTypes } from "../../Common/constants";
+import routes from "../../Redux/api";
+import request from "../../Utils/request/request";
interface BedCapacityProps extends CapacityModal {
facilityId: string;
@@ -55,7 +50,6 @@ const bedCountReducer = (state = initialState, action: any) => {
export const BedCapacity = (props: BedCapacityProps) => {
const config = useConfig();
- const dispatchAction: any = useDispatch();
const { facilityId, handleClose, handleUpdate, className, id } = props;
const [state, dispatch] = useReducer(bedCountReducer, initialState);
const [isLastOptionType, setIsLastOptionType] = useState(false);
@@ -67,63 +61,53 @@ export const BedCapacity = (props: BedCapacityProps) => {
? `Save ${!isLastOptionType ? "& Add More" : "Bed Capacity"}`
: "Update Bed Capacity";
- const fetchData = useCallback(
- async (status: statusType) => {
- setIsLoading(true);
- if (!id) {
- // Add Form functionality
- const capacityRes = await dispatchAction(
- listCapacity({}, { facilityId })
- );
- if (!status.aborted) {
- if (capacityRes && capacityRes.data) {
- const existingData = capacityRes.data.results;
- // if all options are diabled
- if (existingData.length === getBedTypes(config).length) {
- return;
- }
- // disable existing bed types
- const updatedBedTypes = getBedTypes(config).map(
- (type: OptionsType) => {
- const isExisting = existingData.find(
- (i: CapacityModal) => i.room_type === type.id
- );
- return {
- ...type,
- disabled: !!isExisting,
- };
- }
- );
- setBedTypes(updatedBedTypes);
- }
- }
- } else {
- // Edit Form functionality
- const res = await dispatchAction(
- getCapacityBed({ facilityId: facilityId, bed_id: id })
- );
- if (res && res.data) {
- dispatch({
- type: "set_form",
- form: {
- bedType: res.data.room_type,
- totalCapacity: res.data.total_capacity,
- currentOccupancy: res.data.current_capacity,
- },
- });
+ async function fetchCapacityBed() {
+ setIsLoading(true);
+ if (!id) {
+ // Add Form functionality
+ const capacityQuery = await request(routes.getCapacity, {
+ pathParams: { facilityId: props.facilityId },
+ });
+ if (capacityQuery?.data) {
+ const existingData = capacityQuery.data?.results;
+ // if all options are diabled
+ if (existingData.length === getBedTypes(config).length) {
+ return;
}
+ // disable existing bed types
+ const updatedBedTypes = getBedTypes(config).map((type: OptionsType) => {
+ const isExisting = existingData.find(
+ (i: CapacityModal) => i.room_type === type.id
+ );
+ return {
+ ...type,
+ disabled: !!isExisting,
+ };
+ });
+ setBedTypes(updatedBedTypes);
}
- setIsLoading(false);
- },
- [dispatchAction, facilityId, id]
- );
+ } else {
+ // Edit Form functionality
+ const capacityQuery = await request(routes.getCapacityBed, {
+ pathParams: { facilityId: props.facilityId, bed_id: id.toString() },
+ });
+ if (capacityQuery.data) {
+ dispatch({
+ type: "set_form",
+ form: {
+ bedType: capacityQuery.data.room_type,
+ totalCapacity: capacityQuery.data.total_capacity,
+ currentOccupancy: capacityQuery.data.current_capacity,
+ },
+ });
+ }
+ }
+ setIsLoading(false);
+ }
- useAbortableEffect(
- (status: statusType) => {
- fetchData(status);
- },
- [dispatch, fetchData, id]
- );
+ useEffect(() => {
+ fetchCapacityBed();
+ }, []);
useEffect(() => {
const lastBedType =
@@ -179,21 +163,24 @@ export const BedCapacity = (props: BedCapacityProps) => {
const valid = validateData();
if (valid) {
setIsLoading(true);
- const data = {
+ const bodyData = {
room_type: Number(state.form.bedType),
total_capacity: Number(state.form.totalCapacity),
current_capacity: Number(state.form.currentOccupancy),
};
- const res = await dispatchAction(
- createCapacity(id, data, { facilityId })
+ const { data } = await request(
+ id ? routes.updateCapacity : routes.createCapacity,
+ {
+ pathParams: { facilityId, ...(id ? { bed_id: id.toString() } : {}) },
+ body: bodyData,
+ }
);
setIsLoading(false);
- if (res && res.data) {
- // disable last added bed type
+ if (data) {
const updatedBedTypes = bedTypes.map((type: OptionsType) => {
return {
...type,
- disabled: res.data.room_type !== type.id ? type.disabled : true,
+ disabled: data.room_type !== type.id ? type.disabled : true,
};
});
setBedTypes(updatedBedTypes);
diff --git a/src/Components/Facility/BedTypeCard.tsx b/src/Components/Facility/BedTypeCard.tsx
index 59e0661169d..67e22f31f42 100644
--- a/src/Components/Facility/BedTypeCard.tsx
+++ b/src/Components/Facility/BedTypeCard.tsx
@@ -1,8 +1,5 @@
-import { useState } from "react";
+import { useEffect, useState } from "react";
import * as Notification from "../../Utils/Notifications";
-import { animated, config, useSpring } from "@react-spring/web";
-import { useDispatch } from "react-redux";
-import { deleteCapacity } from "../../Redux/actions";
import { BedCapacity } from "./BedCapacity";
import DialogModal from "../Common/Dialog";
import ButtonV2 from "../Common/components/ButtonV2";
@@ -10,7 +7,8 @@ import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import CareIcon from "../../CAREUI/icons/CareIcon";
import RecordMeta from "../../CAREUI/display/RecordMeta";
import ConfirmDialog from "../Common/ConfirmDialog";
-import { useTranslation } from "react-i18next";
+import routes from "../../Redux/api";
+import request from "../../Utils/request/request";
interface BedTypeCardProps {
facilityId?: string;
@@ -24,9 +22,6 @@ interface BedTypeCardProps {
handleUpdate: () => void;
}
-const CIRCLE_PATH =
- "M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831";
-
export const BedTypeCard: React.FC
= ({
facilityId,
bedCapacityId,
@@ -38,20 +33,19 @@ export const BedTypeCard: React.FC = ({
removeBedType,
handleUpdate,
}) => {
- const { t } = useTranslation();
- const dispatchAction: any = useDispatch();
+ const [isRefreshing, setIsRefreshing] = useState(false);
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
const [open, setOpen] = useState(false);
const [selectedId, setSelectedId] = useState(-1);
const handleDeleteSubmit = async () => {
if (room_type) {
- const res = await dispatchAction(
- deleteCapacity({
- facilityId: facilityId,
- bed_id: room_type,
- })
- );
- if (res && res.status == 204) {
+ const { res } = await request(routes.deleteCapacityBed, {
+ pathParams: {
+ facilityId: facilityId ?? "",
+ bed_id: room_type.toString(),
+ },
+ });
+ if (res?.status == 204) {
Notification.Success({
msg: "Bed type deleted successfully",
});
@@ -63,138 +57,88 @@ export const BedTypeCard: React.FC = ({
}
};
- const _p = total ? Math.round((used / total) * 100) : 0;
+ useEffect(() => {
+ if (isRefreshing) {
+ setTimeout(() => {
+ setIsRefreshing(false);
+ }, 500);
+ }
+ }, [isRefreshing]);
- const { occupied, totalCount, progress, innerProgress } = useSpring({
- from: { occupied: 0, totalCount: 0, progress: "0, 100", innerProgress: 0 },
- to: {
- occupied: used,
- totalCount: total,
- progress: `${Number.isNaN(_p) ? 0 : _p}, 100`,
- innerProgress: Number.isNaN(_p) ? 0 : _p,
- },
- delay: 0,
- config: config.slow,
- });
+ const usedPercent = total ? Math.round((used / total) * 100) : 0;
return (
-
-
+
+
{label}
-
+
+
+ {usedPercent}%
+
+
+
+ {used} / {total}
+
+
+
-
-
-
-
-
-
-
-
- {innerProgress.to(
- (x: number) => `${Math.round(x) || 0}%`
- )}
-
-
- {
-
-
-
- }
-
-
+
+ {" "}
+ Currently Occupied / Total Capacity{" "}
+
+ {facilityId ? (
+
+
+ {lastUpdated && (
+
+ )}
-
-
-
- Used:
-
- {occupied.to((x: number) => Math.round(x))}
-
-
-
-
-
- Total:
-
- {totalCount.to((x: number) => Math.round(x))}
-
-
-
+
+ {
+ setSelectedId(room_type || 0);
+ setOpen(true);
+ }}
+ authorizeFor={NonReadOnlyUsers}
+ className="tooltip bg-opacity/20 flex aspect-square h-7 w-7 flex-col items-center justify-center rounded bg-gray-300 px-4 py-0"
+ variant="secondary"
+ ghost
+ >
+
+ Edit
+
+
+ setOpenDeleteDialog(true)}
+ authorizeFor={NonReadOnlyUsers}
+ className=" tooltip bg-opacity/10 flex aspect-square h-7 w-7 flex-col items-center justify-center rounded bg-red-100 px-4 py-0 hover:bg-red-200"
+ variant="secondary"
+ ghost
+ >
+
+ Delete
+
- {facilityId && (
-
- {lastUpdated && (
-
- )}
-
- {
- setSelectedId(room_type || 0);
- setOpen(true);
- }}
- authorizeFor={NonReadOnlyUsers}
- className="tooltip p-2"
- variant="secondary"
- ghost
- >
-
- Edit
-
- setOpenDeleteDialog(true)}
- authorizeFor={NonReadOnlyUsers}
- className="tooltip p-2"
- variant="danger"
- ghost
- >
-
- Delete
-
-
-
- )}
-
- No Data Available
-
-
+ ) : (
+
+ )}
{
return (
-
+
Bed Capacity
{
};
// Capacity/Triage/Doctor
-export const createCapacity = (
- id: number | undefined,
- params: object,
- pathParam: object
-) => {
- return id
- ? fireRequest("updateCapacity", [id], params, pathParam)
- : fireRequest("createCapacity", [], params, pathParam);
-};
export const createDoctor = (
id: number | undefined,
params: object,
@@ -206,26 +197,12 @@ export const getTriageInfo = (pathParam: object) => {
export const getTriageDetails = (pathParam: object) => {
return fireRequest("getTriageDetails", [], {}, pathParam);
};
-export const listCapacity = (params: object, pathParam: object) => {
- return fireRequest("getCapacity", [], params, pathParam);
-};
export const listDoctor = (params: object, pathParam: object) => {
return fireRequest("listDoctor", [], params, pathParam);
};
-export const getCapacity = (id: number, pathParam: object) => {
- return fireRequest("getCapacity", [id], {}, pathParam);
-};
-
-export const getCapacityBed = (pathParam: object) => {
- return fireRequest("getCapacityBed", [], {}, pathParam);
-};
-
export const getDoctor = (pathParam: object) => {
return fireRequest("getDoctor", [], {}, pathParam);
};
-export const deleteCapacity = (pathParam: object) => {
- return fireRequest("deleteCapacityBed", [], {}, pathParam);
-};
//Patient
export const searchPatient = (params: object) => {
diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx
index 2b8d4f8f51b..c511a48fcd9 100644
--- a/src/Redux/api.tsx
+++ b/src/Redux/api.tsx
@@ -51,6 +51,7 @@ import {
BedModel,
} from "../Components/Facility/models";
import {
+ IDeleteBedCapacity,
IDeleteExternalResult,
IExternalResult,
IExternalResultCsv,
@@ -529,6 +530,7 @@ const routes = {
createCapacity: {
path: "/api/v1/facility/{facilityId}/capacity/",
method: "POST",
+ TRes: Type(),
},
createDoctor: {
@@ -543,11 +545,13 @@ const routes = {
getCapacityBed: {
path: "/api/v1/facility/{facilityId}/capacity/{bed_id}/",
+ TRes: Type(),
},
deleteCapacityBed: {
path: "/api/v1/facility/{facilityId}/capacity/{bed_id}/",
method: "DELETE",
+ TRes: Type(),
},
listDoctor: {
@@ -559,8 +563,9 @@ const routes = {
},
updateCapacity: {
- path: "/api/v1/facility/{facilityId}/capacity",
+ path: "/api/v1/facility/{facilityId}/capacity/{bed_id}/",
method: "PUT",
+ TRes: Type(),
},
updateDoctor: {
From ff271f8030b1cac47035e37ec98d630f7dbd433b Mon Sep 17 00:00:00 2001
From: Pranshu Aggarwal <70687348+Pranshu1902@users.noreply.github.com>
Date: Thu, 4 Jan 2024 20:05:36 +0530
Subject: [PATCH 15/19] Hide delete facility option for users who dont have
access (#6953)
* Hide delete facility option for users who dont have access
* refactor
Co-authored-by: Rithvik Nishad
* fix lint and cypress tests
---------
Co-authored-by: Rithvik Nishad
Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com>
---
cypress/e2e/patient_spec/patient_crud.cy.ts | 2 +-
src/Components/Facility/FacilityHome.tsx | 27 ++++++++++++---------
2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/cypress/e2e/patient_spec/patient_crud.cy.ts b/cypress/e2e/patient_spec/patient_crud.cy.ts
index 06a27333b9e..66c8b35e236 100644
--- a/cypress/e2e/patient_spec/patient_crud.cy.ts
+++ b/cypress/e2e/patient_spec/patient_crud.cy.ts
@@ -8,7 +8,7 @@ import {
emergency_phone_number,
phone_number,
} from "../../pageobject/constants";
-const yearOfBirth = "2023";
+const yearOfBirth = "2001";
const calculateAge = () => {
const currentYear = new Date().getFullYear();
diff --git a/src/Components/Facility/FacilityHome.tsx b/src/Components/Facility/FacilityHome.tsx
index 2341d231675..52a7cd24027 100644
--- a/src/Components/Facility/FacilityHome.tsx
+++ b/src/Components/Facility/FacilityHome.tsx
@@ -1,6 +1,6 @@
import * as Notification from "../../Utils/Notifications.js";
-import AuthorizeFor, { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
+import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor";
import { FacilityModel } from "./models";
import { FACILITY_FEATURE_TYPES, USER_TYPES } from "../../Common/constants";
import DropdownMenu, { DropdownItem } from "../Common/components/Menu";
@@ -99,6 +99,10 @@ export const FacilityHome = (props: any) => {
USER_TYPES.findIndex((type) => type == authUser.user_type) >=
StaffUserTypeIndex;
+ const hasPermissionToDeleteFacility =
+ authUser.user_type === "DistrictAdmin" ||
+ authUser.user_type === "StateAdmin";
+
const editCoverImageTooltip = hasPermissionToEditCoverImage && (
@@ -372,16 +376,17 @@ export const FacilityHome = (props: any) => {
>
View Users
- setOpenDeleteDialog(true)}
- className="flex items-center gap-3"
- icon={}
- authorizeFor={AuthorizeFor(["DistrictAdmin", "StateAdmin"])}
- >
- Delete Facility
-
+ {hasPermissionToDeleteFacility && (
+ setOpenDeleteDialog(true)}
+ className="flex items-center gap-3"
+ icon={}
+ >
+ Delete Facility
+
+ )}
From 75e64f7b76413dd6c66077c33bd84ddc8a766ef5 Mon Sep 17 00:00:00 2001
From: Rithvik Nishad
Date: Thu, 4 Jan 2024 21:04:12 +0530
Subject: [PATCH 16/19] Central Nursing Station: Migrate to `useQuery` and
update to use `resolved_middleware` (#6967)
* Remove Legacy HL7Monitor Components
* Use `resolved_middleware` in ConsultationUpdates Tab
* CNS: Migrate to `useQuery` and use `resolved_middleware`
* remove unused redux actions
---
src/Components/CameraFeed/utils.ts | 6 +-
.../Facility/CentralNursingStation.tsx | 90 ++---
.../ConsultationUpdatesTab.tsx | 52 +--
src/Components/Facility/LegacyFacilityCNS.tsx | 313 ------------------
src/Components/Facility/LegacyMonitorCard.tsx | 47 ---
.../Patient/LegacyPatientVitalsCard.tsx | 288 ----------------
src/Components/VitalsMonitor/utils.ts | 17 +
src/Redux/actions.tsx | 9 -
src/Redux/api.tsx | 2 +
9 files changed, 61 insertions(+), 763 deletions(-)
delete mode 100644 src/Components/Facility/LegacyFacilityCNS.tsx
delete mode 100644 src/Components/Facility/LegacyMonitorCard.tsx
delete mode 100644 src/Components/Patient/LegacyPatientVitalsCard.tsx
diff --git a/src/Components/CameraFeed/utils.ts b/src/Components/CameraFeed/utils.ts
index e2793d76b41..fc940558aa0 100644
--- a/src/Components/CameraFeed/utils.ts
+++ b/src/Components/CameraFeed/utils.ts
@@ -1,5 +1,5 @@
import { MutableRefObject } from "react";
-import { AssetData } from "../Assets/AssetTypes";
+import { AssetClass, AssetData } from "../Assets/AssetTypes";
import { getCameraConfig } from "../../Utils/transformUtils";
import { isIOS } from "../../Utils/utils";
@@ -18,6 +18,10 @@ export const calculateVideoDelay = (
};
export const getStreamUrl = (asset: AssetData) => {
+ if (asset.asset_class !== AssetClass.ONVIF) {
+ throw "getStreamUrl can be invoked only for ONVIF Assets";
+ }
+
const config = getCameraConfig(asset);
const host = asset.resolved_middleware?.hostname;
const uuid = config.accessKey;
diff --git a/src/Components/Facility/CentralNursingStation.tsx b/src/Components/Facility/CentralNursingStation.tsx
index 9e8febe88fd..75214b5506c 100644
--- a/src/Components/Facility/CentralNursingStation.tsx
+++ b/src/Components/Facility/CentralNursingStation.tsx
@@ -1,13 +1,7 @@
-import { useDispatch } from "react-redux";
import useFullscreen from "../../Common/hooks/useFullscreen";
-import { Fragment, useEffect, useState } from "react";
-import {
- getPermittedFacility,
- listPatientAssetBeds,
-} from "../../Redux/actions";
+import { Fragment } from "react";
import HL7PatientVitalsMonitor from "../VitalsMonitor/HL7PatientVitalsMonitor";
import useFilters from "../../Common/hooks/useFilters";
-import { FacilityModel } from "./models";
import Loading from "../Common/Loading";
import Page from "../Common/components/Page";
import ButtonV2 from "../Common/components/ButtonV2";
@@ -15,7 +9,6 @@ import CareIcon from "../../CAREUI/icons/CareIcon";
import { classNames } from "../../Utils/utils";
import { LocationSelect } from "../Common/LocationSelect";
import Pagination from "../Common/Pagination";
-import { PatientAssetBed } from "../Assets/AssetTypes";
import { Popover, Transition } from "@headlessui/react";
import { FieldLabel } from "../Form/FormFields/FormField";
import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField";
@@ -23,6 +16,9 @@ import { useTranslation } from "react-i18next";
import { SortOption } from "../Common/SortDropdown";
import { SelectFormField } from "../Form/FormFields/SelectFormField";
import useVitalsAspectRatioConfig from "../VitalsMonitor/useVitalsAspectRatioConfig";
+import useQuery from "../../Utils/request/useQuery";
+import routes from "../../Redux/api";
+import { getVitalsMonitorSocketUrl } from "../VitalsMonitor/utils";
const PER_PAGE_LIMIT = 6;
@@ -39,72 +35,28 @@ interface Props {
export default function CentralNursingStation({ facilityId }: Props) {
const { t } = useTranslation();
- const dispatch = useDispatch();
const [isFullscreen, setFullscreen] = useFullscreen();
-
- const [facilityObject, setFacilityObject] = useState();
- const [data, setData] =
- useState[0][]>();
- const [totalCount, setTotalCount] = useState(0);
const { qParams, updateQuery, removeFilter, updatePage } = useFilters({
limit: PER_PAGE_LIMIT,
});
+ const query = useQuery(routes.listPatientAssetBeds, {
+ pathParams: { facility_external_id: facilityId },
+ query: {
+ ...qParams,
+ page: qParams.page || 1,
+ limit: PER_PAGE_LIMIT,
+ offset: (qParams.page ? qParams.page - 1 : 0) * PER_PAGE_LIMIT,
+ asset_class: "HL7MONITOR",
+ ordering: qParams.ordering || "bed__name",
+ bed_is_occupied: qParams.bed_is_occupied ?? true,
+ },
+ });
- useEffect(() => {
- async function fetchFacilityOrObject() {
- if (facilityObject) return facilityObject;
- const res = await dispatch(getPermittedFacility(facilityId));
- if (res.status !== 200) return;
- setFacilityObject(res.data);
- return res.data as FacilityModel;
- }
-
- async function fetchData() {
- setData(undefined);
-
- const filters = {
- ...qParams,
- page: qParams.page || 1,
- limit: PER_PAGE_LIMIT,
- offset: (qParams.page ? qParams.page - 1 : 0) * PER_PAGE_LIMIT,
- asset_class: "HL7MONITOR",
- ordering: qParams.ordering || "bed__name",
- bed_is_occupied: qParams.bed_is_occupied ?? true,
- };
-
- const [facilityObj, res] = await Promise.all([
- fetchFacilityOrObject(),
- dispatch(listPatientAssetBeds(facilityId, filters)),
- ]);
-
- if (!facilityObj || res.status !== 200) {
- return;
- }
-
- const entries = res.data.results as PatientAssetBed[];
-
- setTotalCount(res.data.count);
- setData(
- entries.map(({ patient, asset, bed }) => {
- const middleware = asset.resolved_middleware?.hostname;
- const local_ip_address = asset.meta?.local_ip_address;
-
- return {
- patientAssetBed: { patient, asset, bed },
- socketUrl: `wss://${middleware}/observations/${local_ip_address}`,
- };
- })
- );
- }
- fetchData();
- }, [
- dispatch,
- facilityId,
- qParams.page,
- qParams.location,
- qParams.ordering,
- qParams.bed_is_occupied,
- ]);
+ const totalCount = query.data?.count ?? 0;
+ const data = query.data?.results.map((obj) => ({
+ patientAssetBed: obj,
+ socketUrl: getVitalsMonitorSocketUrl(obj.asset),
+ }));
const { config, hash } = useVitalsAspectRatioConfig({
default: 6 / 11,
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx
index beac7f595a8..ed2d4277c54 100644
--- a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx
+++ b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx
@@ -2,8 +2,8 @@ import { lazy, useEffect, useState } from "react";
import { ConsultationTabProps } from "./index";
import { AssetBedModel, AssetClass, AssetData } from "../../Assets/AssetTypes";
import { useDispatch } from "react-redux";
-import { getPermittedFacility, listAssetBeds } from "../../../Redux/actions";
-import { BedModel, FacilityModel } from "../models";
+import { listAssetBeds } from "../../../Redux/actions";
+import { BedModel } from "../models";
import HL7PatientVitalsMonitor from "../../VitalsMonitor/HL7PatientVitalsMonitor";
import VentilatorPatientVitalsMonitor from "../../VitalsMonitor/VentilatorPatientVitalsMonitor";
import useVitalsAspectRatioConfig from "../../VitalsMonitor/useVitalsAspectRatioConfig";
@@ -13,6 +13,7 @@ import Chip from "../../../CAREUI/display/Chip";
import { formatAge, formatDate, formatDateTime } from "../../../Utils/utils";
import ReadMore from "../../Common/components/Readmore";
import DailyRoundsList from "../Consultations/DailyRoundsList";
+import { getVitalsMonitorSocketUrl } from "../../VitalsMonitor/utils";
const PageTitle = lazy(() => import("../../Common/PageTitle"));
@@ -40,32 +41,22 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => {
return;
const fetchData = async () => {
- const [facilityRes, assetBedRes] = await Promise.all([
- dispatch(getPermittedFacility(props.consultationData.facility as any)),
- dispatch(
- listAssetBeds({
- facility: props.consultationData.facility as any,
- bed: props.consultationData.current_bed?.bed_object.id,
- })
- ),
- ]);
-
- const { middleware_address } = facilityRes.data as FacilityModel;
+ const assetBedRes = await dispatch(
+ listAssetBeds({
+ facility: props.consultationData.facility as any,
+ bed: props.consultationData.current_bed?.bed_object.id,
+ })
+ );
const assetBeds = assetBedRes?.data?.results as AssetBedModel[];
const monitorBedData = assetBeds?.find(
(i) => i.asset_object?.asset_class === AssetClass.HL7MONITOR
);
+
setMonitorBedData(monitorBedData);
- const assetDataForMonitor = monitorBedData?.asset_object;
- const hl7Meta = assetDataForMonitor?.meta;
- const hl7Middleware =
- hl7Meta?.middleware_hostname ||
- assetDataForMonitor?.location_object?.middleware_address ||
- middleware_address;
- if (hl7Middleware && hl7Meta?.local_ip_address) {
+ if (monitorBedData?.asset_object) {
setHL7SocketUrl(
- `wss://${hl7Middleware}/observations/${hl7Meta.local_ip_address}`
+ getVitalsMonitorSocketUrl(monitorBedData?.asset_object)
);
}
@@ -73,6 +64,7 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => {
props.consultationData?.current_bed?.assets_objects?.find(
(i) => i.asset_class === AssetClass.VENTILATOR
);
+
let ventilatorBedData;
if (consultationBedVentilator) {
ventilatorBedData = {
@@ -84,25 +76,13 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => {
(i) => i.asset_object.asset_class === AssetClass.VENTILATOR
);
}
+
setVentilatorBedData(ventilatorBedData);
- const ventilatorMeta = ventilatorBedData?.asset_object?.meta;
- const ventilatorMiddleware =
- ventilatorMeta?.middleware_hostname ||
- consultationBedVentilator?.location_object.middleware_address ||
- middleware_address;
- if (ventilatorMiddleware && ventilatorMeta?.local_ip_address) {
+ if (ventilatorBedData?.asset_object) {
setVentilatorSocketUrl(
- `wss://${ventilatorMiddleware}/observations/${ventilatorMeta?.local_ip_address}`
+ getVitalsMonitorSocketUrl(ventilatorBedData?.asset_object)
);
}
-
- if (
- !(hl7Middleware && hl7Meta?.local_ip_address) &&
- !(ventilatorMiddleware && ventilatorMeta?.local_ip_address)
- ) {
- setHL7SocketUrl(undefined);
- setVentilatorSocketUrl(undefined);
- }
};
fetchData();
diff --git a/src/Components/Facility/LegacyFacilityCNS.tsx b/src/Components/Facility/LegacyFacilityCNS.tsx
deleted file mode 100644
index 5b0005c9daf..00000000000
--- a/src/Components/Facility/LegacyFacilityCNS.tsx
+++ /dev/null
@@ -1,313 +0,0 @@
-import { navigate } from "raviger";
-import { useEffect, useState } from "react";
-import { useDispatch } from "react-redux";
-import CareIcon from "../../CAREUI/icons/CareIcon";
-import {
- getAllPatient,
- getPermittedFacility,
- listAssetBeds,
-} from "../../Redux/actions";
-import { classNames } from "../../Utils/utils";
-import { AssetData, AssetLocationObject } from "../Assets/AssetTypes";
-import ButtonV2, { Cancel, Submit } from "../Common/components/ButtonV2";
-import Page from "../Common/components/Page";
-import Loading from "../Common/Loading";
-import Pagination from "../Common/Pagination";
-import { PatientModel } from "../Patient/models";
-import { FacilityModel } from "./models";
-import AutocompleteFormField from "../Form/FormFields/Autocomplete";
-import { uniqBy } from "lodash-es";
-import DialogModal from "../Common/Dialog";
-import { LegacyMonitorCard } from "./LegacyMonitorCard";
-
-interface Monitor {
- patient: PatientModel;
- asset: AssetData;
- socketUrl: string;
-}
-
-const PER_PAGE_LIMIT = 6;
-const CNS_REFRESH_INTERVAL = 0.5 * 60e3;
-
-export default function LegacyFacilityCNS({
- facilityId,
-}: {
- facilityId: string;
-}) {
- const dispatch = useDispatch();
- const [isFullscreen, setIsFullscreen] = useState(false);
- const [monitors, setMonitors] = useState();
- const [facility, setFacility] = useState();
- const [currentPage, setCurrentPage] = useState(1);
- const [defaultShowAllLocation, setDefaultShowAllLocation] = useState(true);
- const searchParams = new URLSearchParams(window.location.search);
-
- // this wil set ?page=1 param in url if it is not present
- useEffect(() => {
- if (!searchParams.get("page")) {
- navigate(`/facility/${facilityId}/cns?page=1`);
- }
- }, []);
- const [location, setLocation] = useState();
- const [showSelectLocation, setShowSelectLocation] = useState(false);
-
- useEffect(() => {
- const onFullscreenChange = () =>
- setIsFullscreen(!!document.fullscreenElement);
- document.addEventListener("fullscreenchange", onFullscreenChange);
- return () =>
- document.removeEventListener("fullscreenchange", onFullscreenChange);
- }, []);
-
- useEffect(() => {
- async function fetchFacility() {
- const res = await dispatch(getPermittedFacility(facilityId || ""));
- if (res.status === 200) setFacility(res.data);
- }
- fetchFacility();
- }, [facilityId, dispatch]);
-
- useEffect(() => {
- if (!facility) return;
- const middlewareHostname = facility.middleware_address;
-
- async function fetchPatients() {
- const res = await dispatch(
- getAllPatient(
- { facility: facilityId, is_active: "True" },
- "cns-patient-list"
- )
- );
- if (res.status === 200) {
- const patients = res.data.results as PatientModel[];
- return patients.filter(
- (patient) => !!patient.last_consultation?.current_bed?.bed_object.id
- );
- }
- }
-
- async function fetchPatientMonitorAsset(patient: PatientModel) {
- const res = await dispatch(
- listAssetBeds(
- {
- bed: patient.last_consultation?.current_bed?.bed_object?.id,
- },
- `asset-bed-${patient.id}`
- )
- );
-
- if (res.status !== 200) return;
-
- const asset = res.data.results.find(
- (assetBed: any) =>
- assetBed.asset_object.meta?.asset_type === "HL7MONITOR"
- )?.asset_object as AssetData | undefined;
-
- if (!asset) return;
-
- const socketUrl = `wss://${middlewareHostname}/observations/${asset.meta?.local_ip_address}`;
-
- return { patient, asset, socketUrl } as Monitor;
- }
-
- async function fetchMonitors() {
- const patients = await fetchPatients();
- if (!patients) return;
-
- const monitors = await Promise.all(
- patients.map((patient) => fetchPatientMonitorAsset(patient))
- );
- return monitors.filter((monitor) => !!monitor) as Monitor[];
- }
-
- fetchMonitors().then((monitors) => {
- setCurrentPage(Number(searchParams.get("page")));
- setMonitors(monitors);
- });
-
- const interval = setInterval(() => {
- fetchMonitors().then(setMonitors);
- }, CNS_REFRESH_INTERVAL);
-
- return () => clearInterval(interval);
- }, [dispatch, facility, facilityId]);
-
- if (!monitors) return ;
- return (
-
- {monitors?.length > 0 ? (
- <>
- setShowSelectLocation(true)}
- >
-
- Change Location
-
- {
- if (isFullscreen) {
- document.exitFullscreen();
- } else {
- document.documentElement.requestFullscreen();
- }
- }}
- className="tooltip !h-11"
- >
-
-
- {isFullscreen ? "Exit Fullscreen" : "Fullscreen"}
-
-
- >
- ) : (
- <>
- history.go(-2)}
- >
- Go Back
-
- >
- )}
-
- {
- setCurrentPage(page);
- navigate(`/facility/${facilityId}/cns?page=${page}`);
- }}
- data={{
- totalCount: defaultShowAllLocation
- ? monitors.length
- : monitors.filter(
- (m) => m.asset.location_object.id === location?.id
- ).length,
- }}
- defaultPerPage={PER_PAGE_LIMIT}
- />
-
- }
- >
- setShowSelectLocation(false)}
- className="w-full max-w-md"
- >
- {!monitors && }
-
-
setLocation(value)}
- options={
- monitors
- ? uniqBy(
- monitors.map((m) => m.asset.location_object),
- "id"
- )
- : []
- }
- isLoading={!monitors}
- optionLabel={(location) => location.name}
- optionDescription={(location) =>
- location.description +
- " (" +
- monitors.filter((m) => m.asset.location_object.id === location.id)
- .length +
- " patients)"
- }
- optionValue={(location) => location}
- disabled={!monitors}
- />
-
- {
- setDefaultShowAllLocation(true);
- setShowSelectLocation(false);
- }}
- >
- Show All Locations
-
- {
- setDefaultShowAllLocation(false);
- setShowSelectLocation(false);
- }}
- className="my-2 mr-2"
- label="Confirm"
- />
- setShowSelectLocation(false)}
- className="my-2 mr-2"
- />
-
-
-
- {monitors.length === 0 && (
-
- No patients are currently monitored
-
- )}
-
- {defaultShowAllLocation
- ? monitors
- ?.slice(
- (currentPage - 1) * PER_PAGE_LIMIT,
- currentPage * PER_PAGE_LIMIT
- )
- .map(({ patient, socketUrl, asset }) => (
-
- ))
- : monitors
- ?.filter((m) => m.asset.location_object.id === location?.id)
- ?.slice(
- (currentPage - 1) * PER_PAGE_LIMIT,
- currentPage * PER_PAGE_LIMIT
- )
- .map(({ patient, socketUrl, asset }) => (
-
- ))}
-
-
- );
-}
diff --git a/src/Components/Facility/LegacyMonitorCard.tsx b/src/Components/Facility/LegacyMonitorCard.tsx
deleted file mode 100644
index 61bff3d607b..00000000000
--- a/src/Components/Facility/LegacyMonitorCard.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { GENDER_TYPES } from "../../Common/constants";
-import { Link } from "raviger";
-import CareIcon from "../../CAREUI/icons/CareIcon";
-import { PatientModel } from "../Patient/models";
-import LegacyPatientVitalsCard from "../Patient/LegacyPatientVitalsCard";
-import { AssetLocationObject } from "../Assets/AssetTypes";
-import { formatAge } from "../../Utils/utils";
-
-interface MonitorCardProps {
- facilityId: string;
- patient: PatientModel;
- socketUrl: string;
- location: AssetLocationObject;
-}
-
-export const LegacyMonitorCard = ({
- facilityId,
- patient,
- socketUrl,
- location,
-}: MonitorCardProps) => {
- return (
-
-
-
- {patient.name}
-
-
- {formatAge(patient.age, patient.date_of_birth)} |{" "}
- {GENDER_TYPES.find((g) => g.id === patient.gender)?.icon}
-
-
-
- {patient.last_consultation?.current_bed?.bed_object?.name}
-
-
-
- {location.name}
-
-
-
-
- );
-};
diff --git a/src/Components/Patient/LegacyPatientVitalsCard.tsx b/src/Components/Patient/LegacyPatientVitalsCard.tsx
deleted file mode 100644
index 6577e4920d4..00000000000
--- a/src/Components/Patient/LegacyPatientVitalsCard.tsx
+++ /dev/null
@@ -1,288 +0,0 @@
-import { ReactNode, useEffect, useRef, useState } from "react";
-import { useDispatch } from "react-redux";
-import { listAssetBeds, getPermittedFacility } from "../../Redux/actions";
-import { classNames } from "../../Utils/utils";
-import { AssetData } from "../Assets/AssetTypes";
-import ToolTip from "../Common/utils/Tooltip";
-import { PatientModel } from "./models";
-import Waveform, { WaveformType } from "./Waveform";
-
-export interface IPatientVitalsCardProps {
- facilityId?: string;
- patient?: PatientModel;
- socketUrl?: string;
- shrinked?: boolean;
-}
-
-const getVital = (
- patientObservations: any,
- vital: string,
- fallbackValue?: any
-) => {
- if (patientObservations) {
- const vitalValues = patientObservations[vital];
- if (vitalValues) {
- const returnValue = vitalValues?.value;
-
- if (returnValue !== undefined && returnValue !== null) {
- return returnValue;
- }
- }
- }
- if (fallbackValue) {
- return fallbackValue;
- }
- return "";
-};
-
-export default function LegacyPatientVitalsCard({
- patient,
- socketUrl,
- facilityId,
- shrinked,
-}: IPatientVitalsCardProps) {
- const wsClient = useRef();
- const [waveforms, setWaveForms] = useState(null);
- const dispatch: any = useDispatch();
- const [middlewareHostname, setMiddlewareHostname] = useState("");
- const [wsUrl, setWsUrl] = useState("");
- const [patientObservations, setPatientObservations] = useState();
- const [stats, setStats] = useState(false);
-
- useEffect(() => {
- const fetchFacility = async () => {
- const res = await dispatch(getPermittedFacility(facilityId || ""));
-
- if (res.status === 200 && res.data) {
- setMiddlewareHostname(res.data.middleware_address);
- }
- };
-
- if (facilityId) fetchFacility();
- }, [dispatch, facilityId]);
-
- useEffect(() => {
- const fetchAssetData = async () => {
- let bedAssets = await dispatch(
- listAssetBeds({
- bed: patient?.last_consultation?.current_bed?.bed_object?.id,
- })
- );
- bedAssets = {
- ...bedAssets,
- data: {
- ...bedAssets.data,
- results: bedAssets.data.results.filter((assetBed: any) =>
- assetBed.asset_object.meta?.asset_type === "HL7MONITOR"
- ? true
- : false
- ),
- },
- };
-
- if (bedAssets.data.results.length > 0) {
- const asset: AssetData = bedAssets.data.results[0].asset_object;
- if (asset?.meta?.local_ip_address) {
- setWsUrl(
- `wss://${middlewareHostname}/observations/${asset?.meta?.local_ip_address}`
- );
- }
- }
- };
-
- if (patient?.last_consultation?.current_bed?.bed_object?.id)
- fetchAssetData();
- }, [
- dispatch,
- middlewareHostname,
- patient?.last_consultation?.current_bed?.bed_object?.id,
- ]);
-
- const connectWs = (url: string) => {
- wsClient.current = new WebSocket(url);
- wsClient.current.addEventListener("message", (e) => {
- const newObservations = JSON.parse(e.data || "{}");
- if (newObservations.length > 0) {
- setWaveForms(
- newObservations.filter((o: any) => o.observation_id === "waveform")
- );
- const newObservationsMap = newObservations.reduce(
- (acc: any, curr: { observation_id: any }) => ({
- ...acc,
- [curr.observation_id]: curr,
- }),
- {}
- );
- setPatientObservations(newObservationsMap);
- }
- });
- };
-
- useEffect(() => {
- if (socketUrl || wsUrl) connectWs(socketUrl || wsUrl);
-
- return () => {
- wsClient.current?.close();
- };
- }, [wsUrl, socketUrl]);
-
- useEffect(() => {
- return () => {
- wsClient.current?.close();
- setWaveForms(null);
- };
- }, [socketUrl, patient]);
-
- type VitalType = {
- label: ReactNode;
- liveKey: string;
- vitalKey: string;
- waveformKey?: string;
- waveformColor?: string;
- waveformName?: string;
- waveformDefaultSpace?: boolean;
- wavetype?: "STREAM" | "REFRESH";
- };
-
- const vitals: VitalType[] = [
- {
- label: shrinked ? "Pulse" : "Pulse Rate",
- liveKey: "pulse-rate",
- vitalKey: "pulse",
- waveformKey: "II",
- waveformColor: "limegreen",
- waveformName: "ECG",
- wavetype: "REFRESH",
- },
- {
- label: shrinked ? "BP" : "Blood Pressure",
- liveKey: "bp",
- vitalKey: "bp",
- },
- {
- label: (
- <>
- SpO2
- >
- ),
- liveKey: "SpO2",
- vitalKey: "ventilator_spo2",
- waveformKey: "Pleth",
- waveformColor: "yellow",
- },
- {
- label: <>R. Rate>,
- liveKey: "respiratory-rate",
- vitalKey: "resp",
- waveformKey: "Respiration",
- waveformColor: "cyan",
- //waveformDefaultSpace: true
- },
- {
- label: shrinked ? "Temp. (°F)" : "Temperature (°F)",
- liveKey: "body-temperature1",
- vitalKey: "temperature",
- },
- ];
-
- return (
-
-
-
- {waveforms ? (
- <>
- {vitals.map((v, i) => {
- const waveform: any = waveforms.filter(
- (w) => w["wave-name"] === v.waveformKey
- )[0];
- return v.waveformKey && waveform ? (
-
w["wave-name"] === v.waveformKey)
- .map((w) => w.data)
- .join(" "),
- }}
- title={v.waveformName || v.waveformKey}
- color={v.waveformColor}
- metrics={stats}
- classes={"h-[150px]"}
- defaultSpace={v.waveformDefaultSpace}
- wavetype={v.wavetype || "STREAM"}
- />
- ) : (
-
- );
- })}
-
-
-
-
-
- >
- ) : (
-
-
-
-
No Live data at the moment!
-
-
- )}
-
-
- {vitals.map((vital, i) => {
- const liveReading = getVital(patientObservations, vital.liveKey);
- return (
-
-
- {liveReading ||
- (vital.vitalKey === "bp"
- ? `${
- patient?.last_consultation?.last_daily_round?.bp
- .systolic || "--"
- }/${
- patient?.last_consultation?.last_daily_round?.bp
- .diastolic || "--"
- }`
- : patient?.last_consultation?.last_daily_round?.[
- vital.vitalKey || ""
- ]) ||
- "--"}
-
-
-
- );
- })}
-
-
-
- );
-}
diff --git a/src/Components/VitalsMonitor/utils.ts b/src/Components/VitalsMonitor/utils.ts
index 2e38f83b65b..21ba769dc83 100644
--- a/src/Components/VitalsMonitor/utils.ts
+++ b/src/Components/VitalsMonitor/utils.ts
@@ -1,3 +1,4 @@
+import { AssetClass, AssetData } from "../Assets/AssetTypes";
import { ChannelOptions, VitalsWaveformBase } from "./types";
/**
@@ -73,3 +74,19 @@ export const getVitalsCanvasSizeAndDuration = (
duration: DEFAULT_DURATION * (ratio / DEFAULT_RATIO),
};
};
+
+export const getVitalsMonitorSocketUrl = (asset: AssetData) => {
+ if (
+ asset.asset_class !== AssetClass.HL7MONITOR &&
+ asset.asset_class !== AssetClass.VENTILATOR
+ ) {
+ throw "getVitalsMonitorSocketUrl can be invoked only for HL7MONITOR or VENTILATOR assets";
+ }
+
+ const middleware = asset.resolved_middleware?.hostname;
+ const ipAddress = asset.meta?.local_ip_address;
+
+ if (middleware && ipAddress) {
+ return `wss://${middleware}/observations/${ipAddress}`;
+ }
+};
diff --git a/src/Redux/actions.tsx b/src/Redux/actions.tsx
index 2b301b09e38..9d9ab59795b 100644
--- a/src/Redux/actions.tsx
+++ b/src/Redux/actions.tsx
@@ -28,10 +28,6 @@ export const getAllSkills = (params: object) => {
return fireRequest("getAllSkills", [], params);
};
-export const getPermittedFacility = (id: number | string, key?: string) => {
- return fireRequest("getPermittedFacility", [], {}, { id: id }, key);
-};
-
export const getAnyFacility = (id: number | string, key?: string) => {
return fireRequest("getAnyFacility", [], {}, { id: id }, key);
};
@@ -109,11 +105,6 @@ export const deleteAssetBed = (asset_id: string) =>
}
);
-export const listPatientAssetBeds = (
- facility_external_id: string,
- params: object
-) => fireRequest("listPatientAssetBeds", [], params, { facility_external_id });
-
// Facility Beds
export const listFacilityBeds = (params: object) =>
fireRequest("listFacilityBeds", [], params, {});
diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx
index c511a48fcd9..8f8fc76484d 100644
--- a/src/Redux/api.tsx
+++ b/src/Redux/api.tsx
@@ -27,6 +27,7 @@ import {
AssetServiceUpdate,
AssetTransaction,
AssetUpdate,
+ PatientAssetBed,
} from "../Components/Assets/AssetTypes";
import {
CapacityModal,
@@ -395,6 +396,7 @@ const routes = {
listPatientAssetBeds: {
path: "/api/v1/facility/{facility_external_id}/patient_asset_beds/",
method: "GET",
+ TRes: Type>(),
},
// Facility Beds
From 9f1b29c1a8b7dd2614f0fc41d8c5f4a3f52e45d8 Mon Sep 17 00:00:00 2001
From: Ashesh <3626859+Ashesh3@users.noreply.github.com>
Date: Thu, 4 Jan 2024 21:25:58 +0530
Subject: [PATCH 17/19] Refactor DailyRoundsList component and
DefaultLogUpdateCard component (#6973)
---
.../Facility/ConsultationDetails/ConsultationUpdatesTab.tsx | 2 +-
.../Consultations/DailyRounds/DefaultLogUpdateCard.tsx | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx
index ed2d4277c54..5e5b574dd07 100644
--- a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx
+++ b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx
@@ -652,7 +652,7 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => {
-
diff --git a/src/Components/Facility/Consultations/DailyRounds/DefaultLogUpdateCard.tsx b/src/Components/Facility/Consultations/DailyRounds/DefaultLogUpdateCard.tsx
index 4cb90c900b1..34518afcb9b 100644
--- a/src/Components/Facility/Consultations/DailyRounds/DefaultLogUpdateCard.tsx
+++ b/src/Components/Facility/Consultations/DailyRounds/DefaultLogUpdateCard.tsx
@@ -32,12 +32,13 @@ const DefaultLogUpdateCard = ({ round, ...props }: Props) => {
attributeKey="other_details"
attributeValue={round.other_details}
/>
-
+
@@ -48,6 +49,7 @@ const DefaultLogUpdateCard = ({ round, ...props }: Props) => {
border
ghost
size="small"
+ className="w-full"
onClick={props.onUpdateLog}
>
From fedb2e20698731f10cf69d5750f3763b416def32 Mon Sep 17 00:00:00 2001
From: Rithvik Nishad
Date: Sat, 6 Jan 2024 19:22:30 +0530
Subject: [PATCH 18/19] Fix blood pressure being negative values when field is
cleared (#6986)
* Fix negative values from being internally recorded in blood pressure
* make validator name more verbose and readable
* remove console logs
---
.../Common/BloodPressureFormField.tsx | 47 ++++++++++++-------
.../Facility/Consultations/Mews.tsx | 2 -
.../Patient/DailyRoundListDetails.tsx | 10 +---
src/Components/Patient/DailyRounds.tsx | 44 ++++-------------
src/Components/Patient/models.tsx | 10 ++--
5 files changed, 46 insertions(+), 67 deletions(-)
diff --git a/src/Components/Common/BloodPressureFormField.tsx b/src/Components/Common/BloodPressureFormField.tsx
index 3ff2774b900..e64b2a15ff6 100644
--- a/src/Components/Common/BloodPressureFormField.tsx
+++ b/src/Components/Common/BloodPressureFormField.tsx
@@ -1,3 +1,4 @@
+import { FieldValidator } from "../Form/FieldValidators";
import FormField from "../Form/FormFields/FormField";
import RangeAutocompleteFormField from "../Form/FormFields/RangeAutocompleteFormField";
import {
@@ -5,40 +6,36 @@ import {
FormFieldBaseProps,
useFormFieldPropsResolver,
} from "../Form/FormFields/Utils";
+import { DailyRoundsModel } from "../Patient/models";
-export interface BloodPressure {
- systolic: number;
- diastolic: number;
-}
+type BloodPressure = NonNullable;
-type Props = FormFieldBaseProps>;
+type Props = FormFieldBaseProps;
export default function BloodPressureFormField(props: Props) {
const field = useFormFieldPropsResolver(props as any);
const handleChange = (event: FieldChangeEvent) => {
- field.onChange({
- name: field.name,
- value: {
- ...field.value,
- [event.name]: event.value ?? -1,
- },
- });
+ const value: BloodPressure = {
+ ...field.value,
+ [event.name]: event.value,
+ };
+ value.mean = meanArterialPressure(value);
+ field.onChange({ name: field.name, value });
};
const map =
!!props.value?.diastolic &&
!!props.value.systolic &&
- meanArterialPressure(props.value as BloodPressure);
+ meanArterialPressure(props.value);
return (
MAP: {map.toFixed(1)}
- ) : undefined,
+ labelSuffix: map ? (
+ MAP: {map.toFixed(1)}
+ ) : undefined,
}}
>
@@ -108,5 +105,19 @@ export const meanArterialPressure = ({
diastolic,
systolic,
}: BloodPressure) => {
- return (2 * diastolic + systolic) / 3;
+ if (diastolic != null && systolic != null) {
+ return (2 * diastolic + systolic) / 3;
+ }
+};
+
+export const BloodPressureValidator: FieldValidator = (bp) => {
+ if (Object.values(bp).every((v) => v == null)) {
+ return;
+ }
+ if (bp.diastolic == null) {
+ return "Diastolic is missing. Either specify both or clear both.";
+ }
+ if (bp.systolic == null) {
+ return "Systolic is missing. Either specify both or clear both.";
+ }
};
diff --git a/src/Components/Facility/Consultations/Mews.tsx b/src/Components/Facility/Consultations/Mews.tsx
index 5160e42f9f2..14e7d7f9e63 100644
--- a/src/Components/Facility/Consultations/Mews.tsx
+++ b/src/Components/Facility/Consultations/Mews.tsx
@@ -26,7 +26,6 @@ const getHeartRateScore = (value?: number) => {
const getSystolicBPScore = (value?: number) => {
if (typeof value !== "number") return;
- if (value === -1) return;
if (value <= 70) return 3;
if (value <= 80) return 2;
@@ -38,7 +37,6 @@ const getSystolicBPScore = (value?: number) => {
};
const getTempRange = (value?: number) => {
- console.log(value);
if (typeof value !== "number") return;
if (value < 95) return 2;
diff --git a/src/Components/Patient/DailyRoundListDetails.tsx b/src/Components/Patient/DailyRoundListDetails.tsx
index 0a73607d688..8f313c0a51d 100644
--- a/src/Components/Patient/DailyRoundListDetails.tsx
+++ b/src/Components/Patient/DailyRoundListDetails.tsx
@@ -158,20 +158,14 @@ export const DailyRoundListDetails = (props: any) => {
Systolic:{" "}
- {dailyRoundListDetailsData.bp?.systolic &&
- dailyRoundListDetailsData.bp?.systolic !== -1
- ? dailyRoundListDetailsData.bp?.systolic
- : "-"}
+ {dailyRoundListDetailsData.bp?.systolic ?? "-"}
{" "}
Diastolic:
- {dailyRoundListDetailsData.bp?.diastolic &&
- dailyRoundListDetailsData.bp?.diastolic !== -1
- ? dailyRoundListDetailsData.bp?.diastolic
- : "-"}
+ {dailyRoundListDetailsData.bp?.diastolic ?? "-"}
diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx
index c12aea42bee..56e26dff022 100644
--- a/src/Components/Patient/DailyRounds.tsx
+++ b/src/Components/Patient/DailyRounds.tsx
@@ -23,7 +23,7 @@ import { DraftSection, useAutoSaveReducer } from "../../Utils/AutoSave";
import * as Notification from "../../Utils/Notifications";
import { formatDateTime } from "../../Utils/utils";
import BloodPressureFormField, {
- meanArterialPressure,
+ BloodPressureValidator,
} from "../Common/BloodPressureFormField";
import { SymptomsSelect } from "../Common/SymptomsSelect";
import TemperatureFormField from "../Common/TemperatureFormField";
@@ -63,9 +63,9 @@ const initForm: any = {
ventilator_spo2: null,
consciousness_level: "UNKNOWN",
bp: {
- systolic: -1,
- diastolic: -1,
- mean: -1,
+ systolic: undefined,
+ diastolic: undefined,
+ mean: undefined,
},
// bed: null,
};
@@ -247,18 +247,14 @@ export const DailyRounds = (props: any) => {
invalidForm = true;
}
return;
- case "bp":
- if (
- (state.form.bp?.systolic &&
- state.form.bp?.diastolic &&
- state.form.bp.systolic !== -1 &&
- state.form.bp.diastolic === -1) ||
- (state.form.bp.systolic === -1 && state.form.bp.diastolic !== -1)
- ) {
- errors.bp = "Please enter both systolic and diastolic values";
+ case "bp": {
+ const error = BloodPressureValidator(state.form.bp);
+ if (error) {
+ errors.bp = error;
invalidForm = true;
}
return;
+ }
default:
return;
}
@@ -303,27 +299,7 @@ export const DailyRounds = (props: any) => {
if (["NORMAL", "TELEMEDICINE"].includes(state.form.rounds_type)) {
data = {
...data,
- bp:
- state.form.bp?.systolic !== -1 && state.form.bp?.diastolic !== -1
- ? {
- systolic: state.form.bp?.systolic
- ? Number(state.form.bp?.systolic)
- : -1,
- diastolic: state.form.bp?.diastolic
- ? Number(state.form.bp?.diastolic)
- : -1,
- mean:
- state.form.bp?.systolic && state.form.bp?.diastolic
- ? parseFloat(
- meanArterialPressure(state.form.bp).toFixed(2)
- )
- : -1,
- }
- : {
- systolic: -1,
- diastolic: -1,
- mean: -1,
- },
+ bp: state.form.bp ?? {},
pulse: state.form.pulse ?? null,
resp: state.form.resp ?? null,
temperature: state.form.temperature ?? null,
diff --git a/src/Components/Patient/models.tsx b/src/Components/Patient/models.tsx
index e1ce5d53050..fc87bedcb14 100644
--- a/src/Components/Patient/models.tsx
+++ b/src/Components/Patient/models.tsx
@@ -282,9 +282,9 @@ export interface DailyRoundsModel {
rhythm?: string;
rhythm_detail?: string;
bp?: {
- diastolic: number;
- mean: number;
- systolic: number;
+ diastolic?: number;
+ mean?: number;
+ systolic?: number;
};
pulse?: number;
resp?: number;
@@ -297,7 +297,7 @@ export interface DailyRoundsModel {
medication_given?: Array;
additional_symptoms_text?: string;
current_health?: string;
- id: string;
+ id?: string;
other_symptoms?: string;
admitted_to?: string;
patient_category?: PatientCategory;
@@ -314,7 +314,7 @@ export interface DailyRoundsModel {
| "AGITATED_OR_CONFUSED"
| "ONSET_OF_AGITATION_AND_CONFUSION"
| "UNKNOWN";
- rounds_type: (typeof DailyRoundTypes)[number];
+ rounds_type?: (typeof DailyRoundTypes)[number];
last_updated_by_telemedicine?: boolean;
created_by_telemedicine?: boolean;
created_by?: {
From 7f6cc0c016809768aef236d03429c7021bef46de Mon Sep 17 00:00:00 2001
From: Rithvik Nishad
Date: Sat, 6 Jan 2024 20:25:12 +0530
Subject: [PATCH 19/19] hacks/treat-negative-bp-as-undefined (#6987)
---
.../Consultations/PrimaryParametersPlot.tsx | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/Components/Facility/Consultations/PrimaryParametersPlot.tsx b/src/Components/Facility/Consultations/PrimaryParametersPlot.tsx
index 4ff81acf868..ecd3a7d2648 100644
--- a/src/Components/Facility/Consultations/PrimaryParametersPlot.tsx
+++ b/src/Components/Facility/Consultations/PrimaryParametersPlot.tsx
@@ -17,6 +17,17 @@ interface PrimaryParametersPlotProps {
consultationId: string;
}
+const sanitizeBPAttribute = (value: number | undefined) => {
+ // Temp. hack until the cleaning of daily rounds as a db migration is done.
+ // TODO: remove once migration is merged.
+
+ if (value == null || value < 0) {
+ return;
+ }
+
+ return value;
+};
+
export const PrimaryParametersPlot = ({
consultationId,
}: PrimaryParametersPlotProps) => {
@@ -77,19 +88,19 @@ export const PrimaryParametersPlot = ({
{
name: "diastolic",
data: Object.values(results)
- .map((p: any) => p.bp && p.bp.diastolic)
+ .map((p: any) => p.bp && sanitizeBPAttribute(p.bp.diastolic))
.reverse(),
},
{
name: "systolic",
data: Object.values(results)
- .map((p: any) => p.bp && p.bp.systolic)
+ .map((p: any) => p.bp && sanitizeBPAttribute(p.bp.systolic))
.reverse(),
},
{
name: "mean",
data: Object.values(results)
- .map((p: any) => p.bp && p.bp.mean)
+ .map((p: any) => p.bp && sanitizeBPAttribute(p.bp.mean))
.reverse(),
},
];