diff --git a/cypress/e2e/assets_spec/AssetHomepage.cy.ts b/cypress/e2e/assets_spec/AssetHomepage.cy.ts index bda4abdfae3..906cd9b2edc 100644 --- a/cypress/e2e/assets_spec/AssetHomepage.cy.ts +++ b/cypress/e2e/assets_spec/AssetHomepage.cy.ts @@ -1,10 +1,11 @@ -import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; -import { AssetQRScanPage } from "../../pageobject/Asset/AssetQRScan"; -import { AssetPagination } from "../../pageobject/Asset/AssetPagination"; -import { AssetFilters } from "../../pageobject/Asset/AssetFilters"; +import { v4 as uuidv4 } from "uuid"; + import { AssetPage } from "../../pageobject/Asset/AssetCreation"; +import { AssetFilters } from "../../pageobject/Asset/AssetFilters"; +import { AssetPagination } from "../../pageobject/Asset/AssetPagination"; +import { AssetQRScanPage } from "../../pageobject/Asset/AssetQRScan"; +import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; import LoginPage from "../../pageobject/Login/LoginPage"; -import { v4 as uuidv4 } from "uuid"; describe("Asset Tab", () => { const assetSearchPage = new AssetSearchPage(); diff --git a/cypress/e2e/assets_spec/AssetsCreation.cy.ts b/cypress/e2e/assets_spec/AssetsCreation.cy.ts index 16a4fd050fb..61c6fe9b517 100644 --- a/cypress/e2e/assets_spec/AssetsCreation.cy.ts +++ b/cypress/e2e/assets_spec/AssetsCreation.cy.ts @@ -1,7 +1,8 @@ -import { AssetPage } from "../../pageobject/Asset/AssetCreation"; import { v4 as uuidv4 } from "uuid"; -import LoginPage from "../../pageobject/Login/LoginPage"; + +import { AssetPage } from "../../pageobject/Asset/AssetCreation"; import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; +import LoginPage from "../../pageobject/Login/LoginPage"; describe("Asset", () => { const assetPage = new AssetPage(); diff --git a/cypress/e2e/assets_spec/AssetsManage.cy.ts b/cypress/e2e/assets_spec/AssetsManage.cy.ts index 756d3b261a6..17ee99bdb62 100644 --- a/cypress/e2e/assets_spec/AssetsManage.cy.ts +++ b/cypress/e2e/assets_spec/AssetsManage.cy.ts @@ -1,8 +1,8 @@ import { AssetPage } from "../../pageobject/Asset/AssetCreation"; -import LoginPage from "../../pageobject/Login/LoginPage"; +import { AssetFilters } from "../../pageobject/Asset/AssetFilters"; import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; -import { AssetFilters } from "../../pageobject/Asset/AssetFilters"; +import LoginPage from "../../pageobject/Login/LoginPage"; function addDaysToDate(numberOfDays: number) { const inputDate = new Date(); diff --git a/cypress/e2e/facility_spec/FacilityCreation.cy.ts b/cypress/e2e/facility_spec/FacilityCreation.cy.ts index 4961ae4a4cb..fff1311fdd6 100644 --- a/cypress/e2e/facility_spec/FacilityCreation.cy.ts +++ b/cypress/e2e/facility_spec/FacilityCreation.cy.ts @@ -1,6 +1,6 @@ import FacilityPage from "../../pageobject/Facility/FacilityCreation"; -import LoginPage from "../../pageobject/Login/LoginPage"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; +import LoginPage from "../../pageobject/Login/LoginPage"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; import { UserCreationPage } from "../../pageobject/Users/UserCreation"; diff --git a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts index e6caf645f7a..bc84aea4882 100644 --- a/cypress/e2e/facility_spec/FacilityHomepage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityHomepage.cy.ts @@ -1,11 +1,10 @@ // FacilityCreation - -import LoginPage from "../../pageobject/Login/LoginPage"; +import { AssetPagination } from "../../pageobject/Asset/AssetPagination"; +import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; +import LoginPage from "../../pageobject/Login/LoginPage"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; -import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import { UserPage } from "../../pageobject/Users/UserSearch"; -import { AssetPagination } from "../../pageobject/Asset/AssetPagination"; describe("Facility Homepage Function", () => { const loginPage = new LoginPage(); diff --git a/cypress/e2e/facility_spec/FacilityInventory.cy.ts b/cypress/e2e/facility_spec/FacilityInventory.cy.ts index cdada75ee06..a9f32984efc 100644 --- a/cypress/e2e/facility_spec/FacilityInventory.cy.ts +++ b/cypress/e2e/facility_spec/FacilityInventory.cy.ts @@ -1,6 +1,6 @@ import FacilityPage from "../../pageobject/Facility/FacilityCreation"; -import LoginPage from "../../pageobject/Login/LoginPage"; import FacilityHome from "../../pageobject/Facility/FacilityHome"; +import LoginPage from "../../pageobject/Login/LoginPage"; describe("Inventory Management Section", () => { const facilityPage = new FacilityPage(); diff --git a/cypress/e2e/facility_spec/FacilityManage.cy.ts b/cypress/e2e/facility_spec/FacilityManage.cy.ts index 1f0d2b66108..10074e81166 100644 --- a/cypress/e2e/facility_spec/FacilityManage.cy.ts +++ b/cypress/e2e/facility_spec/FacilityManage.cy.ts @@ -1,8 +1,9 @@ -import LoginPage from "../../pageobject/Login/LoginPage"; -import FacilityManage from "../../pageobject/Facility/FacilityManage"; -import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import { v4 as uuidv4 } from "uuid"; +import FacilityPage from "../../pageobject/Facility/FacilityCreation"; +import FacilityManage from "../../pageobject/Facility/FacilityManage"; +import LoginPage from "../../pageobject/Login/LoginPage"; + describe("Facility Manage Functions", () => { const loginPage = new LoginPage(); const facilityManage = new FacilityManage(); diff --git a/cypress/e2e/patient_spec/PatientBedManagement.cy.ts b/cypress/e2e/patient_spec/PatientBedManagement.cy.ts index 84ef2f4800e..65adf131c87 100644 --- a/cypress/e2e/patient_spec/PatientBedManagement.cy.ts +++ b/cypress/e2e/patient_spec/PatientBedManagement.cy.ts @@ -1,7 +1,7 @@ import LoginPage from "../../pageobject/Login/LoginPage"; +import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import PatientLogupdate from "../../pageobject/Patient/PatientLogupdate"; -import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; describe("Patient swtich bed functionality", () => { const loginPage = new LoginPage(); diff --git a/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts b/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts index ee38b24d746..4c84f7fad8f 100644 --- a/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts +++ b/cypress/e2e/patient_spec/PatientConsultationCreation.cy.ts @@ -1,12 +1,12 @@ import LoginPage from "../../pageobject/Login/LoginPage"; -import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; -import PatientPredefined from "../../pageobject/Patient/PatientPredefined"; -import ShiftCreation from "../../pageobject/Shift/ShiftCreation"; -import PatientInvestigation from "../../pageobject/Patient/PatientInvestigation"; -import PatientTreatmentPlan from "../../pageobject/Patient/PatientTreatmentPlan"; +import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import PatientDeathReport from "../../pageobject/Patient/PatientDeathReport"; +import PatientInvestigation from "../../pageobject/Patient/PatientInvestigation"; +import PatientPredefined from "../../pageobject/Patient/PatientPredefined"; import PatientPrescription from "../../pageobject/Patient/PatientPrescription"; +import PatientTreatmentPlan from "../../pageobject/Patient/PatientTreatmentPlan"; +import ShiftCreation from "../../pageobject/Shift/ShiftCreation"; describe("Patient Consultation in multiple combination", () => { const patientConsultationPage = new PatientConsultationPage(); diff --git a/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts b/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts index 9197cac2d90..dd626f619ce 100644 --- a/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts +++ b/cypress/e2e/patient_spec/PatientDoctorConnect.cy.ts @@ -1,4 +1,5 @@ import { DoctorConnect } from "pageobject/Patient/PatientDoctorConnect"; + import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; diff --git a/cypress/e2e/patient_spec/PatientFileUpload.ts b/cypress/e2e/patient_spec/PatientFileUpload.ts index cc94943fd6f..110631551a1 100644 --- a/cypress/e2e/patient_spec/PatientFileUpload.ts +++ b/cypress/e2e/patient_spec/PatientFileUpload.ts @@ -1,6 +1,7 @@ import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import { PatientFileUpload } from "../../pageobject/Patient/PatientFileupload"; + const loginPage = new LoginPage(); const patientPage = new PatientPage(); const patientFileUpload = new PatientFileUpload(); diff --git a/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts b/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts index b32990872e2..b6d7ecbc173 100644 --- a/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts +++ b/cypress/e2e/patient_spec/PatientLogUpdate.cy.ts @@ -1,8 +1,8 @@ import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; -import PatientLogupdate from "../../pageobject/Patient/PatientLogupdate"; import PatientInvestigation from "../../pageobject/Patient/PatientInvestigation"; +import PatientLogupdate from "../../pageobject/Patient/PatientLogupdate"; import PatientPrescription from "../../pageobject/Patient/PatientPrescription"; describe("Patient Log Update in Normal, Critical and TeleIcu", () => { diff --git a/cypress/e2e/patient_spec/PatientPrescription.cy.ts b/cypress/e2e/patient_spec/PatientPrescription.cy.ts index f5febc85fdc..53e67324199 100644 --- a/cypress/e2e/patient_spec/PatientPrescription.cy.ts +++ b/cypress/e2e/patient_spec/PatientPrescription.cy.ts @@ -1,6 +1,6 @@ -import PatientPrescription from "../../pageobject/Patient/PatientPrescription"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; +import PatientPrescription from "../../pageobject/Patient/PatientPrescription"; const patientPrescription = new PatientPrescription(); const loginPage = new LoginPage(); diff --git a/cypress/e2e/patient_spec/PatientRegistration.cy.ts b/cypress/e2e/patient_spec/PatientRegistration.cy.ts index d774a90ceb8..cb84fa06674 100644 --- a/cypress/e2e/patient_spec/PatientRegistration.cy.ts +++ b/cypress/e2e/patient_spec/PatientRegistration.cy.ts @@ -1,10 +1,10 @@ +import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; -import FacilityPage from "../../pageobject/Facility/FacilityCreation"; -import { generatePhoneNumber } from "../../pageobject/utils/constants"; -import PatientTransfer from "../../pageobject/Patient/PatientTransfer"; import PatientInsurance from "../../pageobject/Patient/PatientInsurance"; import PatientMedicalHistory from "../../pageobject/Patient/PatientMedicalHistory"; +import PatientTransfer from "../../pageobject/Patient/PatientTransfer"; +import { generatePhoneNumber } from "../../pageobject/utils/constants"; const yearOfBirth = "2001"; const isHCXEnabled = Cypress.env("ENABLE_HCX"); diff --git a/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts b/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts index 8dc526a68c3..299d753d720 100644 --- a/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts +++ b/cypress/e2e/resource_spec/ResourcesHomepage.cy.ts @@ -1,6 +1,6 @@ +import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import LoginPage from "../../pageobject/Login/LoginPage"; import ResourcePage from "../../pageobject/Resource/ResourcePage"; -import FacilityPage from "../../pageobject/Facility/FacilityCreation"; describe("Resource Page", () => { let createdResource: string; diff --git a/cypress/e2e/users_spec/UsersCreation.cy.ts b/cypress/e2e/users_spec/UsersCreation.cy.ts index 683a2131b2f..f495a136d97 100644 --- a/cypress/e2e/users_spec/UsersCreation.cy.ts +++ b/cypress/e2e/users_spec/UsersCreation.cy.ts @@ -1,11 +1,11 @@ -import LoginPage from "../../pageobject/Login/LoginPage"; import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; -import { UserPage } from "../../pageobject/Users/UserSearch"; +import LoginPage from "../../pageobject/Login/LoginPage"; import { UserCreationPage } from "../../pageobject/Users/UserCreation"; +import { UserPage } from "../../pageobject/Users/UserSearch"; import { - generatePhoneNumber, generateEmergencyPhoneNumber, + generatePhoneNumber, } from "../../pageobject/utils/constants"; describe("User Creation", () => { diff --git a/cypress/e2e/users_spec/UsersManage.cy.ts b/cypress/e2e/users_spec/UsersManage.cy.ts index 98c2d564f6d..9ed4fe34ec7 100644 --- a/cypress/e2e/users_spec/UsersManage.cy.ts +++ b/cypress/e2e/users_spec/UsersManage.cy.ts @@ -1,7 +1,7 @@ import LoginPage from "../../pageobject/Login/LoginPage"; -import { UserPage } from "../../pageobject/Users/UserSearch"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; import { UserCreationPage } from "../../pageobject/Users/UserCreation"; +import { UserPage } from "../../pageobject/Users/UserSearch"; describe("Manage User", () => { const loginPage = new LoginPage(); diff --git a/public/locale/en.json b/public/locale/en.json index b6ccb84de08..ef591130213 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -133,9 +133,13 @@ "ORAL_ISSUE__NO_ISSUE": "No issues", "ORAL_ISSUE__ODYNOPHAGIA": "Odynophagia", "OXYGEN_MODALITY__HIGH_FLOW_NASAL_CANNULA": "High Flow Nasal Cannula", + "OXYGEN_MODALITY__HIGH_FLOW_NASAL_CANNULA_short": "HFNC", "OXYGEN_MODALITY__NASAL_PRONGS": "Nasal Prongs", + "OXYGEN_MODALITY__NASAL_PRONGS_short": "NP", "OXYGEN_MODALITY__NON_REBREATHING_MASK": "Non Rebreathing Mask", + "OXYGEN_MODALITY__NON_REBREATHING_MASK_short": "NRM", "OXYGEN_MODALITY__SIMPLE_FACE_MASK": "Simple Face Mask", + "OXYGEN_MODALITY__SIMPLE_FACE_MASK_short": "SFM", "PRESCRIPTION_FREQUENCY_BD": "Twice daily", "PRESCRIPTION_FREQUENCY_HS": "Night only", "PRESCRIPTION_FREQUENCY_OD": "Once daily", @@ -206,12 +210,19 @@ "URINATION_FREQUENCY__NORMAL": "Normal", "VENTILATOR": "Detailed Update", "VENTILATOR_MODE__CMV": "Control Mechanical Ventilation (CMV)", + "VENTILATOR_MODE__CMV_short": "CMV", "VENTILATOR_MODE__PCV": "Pressure Control Ventilation (PCV)", + "VENTILATOR_MODE__PCV_short": "PCV", "VENTILATOR_MODE__PC_SIMV": "Pressure Controlled SIMV (PC-SIMV)", + "VENTILATOR_MODE__PC_SIMV_short": "PC-SIMV", "VENTILATOR_MODE__PSV": "C-PAP / Pressure Support Ventilation (PSV)", + "VENTILATOR_MODE__PSV_short": "C-PAP/PSV", "VENTILATOR_MODE__SIMV": "Synchronised Intermittent Mandatory Ventilation (SIMV)", + "VENTILATOR_MODE__SIMV_short": "SIMV", "VENTILATOR_MODE__VCV": "Volume Control Ventilation (VCV)", + "VENTILATOR_MODE__VCV_short": "VCV", "VENTILATOR_MODE__VC_SIMV": "Volume Controlled SIMV (VC-SIMV)", + "VENTILATOR_MODE__VC_SIMV_short": "VC-SIMV", "View Facility": "View Facility", "aadhaar_number": "Aadhaar Number", "aadhaar_number_will_not_be_stored": "Aadhaar number will not be stored by CARE", @@ -611,6 +622,7 @@ "encounter_suggestion__OP": "Out-patient visit", "encounter_suggestion__R": "Consultation", "encounter_suggestion_edit_disallowed": "Not allowed to switch to this option in edit consultation", + "end_datetime": "End Date/Time", "enter_aadhaar_number": "Enter a 12-digit Aadhaar ID", "enter_aadhaar_otp": "Enter OTP sent to the registered mobile with Aadhaar", "enter_abha_address": "Enter ABHA Address", @@ -1145,6 +1157,7 @@ "spokes": "Spoke Facilities", "srf_id": "SRF ID", "staff_list": "Staff List", + "start_datetime": "Start Date/Time", "start_dosage": "Start Dosage", "state": "State", "status": "Status", @@ -1236,6 +1249,13 @@ "vacant": "Vacant", "vehicle_preference": "Vehicle preference", "vendor_name": "Vendor Name", + "ventilator_interface": "Respiratory Support Type", + "ventilator_log": "Ventilator Log", + "ventilator_modality": "Modality", + "ventilator_mode": "Ventilator Mode", + "ventilator_oxygen_modality": "Oxygen Modality", + "ventilator_oxygen_modality_oxygen_rate": "Oxygen Flow Rate", + "ventilator_spo2": "SpO₂", "verify_and_link": "Verify and Link", "verify_otp": "Verify OTP", "verify_otp_error": "Failed to verify OTP. Please try again later.", diff --git a/src/components/Facility/ConsultationDetails/ConsultationVentilatorTab.tsx b/src/components/Facility/ConsultationDetails/ConsultationVentilatorTab.tsx index 1ded0ba7684..b26ea6e0e53 100644 --- a/src/components/Facility/ConsultationDetails/ConsultationVentilatorTab.tsx +++ b/src/components/Facility/ConsultationDetails/ConsultationVentilatorTab.tsx @@ -1,8 +1,30 @@ +import Loading from "@/components/Common/Loading"; import PageTitle from "@/components/Common/PageTitle"; import { ConsultationTabProps } from "@/components/Facility/ConsultationDetails/index"; import { VentilatorPlot } from "@/components/Facility/Consultations/VentilatorPlot"; +import VentilatorTable from "@/components/Facility/Consultations/VentilatorTable"; + +import useFilters from "@/hooks/useFilters"; + +import routes from "@/Utils/request/api"; +import useQuery from "@/Utils/request/useQuery"; export const ConsultationVentilatorTab = (props: ConsultationTabProps) => { + const { consultationId } = props; + const { qParams, Pagination, resultsPerPage } = useFilters({ limit: 36 }); + + const { loading: isLoading, data } = useQuery(routes.getDailyReports, { + pathParams: { consultationId }, + query: { + limit: resultsPerPage, + offset: (qParams.page ? qParams.page - 1 : 0) * resultsPerPage, + }, + }); + + if (isLoading) { + return ; + } + return (
{ hideBack={true} breadcrumbs={false} /> - + + + {Boolean(data?.count && data.count > 0) && ( +
+ +
+ )}
); }; diff --git a/src/components/Facility/ConsultationDetails/Events/EventsList.tsx b/src/components/Facility/ConsultationDetails/Events/EventsList.tsx index e3f7072391e..47c68636a1a 100644 --- a/src/components/Facility/ConsultationDetails/Events/EventsList.tsx +++ b/src/components/Facility/ConsultationDetails/Events/EventsList.tsx @@ -68,6 +68,12 @@ export default function EventsList({ query }: { query: QueryParams }) { } const values = Object.fromEntries(entries); + if ( + values.ventilator_interface === "INVASIVE" || + values.ventilator_interface === "NON_INVASIVE" + ) { + values.ventilator_interface += " VENTILATOR"; + } switch (item.event_type.name) { case "INTERNAL_TRANSFER": diff --git a/src/components/Facility/Consultations/VentilatorPlot.tsx b/src/components/Facility/Consultations/VentilatorPlot.tsx index 6991fd02b8d..38948f165ea 100644 --- a/src/components/Facility/Consultations/VentilatorPlot.tsx +++ b/src/components/Facility/Consultations/VentilatorPlot.tsx @@ -1,14 +1,11 @@ import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; -import Pagination from "@/components/Common/Pagination"; +import Loading from "@/components/Common/Loading"; import BinaryChronologicalChart from "@/components/Facility/Consultations/components/BinaryChronologicalChart"; import { LinePlot } from "@/components/Facility/Consultations/components/LinePlot"; -import { VentilatorPlotFields } from "@/components/Facility/models"; +import { DailyRoundsModel } from "@/components/Patient/models"; -import { PAGINATION_LIMIT } from "@/common/constants"; - -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; import { formatDateTime } from "@/Utils/utils"; /* @@ -31,48 +28,222 @@ const modality: Array = [ ]; */ -export const VentilatorPlot = (props: any) => { - const { consultationId } = props; - const [results, setResults] = useState({}); - const [currentPage, setCurrentPage] = useState(1); - const [totalCount, setTotalCount] = useState(0); +interface graphDataProps { + [key: string]: { + bilateral_air_entry?: boolean; + etco2?: number; + id?: string; + ventilator_fio2?: number; + ventilator_mean_airway_pressure?: number; + ventilator_oxygen_modality_flow_rate?: number; + ventilator_oxygen_modality_oxygen_rate?: number; + ventilator_peep?: number | null; + ventilator_pip?: number; + ventilator_pressure_support?: number; + ventilator_resp_rate?: number; + ventilator_spo2?: number; + ventilator_tidal_volume?: number; + }; +} - useEffect(() => { - const fetchDailyRounds = async ( - currentPage: number, - consultationId: string, - ) => { - const { res, data } = await request(routes.dailyRoundsAnalyse, { - body: { page: currentPage, fields: VentilatorPlotFields }, - pathParams: { - consultationId, - }, +export const VentilatorPlot = ({ + dailyRoundsList, +}: { + dailyRoundsList?: DailyRoundsModel[]; +}) => { + const [results, setResults] = useState({}); + const { t } = useTranslation(); + + const getGraphData = (dailyRoundsData?: DailyRoundsModel[]) => { + const graphData: graphDataProps = {}; + const graphDataCount = dailyRoundsData?.length ?? 0; + if (dailyRoundsData) { + dailyRoundsData.forEach((currentRound: DailyRoundsModel) => { + // @ts-expect-error taken_at should always be available + graphData[currentRound.taken_at] = { + bilateral_air_entry: currentRound.bilateral_air_entry, + etco2: currentRound.etco2, + id: currentRound.id, + ventilator_fio2: currentRound.ventilator_fio2, + ventilator_mean_airway_pressure: + currentRound.ventilator_mean_airway_pressure, + ventilator_oxygen_modality_flow_rate: + currentRound.ventilator_oxygen_modality_flow_rate, + ventilator_oxygen_modality_oxygen_rate: + currentRound.ventilator_oxygen_modality_oxygen_rate, + ventilator_peep: currentRound.ventilator_peep + ? Number(currentRound.ventilator_peep) + : null, + ventilator_pip: currentRound.ventilator_pip, + ventilator_pressure_support: currentRound.ventilator_pressure_support, + ventilator_resp_rate: currentRound.ventilator_resp_rate, + ventilator_spo2: currentRound.ventilator_spo2, + ventilator_tidal_volume: currentRound.ventilator_tidal_volume, + }; }); - if (res && res.ok && data) { - setResults(data.results); - setTotalCount(data.count); - } - }; + } + return { graphData, graphDataCount }; + }; + + useEffect(() => { + const { graphData } = getGraphData(dailyRoundsList); + setResults(graphData); + }, [dailyRoundsList]); - fetchDailyRounds(currentPage, consultationId); - }, [consultationId, currentPage]); + if (!dailyRoundsList) { + return ; + } - const handlePagination = (page: number) => { - setCurrentPage(page); + const dates = Object.keys(results).map((p: string) => formatDateTime(p)); + + const getConditionAndLegend = ( + name: string, + currentRound: DailyRoundsModel, + ) => { + let condition = false; + let legend = ""; + switch (name) { + case "ventilator_pip": + case "ventilator_mean_airway_pressure": + case "ventilator_resp_rate": + case "ventilator_pressure_support": + case "ventilator_tidal_volume": + case "ventilator_peep": + condition = + (currentRound.ventilator_interface === "INVASIVE" || + currentRound.ventilator_interface === "NON_INVASIVE") && + !!currentRound.ventilator_mode; + break; + case "ventilator_fio2": + condition = + currentRound.ventilator_interface === "OXYGEN_SUPPORT" && + currentRound.ventilator_oxygen_modality === "HIGH_FLOW_NASAL_CANNULA"; + break; + case "ventilator_spo2": + condition = + currentRound.ventilator_interface === "OXYGEN_SUPPORT" && + (currentRound.ventilator_oxygen_modality === "NASAL_PRONGS" || + currentRound.ventilator_oxygen_modality === "SIMPLE_FACE_MASK" || + currentRound.ventilator_oxygen_modality === + "NON_REBREATHING_MASK" || + currentRound.ventilator_oxygen_modality === + "HIGH_FLOW_NASAL_CANNULA"); + break; + case "etco2": + case "ventilator_oxygen_modality_flow_rate": + condition = + !!currentRound.ventilator_mode || + !!currentRound.ventilator_oxygen_modality || + false; + break; + case "ventilator_oxygen_modality_oxygen_rate": + condition = + currentRound.ventilator_interface === "OXYGEN_SUPPORT" && + (currentRound.ventilator_oxygen_modality === "NASAL_PRONGS" || + currentRound.ventilator_oxygen_modality === "SIMPLE_FACE_MASK" || + currentRound.ventilator_oxygen_modality === "NON_REBREATHING_MASK"); + break; + } + switch (currentRound.ventilator_interface) { + case "OXYGEN_SUPPORT": + legend = + t( + `OXYGEN_MODALITY__${currentRound.ventilator_oxygen_modality}_short`, + ) + + " (" + + t("RESPIRATORY_SUPPORT_SHORT__OXYGEN_SUPPORT") + + ")"; + break; + case "INVASIVE": + legend = + t(`VENTILATOR_MODE__${currentRound.ventilator_mode}_short`) + + " (" + + t("RESPIRATORY_SUPPORT_SHORT__INVASIVE") + + ")"; + break; + case "NON_INVASIVE": + legend = + t(`VENTILATOR_MODE__${currentRound.ventilator_mode}_short`) + + " (" + + t("RESPIRATORY_SUPPORT_SHORT__NON_INVASIVE") + + ")"; + break; + } + return { condition, legend }; + }; + + const getModeOrModality = (round: DailyRoundsModel) => { + const ventilatorInterface = round.ventilator_interface; + if (!ventilatorInterface) return null; + switch (ventilatorInterface) { + case "INVASIVE": + case "NON_INVASIVE": + return round.ventilator_mode; + case "OXYGEN_SUPPORT": + return round.ventilator_oxygen_modality; + default: + return null; + } }; - const dates = Object.keys(results) - .map((p: string) => formatDateTime(p)) - .reverse(); + const getMarkLineData = (name: string) => { + const markLineData = []; + if (!dailyRoundsList) return []; + let index = 0; + while (index < dailyRoundsList.length) { + const currentRound = dailyRoundsList[index]; + const { condition, legend } = getConditionAndLegend(name, currentRound); + const currentInterfaceOrModality = getModeOrModality(currentRound); + if (condition) { + const startIndex = dates.findIndex( + (element) => element === formatDateTime(currentRound.taken_at), + ); + if (startIndex !== -1) { + let nextIndex = index + 1; + while (nextIndex < dailyRoundsList.length) { + const nextRound = dailyRoundsList[nextIndex]; + const nextInterfaceOrModality = getModeOrModality(nextRound); + if ( + currentRound.ventilator_interface === + nextRound.ventilator_interface && + currentInterfaceOrModality === nextInterfaceOrModality + ) { + nextIndex += 1; + } else { + break; + } + } + const position = + startIndex === 0 ? "insideMiddleBottom" : "insideMiddleTop"; + markLineData.push({ + name: legend, + xAxis: dates[startIndex], + label: { + show: true, + position, + formatter: "{b}", + color: "#000000", + textBorderColor: "#ffffff", + textBorderWidth: 2, + }, + }); + index = nextIndex; + } else { + index += 1; + } + } else { + index += 1; + } + } + return markLineData; + }; - const yAxisData = (name: string) => { - return Object.values(results) - .map((p: any) => p[name]) - .reverse(); + const yAxisData = (name: keyof graphDataProps[string]) => { + return Object.values(results).map((p) => p[name]); }; const bilateral = Object.values(results) - .map((p: any, i) => { + .map((p, i) => { return { value: p.bilateral_air_entry, timestamp: Object.keys(results)[i], @@ -91,6 +262,7 @@ export const VentilatorPlot = (props: any) => { yData={yAxisData("ventilator_pip")} low={12} high={30} + verticalMarkerData={getMarkLineData("ventilator_pip")} />
@@ -101,6 +273,9 @@ export const VentilatorPlot = (props: any) => { yData={yAxisData("ventilator_mean_airway_pressure")} low={12} high={25} + verticalMarkerData={getMarkLineData( + "ventilator_mean_airway_pressure", + )} />
@@ -111,6 +286,7 @@ export const VentilatorPlot = (props: any) => { yData={yAxisData("ventilator_resp_rate")} low={12} high={20} + verticalMarkerData={getMarkLineData("ventilator_resp_rate")} />
@@ -121,6 +297,7 @@ export const VentilatorPlot = (props: any) => { yData={yAxisData("ventilator_pressure_support")} low={5} high={15} + verticalMarkerData={getMarkLineData("ventilator_pressure_support")} />
@@ -129,6 +306,7 @@ export const VentilatorPlot = (props: any) => { name="Tidal Volume" xData={dates} yData={yAxisData("ventilator_tidal_volume")} + verticalMarkerData={getMarkLineData("ventilator_tidal_volume")} />
@@ -139,6 +317,7 @@ export const VentilatorPlot = (props: any) => { yData={yAxisData("ventilator_peep")} low={5} high={10} + verticalMarkerData={getMarkLineData("ventilator_peep")} />
@@ -149,6 +328,7 @@ export const VentilatorPlot = (props: any) => { yData={yAxisData("ventilator_fio2")} low={21} high={60} + verticalMarkerData={getMarkLineData("ventilator_fio2")} />
@@ -159,6 +339,7 @@ export const VentilatorPlot = (props: any) => { yData={yAxisData("ventilator_spo2")} low={90} high={100} + verticalMarkerData={getMarkLineData("ventilator_spo2")} />
@@ -169,6 +350,7 @@ export const VentilatorPlot = (props: any) => { yData={yAxisData("etco2")} low={35} high={45} + verticalMarkerData={getMarkLineData("etco2")} />
@@ -185,6 +367,9 @@ export const VentilatorPlot = (props: any) => { name="Oxygen Flow Rate" xData={dates} yData={yAxisData("ventilator_oxygen_modality_oxygen_rate")} + verticalMarkerData={getMarkLineData( + "ventilator_oxygen_modality_oxygen_rate", + )} />
@@ -193,20 +378,12 @@ export const VentilatorPlot = (props: any) => { name="Flow Rate" xData={dates} yData={yAxisData("ventilator_oxygen_modality_flow_rate")} + verticalMarkerData={getMarkLineData( + "ventilator_oxygen_modality_flow_rate", + )} />
- - {totalCount > PAGINATION_LIMIT && ( -
- -
- )} ); }; diff --git a/src/components/Facility/Consultations/VentilatorTable.tsx b/src/components/Facility/Consultations/VentilatorTable.tsx new file mode 100644 index 00000000000..2059f14bac0 --- /dev/null +++ b/src/components/Facility/Consultations/VentilatorTable.tsx @@ -0,0 +1,129 @@ +import { useTranslation } from "react-i18next"; + +import { compareByDateString, formatDateTime } from "@/Utils/utils"; + +import { DailyRoundsModel } from "../../Patient/models"; + +type VentilatorTableProps = { + dailyRoundsList?: DailyRoundsModel[]; +}; + +export default function VentilatorTable(props: VentilatorTableProps) { + const { t } = useTranslation(); + const { dailyRoundsList } = props; + + const VentilatorTableRow = ({ + dailyRound, + start_date, + end_date, + }: { + dailyRound: DailyRoundsModel; + start_date: string; + end_date: string; + }) => { + const getModeText = () => { + const { + ventilator_interface, + ventilator_mode, + ventilator_oxygen_modality, + } = dailyRound; + switch (ventilator_interface) { + case "INVASIVE": + case "NON_INVASIVE": + return t(`VENTILATOR_MODE__${ventilator_mode}`); + case "OXYGEN_SUPPORT": + return t(`OXYGEN_MODALITY__${ventilator_oxygen_modality}`); + default: + return null; + } + }; + return ( + + {start_date} + {end_date} + + {t(`RESPIRATORY_SUPPORT__${dailyRound?.ventilator_interface}`)} + + {getModeText()} + + ); + }; + + const getModeOrModality = (round: DailyRoundsModel) => { + const ventilatorInterface = round.ventilator_interface; + if (!ventilatorInterface) return null; + switch (ventilatorInterface) { + case "INVASIVE": + case "NON_INVASIVE": + return round.ventilator_mode; + case "OXYGEN_SUPPORT": + return round.ventilator_oxygen_modality; + default: + return null; + } + }; + + const VentilatorTableBody = (dailyRoundsList: DailyRoundsModel[]) => { + const rows = []; + for (let index = 0; index < dailyRoundsList.length; index++) { + const currentRound = dailyRoundsList[index]; + const currentInterfaceOrModality = getModeOrModality(currentRound); + if (!currentInterfaceOrModality) continue; + while (index < dailyRoundsList.length - 1) { + const nextRound = dailyRoundsList[index + 1]; + const nextInterfaceOrModality = getModeOrModality(nextRound); + if ( + nextInterfaceOrModality && + currentRound.ventilator_interface == nextRound.ventilator_interface && + currentInterfaceOrModality == nextInterfaceOrModality + ) { + index += 1; + } else { + break; + } + } + const end_date = + index + 1 < dailyRoundsList.length + ? formatDateTime(dailyRoundsList[index + 1].taken_at) + : ""; + const start_date = formatDateTime(currentRound.taken_at); + rows.push( + , + ); + } + return rows; + }; + + if (!dailyRoundsList?.length) { + return; + } + const sortedData: DailyRoundsModel[] = dailyRoundsList.sort( + compareByDateString("taken_at"), + ); + + return ( +
+ + + + + + + + + + + {VentilatorTableBody(sortedData)} +
+ {t("ventilator_log")} +
{t("start_datetime")}{t("end_datetime")}{t("ventilator_modality")} + {`${t("ventilator_mode")} / ${t("ventilator_oxygen_modality")}`} +
+
+ ); +} diff --git a/src/components/Facility/Consultations/components/BinaryChronologicalChart.tsx b/src/components/Facility/Consultations/components/BinaryChronologicalChart.tsx index 82eb7f3da4d..6183f19368d 100644 --- a/src/components/Facility/Consultations/components/BinaryChronologicalChart.tsx +++ b/src/components/Facility/Consultations/components/BinaryChronologicalChart.tsx @@ -4,7 +4,7 @@ import { formatDateTime } from "@/Utils/utils"; export default function BinaryChronologicalChart(props: { data: { - value: boolean; + value: boolean | undefined; timestamp: string; notes?: string; }[]; diff --git a/src/components/Facility/Consultations/components/LinePlot.tsx b/src/components/Facility/Consultations/components/LinePlot.tsx index 0829527faae..e9f1adf731f 100644 --- a/src/components/Facility/Consultations/components/LinePlot.tsx +++ b/src/components/Facility/Consultations/components/LinePlot.tsx @@ -12,12 +12,21 @@ export const LinePlot = (props: any) => { const { title, name, - xData, - yData, low = null, high = null, defaultSpace, + verticalMarkerData = null, } = props; + let { xData, yData } = props; + const yDatacount = yData.filter( + (item: number | null): item is number => + item !== null && !Number.isNaN(item), + ).length; + if (yDatacount === 0) { + yData = []; + xData = []; + } + let generalOptions: any = { grid: { top: "40px", @@ -106,6 +115,25 @@ export const LinePlot = (props: any) => { ], }; + if (verticalMarkerData && yDatacount > 0) { + let series = generalOptions.series[0]; + series = { + ...series, + markLine: { + silent: true, + data: verticalMarkerData, + symbol: "none", + lineStyle: { + color: "#000000", + }, + }, + }; + generalOptions = { + ...generalOptions, + series, + }; + } + if (props.type && props.type === "WAVEFORM") { generalOptions = { ...generalOptions, diff --git a/src/components/Facility/Consultations/components/ReactEcharts.tsx b/src/components/Facility/Consultations/components/ReactEcharts.tsx index 326bd23661a..4215b34fa4d 100644 --- a/src/components/Facility/Consultations/components/ReactEcharts.tsx +++ b/src/components/Facility/Consultations/components/ReactEcharts.tsx @@ -5,6 +5,7 @@ import { DataZoomComponent, GridComponent, LegendComponent, + MarkLineComponent, TitleComponent, ToolboxComponent, TooltipComponent, @@ -27,6 +28,7 @@ echarts.use([ TooltipComponent, VisualMapComponent, VisualMapPiecewiseComponent, + MarkLineComponent, ]); interface ReactEchartsProps extends EChartsReactProps {