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 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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 + + )}