From c08a7f520e00c587e728dc56fc128cfa76e1027e Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Mon, 5 Feb 2024 16:20:36 +0530 Subject: [PATCH 01/19] Fix filters cache restoration logic + cleaner URL query params and filters cache + fixes state management of facility, lsg body and district in patient filters (#7157) * Fix when filters cache is applied and ignore unapllied filters in query params and cache * fixes #7166; fix selected state of facility, lsg body and district * remove unused redux actions --- src/Common/hooks/useFilters.tsx | 55 ++++++------ src/Components/Auth/Login.tsx | 4 +- src/Components/Common/FacilitySelect.tsx | 2 +- .../FacilityFilter/DistrictSelect.tsx | 2 +- src/Components/Patient/PatientFilter.tsx | 89 +++++++------------ src/Redux/actions.tsx | 3 - src/Redux/api.tsx | 2 + src/Utils/FiltersCache.tsx | 77 ++++++++++++++++ src/Utils/utils.ts | 8 -- 9 files changed, 140 insertions(+), 102 deletions(-) create mode 100644 src/Utils/FiltersCache.tsx diff --git a/src/Common/hooks/useFilters.tsx b/src/Common/hooks/useFilters.tsx index 4229ae8ab02..1c62a10d9d0 100644 --- a/src/Common/hooks/useFilters.tsx +++ b/src/Common/hooks/useFilters.tsx @@ -5,14 +5,14 @@ import GenericFilterBadge from "../../CAREUI/display/FilterBadge"; import PaginationComponent from "../../Components/Common/Pagination"; import useConfig from "./useConfig"; import { classNames } from "../../Utils/utils"; +import FiltersCache from "../../Utils/FiltersCache"; export type FilterState = Record; -export type FilterParamKeys = string | string[]; interface FilterBadgeProps { name: string; value?: string; - paramKey: FilterParamKeys; + paramKey: string | string[]; } /** @@ -32,18 +32,18 @@ export default function useFilters({ const [showFilters, setShowFilters] = useState(false); const [qParams, _setQueryParams] = useQueryParams(); + const updateCache = (query: QueryParam) => { + const blacklist = FILTERS_CACHE_BLACKLIST.concat(cacheBlacklist); + FiltersCache.set(query, blacklist); + }; + const setQueryParams = ( query: QueryParam, options?: setQueryParamsOptions ) => { - const updatedQParams = { ...query }; - - for (const param of cacheBlacklist) { - delete updatedQParams[param]; - } - + query = FiltersCache.utils.clean(query); _setQueryParams(query, options); - updateFiltersCache(updatedQParams); + updateCache(query); }; const updateQuery = (filter: FilterState) => { @@ -61,15 +61,22 @@ export default function useFilters({ const removeFilter = (param: string) => removeFilters([param]); useEffect(() => { - const cache = getFiltersCache(); const qParamKeys = Object.keys(qParams); - const canSkip = Object.keys(cache).every( - (key) => qParamKeys.includes(key) && qParams[key] === cache[key] - ); - if (canSkip) return; - if (Object.keys(cache).length) { - setQueryParams(cache); + + // If we navigate to a path that has query params set on mount, + // skip restoring the cache, instead update the cache with new filters. + if (qParamKeys.length) { + updateCache(qParams); + return; } + + const cache = FiltersCache.get(); + if (!cache) { + return; + } + + // Restore cache + setQueryParams(cache); }, []); const FilterBadge = ({ name, value, paramKey }: FilterBadgeProps) => { @@ -99,7 +106,7 @@ export default function useFilters({ }; const badgeUtils = { - badge(name: string, paramKey: FilterParamKeys) { + badge(name: string, paramKey: FilterBadgeProps["paramKey"]) { return { name, paramKey }; }, ordering(name = "Sort by", paramKey = "ordering") { @@ -109,7 +116,7 @@ export default function useFilters({ value: qParams[paramKey] && t("SortOptions." + qParams[paramKey]), }; }, - value(name: string, paramKey: FilterParamKeys, value: string) { + value(name: string, paramKey: FilterBadgeProps["paramKey"], value: string) { return { name, value, paramKey }; }, phoneNumber(name = "Phone Number", paramKey = "phone_number") { @@ -278,15 +285,3 @@ const removeFromQuery = (query: Record, params: string[]) => { }; const FILTERS_CACHE_BLACKLIST = ["page", "limit", "offset"]; - -const getFiltersCacheKey = () => `filters--${window.location.pathname}`; -const getFiltersCache = () => { - return JSON.parse(localStorage.getItem(getFiltersCacheKey()) || "{}"); -}; -const updateFiltersCache = (cache: Record) => { - const result = { ...cache }; - for (const param of FILTERS_CACHE_BLACKLIST) { - delete result[param]; - } - localStorage.setItem(getFiltersCacheKey(), JSON.stringify(result)); -}; diff --git a/src/Components/Auth/Login.tsx b/src/Components/Auth/Login.tsx index d1cd94dbab5..8dcae9bafc0 100644 --- a/src/Components/Auth/Login.tsx +++ b/src/Components/Auth/Login.tsx @@ -11,8 +11,8 @@ import useConfig from "../../Common/hooks/useConfig"; import CircularProgress from "../Common/components/CircularProgress"; import ReactMarkdown from "react-markdown"; import rehypeRaw from "rehype-raw"; -import { invalidateFiltersCache } from "../../Utils/utils"; import { useAuthContext } from "../../Common/hooks/useAuthUser"; +import FiltersCache from "../../Utils/FiltersCache"; export const Login = (props: { forgot?: boolean }) => { const { signIn } = useAuthContext(); @@ -93,7 +93,7 @@ export const Login = (props: { forgot?: boolean }) => { const handleSubmit = async (e: any) => { e.preventDefault(); setLoading(true); - invalidateFiltersCache(); + FiltersCache.invaldiateAll(); const validated = validateData(); if (!validated) { setLoading(false); diff --git a/src/Components/Common/FacilitySelect.tsx b/src/Components/Common/FacilitySelect.tsx index 17f67a7def1..b207189d27d 100644 --- a/src/Components/Common/FacilitySelect.tsx +++ b/src/Components/Common/FacilitySelect.tsx @@ -16,7 +16,7 @@ interface FacilitySelectProps { showAll?: boolean; showNOptions?: number; freeText?: boolean; - selected: FacilityModel | FacilityModel[] | null; + selected?: FacilityModel | FacilityModel[] | null; setSelected: (selected: FacilityModel | FacilityModel[] | null) => void; } diff --git a/src/Components/Facility/FacilityFilter/DistrictSelect.tsx b/src/Components/Facility/FacilityFilter/DistrictSelect.tsx index 088048ba6dd..ef77d50221e 100644 --- a/src/Components/Facility/FacilityFilter/DistrictSelect.tsx +++ b/src/Components/Facility/FacilityFilter/DistrictSelect.tsx @@ -8,7 +8,7 @@ interface DistrictSelectProps { errors: string; className?: string; multiple?: boolean; - selected: string; + selected?: string; setSelected: (selected: string) => void; } diff --git a/src/Components/Patient/PatientFilter.tsx b/src/Components/Patient/PatientFilter.tsx index 0e1cdfdd083..6392c5c4d45 100644 --- a/src/Components/Patient/PatientFilter.tsx +++ b/src/Components/Patient/PatientFilter.tsx @@ -1,5 +1,4 @@ import dayjs from "dayjs"; -import { useCallback, useEffect } from "react"; import CareIcon from "../../CAREUI/icons/CareIcon"; import FiltersSlideover from "../../CAREUI/interactive/FiltersSlideover"; import { @@ -12,12 +11,6 @@ import { } from "../../Common/constants"; import useConfig from "../../Common/hooks/useConfig"; import useMergeState from "../../Common/hooks/useMergeState"; -import { - getAllLocalBody, - getAnyFacility, - getDistrict, -} from "../../Redux/actions"; -import { useDispatch } from "react-redux"; import { dateQueryString } from "../../Utils/utils"; import { DateRange } from "../Common/DateRangeInputV2"; import { FacilitySelect } from "../Common/FacilitySelect"; @@ -35,6 +28,9 @@ import { import MultiSelectMenuV2 from "../Form/MultiSelectMenuV2"; import SelectMenuV2 from "../Form/SelectMenuV2"; import DiagnosesFilter, { FILTER_BY_DIAGNOSES_KEYS } from "./DiagnosesFilter"; +import useQuery from "../../Utils/request/useQuery"; +import routes from "../../Redux/api"; +import request from "../../Utils/request/request"; const getDate = (value: any) => value && dayjs(value).isValid() && dayjs(value).toDate(); @@ -105,37 +101,24 @@ export default function PatientFilter(props: any) { diagnoses_unconfirmed: filter.diagnoses_unconfirmed || null, diagnoses_differential: filter.diagnoses_differential || null, }); - const dispatch: any = useDispatch(); - - useEffect(() => { - async function fetchData() { - if (filter.facility) { - const { data: facilityData } = await dispatch( - getAnyFacility(filter.facility, "facility") - ); - setFilterState({ facility_ref: facilityData }); - } - if (filter.district) { - const { data: districtData } = await dispatch( - getDistrict(filter.district, "district") - ); - setFilterState({ district_ref: districtData }); - } + useQuery(routes.getAnyFacility, { + pathParams: { id: filter.facility }, + prefetch: !!filter.facility, + onResponse: ({ data }) => setFilterState({ facility_ref: data }), + }); - if (filter.lsgBody) { - const { data: lsgRes } = await dispatch(getAllLocalBody({})); - const lsgBodyData = lsgRes.results; + useQuery(routes.getDistrict, { + pathParams: { id: filter.district }, + prefetch: !!filter.district, + onResponse: ({ data }) => setFilterState({ district_ref: data }), + }); - setFilterState({ - lsgBody_ref: lsgBodyData.filter( - (obj: any) => obj.id.toString() === filter.lsgBody.toString() - )[0], - }); - } - } - fetchData(); - }, [dispatch]); + useQuery(routes.getLocalBody, { + pathParams: { id: filter.lsgBody }, + prefetch: !!filter.lsgBody, + onResponse: ({ data }) => setFilterState({ lsgBody_ref: data }), + }); const VACCINATED_FILTER = [ { id: "0", text: "Unvaccinated" }, @@ -161,21 +144,19 @@ export default function PatientFilter(props: any) { { id: "false", text: "No" }, ]; - const setFacility = (selected: any, name: string) => { - const filterData: any = { ...filterState }; - filterData[`${name}_ref`] = selected; - filterData[name] = (selected || {}).id; - - setFilterState(filterData); + const setFilterWithRef = (name: string, selected?: any) => { + setFilterState({ + [`${name}_ref`]: selected, + [name]: selected?.id, + }); }; - const lsgSearch = useCallback( - async (search: string) => { - const res = await dispatch(getAllLocalBody({ local_body_name: search })); - return res?.data?.results; - }, - [dispatch] - ); + const lsgSearch = async (search: string) => { + const { data } = await request(routes.getAllLocalBody, { + query: { local_body_name: search }, + }); + return data?.results; + }; const applyFilter = () => { const { @@ -585,7 +566,7 @@ export default function PatientFilter(props: any) { name="facility" showAll={false} selected={filterState.facility_ref} - setSelected={(obj) => setFacility(obj, "facility")} + setSelected={(obj) => setFilterWithRef("facility", obj)} /> {filterState.facility && ( @@ -629,13 +610,7 @@ export default function PatientFilter(props: any) { name="lsg_body" selected={filterState.lsgBody_ref} fetchData={lsgSearch} - onChange={(selected) => - setFilterState({ - ...filterState, - lsgBody_ref: selected, - lsgBody: selected.id, - }) - } + onChange={(obj) => setFilterWithRef("lsgBody", obj)} optionLabel={(option) => option.name} compareBy="id" /> @@ -648,7 +623,7 @@ export default function PatientFilter(props: any) { multiple={false} name="district" selected={filterState.district_ref} - setSelected={(obj: any) => setFacility(obj, "district")} + setSelected={(obj) => setFilterWithRef("district", obj)} errors={""} /> diff --git a/src/Redux/actions.tsx b/src/Redux/actions.tsx index 8350ca8bd29..8e3ae382547 100644 --- a/src/Redux/actions.tsx +++ b/src/Redux/actions.tsx @@ -132,9 +132,6 @@ export const getWardByLocalBody = (pathParam: object) => { export const getLocalBody = (pathParam: object) => { return fireRequest("getLocalBody", [], {}, pathParam); }; -export const getAllLocalBody = (params: object) => { - return fireRequest("getAllLocalBody", [], params); -}; // Sample Test export const getSampleTestList = (params: object, pathParam: object) => { diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index de30ed7b567..6425ff8eab0 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -761,6 +761,8 @@ const routes = { }, getAllLocalBody: { path: "/api/v1/local_body/", + method: "GET", + TRes: Type>(), }, getLocalbodyByName: { path: "/api/v1/local_body/", diff --git a/src/Utils/FiltersCache.tsx b/src/Utils/FiltersCache.tsx new file mode 100644 index 00000000000..e69fb14da58 --- /dev/null +++ b/src/Utils/FiltersCache.tsx @@ -0,0 +1,77 @@ +type Filters = Record; + +/** + * @returns The filters cache key associated to the current window URL + */ +const getKey = () => { + return `filters--${window.location.pathname}`; +}; + +/** + * Returns a sanitized filter object that ignores filters with no value or + * filters that are part of the blacklist. + * + * @param filters Input filters to be sanitized + * @param blacklist Optional array of filter keys that are to be ignored. + */ +const clean = (filters: Filters, blacklist?: string[]) => { + const reducer = (cleaned: Filters, key: string) => { + const valueAllowed = (filters[key] ?? "") != ""; + if (valueAllowed && !blacklist?.includes(key)) { + cleaned[key] = filters[key]; + } + return cleaned; + }; + + return Object.keys(filters).reduce(reducer, {}); +}; + +/** + * Retrieves the cached filters + */ +const get = (key?: string) => { + const content = localStorage.getItem(key ?? getKey()); + return content ? (JSON.parse(content) as Filters) : null; +}; + +/** + * Sets the filters cache with the specified filters. + */ +const set = (filters: Filters, blacklist?: string[], key?: string) => { + key ??= getKey(); + filters = clean(filters, blacklist); + + if (Object.keys(filters).length) { + localStorage.setItem(key, JSON.stringify(filters)); + } else { + invalidate(key); + } +}; + +/** + * Removes the filters cache for the specified key or current URL. + */ +const invalidate = (key?: string) => { + localStorage.removeItem(key ?? getKey()); +}; + +/** + * Removes all filters cache in the platform. + */ +const invaldiateAll = () => { + for (const key in localStorage) { + if (key.startsWith("filters--")) { + invalidate(key); + } + } +}; + +export default { + get, + set, + invalidate, + invaldiateAll, + utils: { + clean, + }, +}; diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 2966790fb10..b890672a6c1 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -449,14 +449,6 @@ export const showUserDelete = (authUser: UserModel, targetUser: UserModel) => { return false; }; -export const invalidateFiltersCache = () => { - for (const key in localStorage) { - if (key.startsWith("filters--")) { - localStorage.removeItem(key); - } - } -}; - export const compareBy = (key: keyof T) => { return (a: T, b: T) => { return a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : 0; From ed99a2cfa9ea287756947e394a2f55ab68c7b2f9 Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Mon, 5 Feb 2024 16:44:33 +0530 Subject: [PATCH 02/19] New Cypress Test | Patient Transfer and Patient Data Import From External Result | Patient Module (#7165) * first draft * first draft * Transfer functionality of a patient * Final PR * refactor few code * refactor cypress policy file * revert vite configuration --- .../patient_spec/patient_consultation.cy.ts | 104 +++++++++++ ..._crud.cy.ts => patient_registration.cy.ts} | 173 +++++++++++------- .../pageobject/Patient/PatientConsultation.ts | 12 +- cypress/pageobject/Patient/PatientCreation.ts | 99 ---------- cypress/pageobject/Patient/PatientExternal.ts | 28 +++ .../pageobject/Patient/PatientInsurance.ts | 32 ++++ .../Patient/PatientMedicalHistory.ts | 59 ++++++ cypress/pageobject/Patient/PatientTransfer.ts | 63 +++++++ src/Components/ExternalResult/ResultItem.tsx | 11 +- src/Components/ExternalResult/ResultList.tsx | 5 +- .../Facility/DuplicatePatientDialog.tsx | 1 + .../Facility/TransferPatientDialog.tsx | 2 + src/Components/Patient/PatientHome.tsx | 1 + src/Components/Patient/PatientInfoCard.tsx | 5 +- src/Components/Patient/PatientRegister.tsx | 2 + 15 files changed, 420 insertions(+), 177 deletions(-) create mode 100644 cypress/e2e/patient_spec/patient_consultation.cy.ts rename cypress/e2e/patient_spec/{patient_crud.cy.ts => patient_registration.cy.ts} (55%) create mode 100644 cypress/pageobject/Patient/PatientExternal.ts create mode 100644 cypress/pageobject/Patient/PatientInsurance.ts create mode 100644 cypress/pageobject/Patient/PatientMedicalHistory.ts create mode 100644 cypress/pageobject/Patient/PatientTransfer.ts diff --git a/cypress/e2e/patient_spec/patient_consultation.cy.ts b/cypress/e2e/patient_spec/patient_consultation.cy.ts new file mode 100644 index 00000000000..9b3248d6656 --- /dev/null +++ b/cypress/e2e/patient_spec/patient_consultation.cy.ts @@ -0,0 +1,104 @@ +import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; +import LoginPage from "../../pageobject/Login/LoginPage"; +import { PatientPage } from "../../pageobject/Patient/PatientCreation"; +import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; +import { + emergency_phone_number, + phone_number, +} from "../../pageobject/constants"; +import FacilityPage from "../../pageobject/Facility/FacilityCreation"; +import PatientMedicalHistory from "../../pageobject/Patient/PatientMedicalHistory"; + +describe("Patient Creation with consultation", () => { + const patientConsultationPage = new PatientConsultationPage(); + const loginPage = new LoginPage(); + const patientPage = new PatientPage(); + const facilityPage = new FacilityPage(); + const patientMedicalHistory = new PatientMedicalHistory(); + const patientDateOfBirth = "01012001"; + const patientOneName = "Patient With Consultation"; + const patientOneGender = "Male"; + const patientOneAddress = "Test Patient Address"; + const patientOnePincode = "682001"; + const patientOneState = "Kerala"; + const patientOneDistrict = "Ernakulam"; + const patientOneLocalbody = "Aluva"; + const patientOneWard = "4"; + const patientOneBloodGroup = "O+"; + + before(() => { + loginPage.loginAsDisctrictAdmin(); + cy.saveLocalStorage(); + }); + + beforeEach(() => { + cy.restoreLocalStorage(); + cy.clearLocalStorage(/filters--.+/); + cy.awaitUrl("/patients"); + }); + + it("Create a patient with consultation", () => { + patientPage.createPatient(); + patientPage.selectFacility("Dummy Facility 40"); + patientPage.patientformvisibility(); + patientPage.typePatientPhoneNumber(phone_number); + patientPage.typePatientEmergencyNumber(emergency_phone_number); + patientPage.typePatientDateOfBirth(patientDateOfBirth); + patientPage.typePatientName(patientOneName); + patientPage.selectPatientGender(patientOneGender); + patientPage.typePatientAddress(patientOneAddress); + facilityPage.fillPincode(patientOnePincode); + facilityPage.selectStateOnPincode(patientOneState); + facilityPage.selectDistrictOnPincode(patientOneDistrict); + facilityPage.selectLocalBody(patientOneLocalbody); + facilityPage.selectWard(patientOneWard); + patientMedicalHistory.clickNoneMedicialHistory(); + patientPage.selectPatientBloodGroup(patientOneBloodGroup); + patientPage.clickCreatePatient(); + patientPage.verifyPatientIsCreated(); + patientConsultationPage.fillIllnessHistory("history"); + patientConsultationPage.selectConsultationStatus( + "Outpatient/Emergency Room" + ); + patientConsultationPage.selectSymptoms("ASYMPTOMATIC"); + + patientConsultationPage.enterConsultationDetails( + "Stable", + "Examination details and Clinical conditions", + "70", + "170", + "IP007", + "generalnote", + "Dev Doctor" + ); + patientConsultationPage.submitConsultation(); + + // Below code for the prescription module only present while creating a new consultation + patientConsultationPage.clickAddPrescription(); + patientConsultationPage.interceptMediaBase(); + patientConsultationPage.selectMedicinebox(); + patientConsultationPage.waitForMediabaseStatusCode(); + patientConsultationPage.prescribefirstMedicine(); + patientConsultationPage.enterDosage("3"); + patientConsultationPage.selectDosageFrequency("Twice daily"); + patientConsultationPage.submitPrescriptionAndReturn(); + patientConsultationPage.verifyConsultationPatientName(patientOneName); + }); + + it("Edit created consultation to existing patient", () => { + // temporary fixing, whole file will be refactored soon + cy.get("[data-cy='patient']").first().click(); + patientConsultationPage.clickEditConsultationButton(); + patientConsultationPage.fillIllnessHistory("editted"); + patientConsultationPage.updateSymptoms("FEVER"); + patientConsultationPage.setSymptomsDate("01082023"); + patientConsultationPage.updateConsultation(); + patientConsultationPage.verifySuccessNotification( + "Consultation updated successfully" + ); + }); + + afterEach(() => { + cy.saveLocalStorage(); + }); +}); diff --git a/cypress/e2e/patient_spec/patient_crud.cy.ts b/cypress/e2e/patient_spec/patient_registration.cy.ts similarity index 55% rename from cypress/e2e/patient_spec/patient_crud.cy.ts rename to cypress/e2e/patient_spec/patient_registration.cy.ts index 156a0d4fe5f..1dce2c7c6f7 100644 --- a/cypress/e2e/patient_spec/patient_crud.cy.ts +++ b/cypress/e2e/patient_spec/patient_registration.cy.ts @@ -2,11 +2,15 @@ import { afterEach, before, beforeEach, cy, describe, it } from "local-cypress"; import LoginPage from "../../pageobject/Login/LoginPage"; import { PatientPage } from "../../pageobject/Patient/PatientCreation"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; -import { PatientConsultationPage } from "../../pageobject/Patient/PatientConsultation"; import { emergency_phone_number, phone_number, } from "../../pageobject/constants"; +import PatientTransfer from "../../pageobject/Patient/PatientTransfer"; +import PatientExternal from "../../pageobject/Patient/PatientExternal"; +import PatientInsurance from "../../pageobject/Patient/PatientInsurance"; +import PatientMedicalHistory from "../../pageobject/Patient/PatientMedicalHistory"; + const yearOfBirth = "2001"; const calculateAge = () => { @@ -17,9 +21,13 @@ const calculateAge = () => { describe("Patient Creation with consultation", () => { const loginPage = new LoginPage(); const patientPage = new PatientPage(); - const patientConsultationPage = new PatientConsultationPage(); const facilityPage = new FacilityPage(); + const patientTransfer = new PatientTransfer(); + const patientExternal = new PatientExternal(); + const patientInsurance = new PatientInsurance(); + const patientMedicalHistory = new PatientMedicalHistory(); const age = calculateAge(); + const patientFacility = "Dummy Facility 40"; const patientDateOfBirth = "01012001"; const patientOneName = "Patient With No Consultation"; const patientOneGender = "Male"; @@ -45,6 +53,10 @@ describe("Patient Creation with consultation", () => { const patientOneSecondPolicyId = "policy name 02"; const patientOneSecondInsurerId = "insurer id 02"; const patientOneSecondInsurerName = "insurer name 02"; + const patientTransferPhoneNumber = "9849511866"; + const patientTransferFacility = "Dummy Shifting Center"; + const patientTransferName = "Dummy Patient 10"; + const patientExternalName = "Patient 20"; before(() => { loginPage.loginAsDisctrictAdmin(); @@ -60,7 +72,7 @@ describe("Patient Creation with consultation", () => { it("Create a new patient with all field in registration form and no consultation", () => { // patient details with all the available fields except covid patientPage.createPatient(); - patientPage.selectFacility("Dummy Facility 40"); + patientPage.selectFacility(patientFacility); patientPage.patientformvisibility(); // Patient Details page patientPage.typePatientPhoneNumber(phone_number); @@ -75,16 +87,18 @@ describe("Patient Creation with consultation", () => { facilityPage.selectLocalBody(patientOneLocalbody); facilityPage.selectWard(patientOneWard); // Patient Medical History - patientPage.typePatientPresentHealth(patientOnePresentHealth); - patientPage.typePatientOngoingMedication(patientOneOngoingMedication); - patientPage.typeMedicalHistory(2, "Diabetes"); - patientPage.typeMedicalHistory(3, "Heart Disease"); - patientPage.typeMedicalHistory(4, "HyperTension"); - patientPage.typeMedicalHistory(5, "Kidney Diseases"); - patientPage.typeMedicalHistory(6, "Lung Diseases/Asthma"); - patientPage.typeMedicalHistory(7, "Cancer"); - patientPage.typeMedicalHistory(8, "Other"); - patientPage.typePatientAllergies(patientOneAllergies); + patientMedicalHistory.typePatientPresentHealth(patientOnePresentHealth); + patientMedicalHistory.typePatientOngoingMedication( + patientOneOngoingMedication + ); + patientMedicalHistory.typeMedicalHistory(2, "Diabetes"); + patientMedicalHistory.typeMedicalHistory(3, "Heart Disease"); + patientMedicalHistory.typeMedicalHistory(4, "HyperTension"); + patientMedicalHistory.typeMedicalHistory(5, "Kidney Diseases"); + patientMedicalHistory.typeMedicalHistory(6, "Lung Diseases/Asthma"); + patientMedicalHistory.typeMedicalHistory(7, "Cancer"); + patientMedicalHistory.typeMedicalHistory(8, "Other"); + patientMedicalHistory.typePatientAllergies(patientOneAllergies); patientPage.selectPatientBloodGroup(patientOneBloodGroup); patientPage.clickCreatePatient(); patientPage.verifyPatientIsCreated(); @@ -101,7 +115,7 @@ describe("Patient Creation with consultation", () => { yearOfBirth, patientOneBloodGroup ); - patientPage.verifyPatientMedicalDetails( + patientMedicalHistory.verifyPatientMedicalDetails( patientOnePresentHealth, patientOneOngoingMedication, patientOneAllergies, @@ -130,39 +144,47 @@ describe("Patient Creation with consultation", () => { patientPage.clickPatientAntenatalStatusYes(); patientPage.selectPatientBloodGroup(patientOneUpdatedBloodGroup); // Edit the patient consultation , select none medical history and multiple health ID - patientPage.clickNoneMedicialHistory(); - patientPage.clickAddInsruanceDetails(); - patientPage.typeSubscriberId( + patientMedicalHistory.clickNoneMedicialHistory(); + patientInsurance.clickAddInsruanceDetails(); + patientInsurance.typePatientInsuranceDetail( patientOneFirstInsuranceId, + "subscriber_id", patientOneFirstSubscriberId ); - patientPage.typePolicyId( + patientInsurance.typePatientInsuranceDetail( patientOneFirstInsuranceId, + "policy_id", patientOneFirstPolicyId ); - patientPage.typeInsurerId( + patientInsurance.typePatientInsuranceDetail( patientOneFirstInsuranceId, + "insurer_id", patientOneFirstInsurerId ); - patientPage.typeInsurerName( + patientInsurance.typePatientInsuranceDetail( patientOneFirstInsuranceId, + "insurer_name", patientOneFirstInsurerName ); - patientPage.clickAddInsruanceDetails(); - patientPage.typeSubscriberId( + patientInsurance.clickAddInsruanceDetails(); + patientInsurance.typePatientInsuranceDetail( patientOneSecondInsuranceId, + "subscriber_id", patientOneSecondSubscriberId ); - patientPage.typePolicyId( + patientInsurance.typePatientInsuranceDetail( patientOneSecondInsuranceId, + "policy_id", patientOneSecondPolicyId ); - patientPage.typeInsurerId( + patientInsurance.typePatientInsuranceDetail( patientOneSecondInsuranceId, + "insurer_id", patientOneSecondInsurerId ); - patientPage.typeInsurerName( + patientInsurance.typePatientInsuranceDetail( patientOneSecondInsuranceId, + "insurer_name", patientOneSecondInsurerName ); patientPage.clickUpdatePatient(); @@ -181,27 +203,27 @@ describe("Patient Creation with consultation", () => { patientOneUpdatedBloodGroup ); // Verify No medical history - patientPage.verifyNoSymptosPresent("Diabetes"); + patientMedicalHistory.verifyNoSymptosPresent("Diabetes"); // verify insurance details and dedicatd page cy.get("[data-testid=patient-details]") .contains(patientOneFirstSubscriberId) .scrollIntoView(); cy.wait(2000); - patientPage.verifyPatientPolicyDetails( + patientInsurance.verifyPatientPolicyDetails( patientOneFirstSubscriberId, patientOneFirstPolicyId, patientOneFirstInsurerId, patientOneFirstInsurerName ); - patientPage.clickPatientInsuranceViewDetail(); + patientInsurance.clickPatientInsuranceViewDetail(); cy.wait(3000); - patientPage.verifyPatientPolicyDetails( + patientInsurance.verifyPatientPolicyDetails( patientOneFirstSubscriberId, patientOneFirstPolicyId, patientOneFirstInsurerId, patientOneFirstInsurerName ); - patientPage.verifyPatientPolicyDetails( + patientInsurance.verifyPatientPolicyDetails( patientOneSecondSubscriberId, patientOneSecondPolicyId, patientOneSecondInsurerId, @@ -209,48 +231,59 @@ describe("Patient Creation with consultation", () => { ); }); - it("Create a New consultation to existing patient", () => { - patientPage.interceptFacilities(); - patientPage.visitConsultationPage(); - patientPage.verifyStatusCode(); - patientConsultationPage.fillIllnessHistory("history"); - patientConsultationPage.selectConsultationStatus( - "Outpatient/Emergency Room" - ); - patientConsultationPage.selectSymptoms("ASYMPTOMATIC"); - - patientConsultationPage.enterConsultationDetails( - "Stable", - "Examination details and Clinical conditions", - "70", - "170", - "IP007", - "generalnote", - "Dev Doctor" - ); - patientConsultationPage.submitConsultation(); - - // Below code for the prescription module only present while creating a new consultation - patientConsultationPage.clickAddPrescription(); - patientConsultationPage.interceptMediaBase(); - patientConsultationPage.selectMedicinebox(); - patientConsultationPage.waitForMediabaseStatusCode(); - patientConsultationPage.prescribefirstMedicine(); - patientConsultationPage.enterDosage("3"); - patientConsultationPage.selectDosageFrequency("Twice daily"); - patientConsultationPage.submitPrescriptionAndReturn(); + it("Patient Registration using the transfer with no consultation", () => { + // transfer the patient and no consulation + patientPage.createPatient(); + patientPage.selectFacility(patientTransferFacility); + patientPage.patientformvisibility(); + patientPage.typePatientPhoneNumber(patientTransferPhoneNumber); + patientTransfer.clickAdmitPatientRecordButton(); + patientTransfer.clickTransferPopupContinueButton(); + patientTransfer.clickTransferPatientNameList(patientTransferName); + patientTransfer.clickTransferPatientDob(patientDateOfBirth); + patientTransfer.clickTransferSubmitButton(); + patientTransfer.verifyFacilitySuccessfullMessage(); + patientTransfer.clickConsultationCancelButton(); + cy.wait(3000); + // allow the transfer button of a patient + patientTransfer.clickAllowPatientTransferButton(); + // Verify the patient error message for the same facility + cy.awaitUrl("/patients"); + patientPage.createPatient(); + patientPage.selectFacility(patientTransferFacility); + patientPage.patientformvisibility(); + patientPage.typePatientPhoneNumber(patientTransferPhoneNumber); + patientTransfer.clickAdmitPatientRecordButton(); + patientTransfer.clickTransferPopupContinueButton(); + patientTransfer.clickTransferPatientNameList(patientTransferName); + patientTransfer.clickTransferPatientDob(patientDateOfBirth); + patientTransfer.clickTransferSubmitButton(); + patientTransfer.verifyFacilityErrorMessage(); }); - it("Edit created consultation to existing patient", () => { - patientPage.visitPatientUrl(); - patientConsultationPage.visitEditConsultationPage(); - patientConsultationPage.fillIllnessHistory("editted"); - patientConsultationPage.updateSymptoms("FEVER"); - patientConsultationPage.setSymptomsDate("01082023"); - patientConsultationPage.updateConsultation(); - patientConsultationPage.verifySuccessNotification( - "Consultation updated successfully" - ); + it("Patient Registration using External Result Import", () => { + // copy the patient external ID from external results + cy.awaitUrl("/external_results"); + patientExternal.verifyExternalListPatientName(patientExternalName); + patientExternal.verifyExternalIdVisible(); + // cypress have a limitation to work only asynchronously + // import the result and create a new patient + let extractedId = ""; + cy.get("#patient-external-id") + .invoke("text") + .then((text) => { + extractedId = text.split("Care external results ID: ")[1]; + cy.log(`Extracted Care external results ID: ${extractedId}`); + cy.awaitUrl("/patients"); + patientPage.createPatient(); + patientPage.selectFacility(patientFacility); + patientPage.patientformvisibility(); + patientExternal.clickImportFromExternalResultsButton(); + patientExternal.typeCareExternalResultId(extractedId); + patientExternal.clickImportPatientData(); + }); + // verify the patient is successfully created + patientExternal.verifyExternalPatientName(patientExternalName); }); afterEach(() => { diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index 8570b2b8e7a..76724d85017 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -17,6 +17,10 @@ export class PatientConsultationPage { }); } + verifyConsultationPatientName(patientName: string) { + cy.get("#patient-name-consultation").should("contain", patientName); + } + fillIllnessHistory(history: string) { cy.wait(5000); cy.get("#history_of_present_illness").scrollIntoView(); @@ -145,9 +149,11 @@ export class PatientConsultationPage { cy.wait("@submitPrescription").its("response.statusCode").should("eq", 201); } - visitEditConsultationPage() { - cy.get("#view_consulation_updates").click(); - cy.get("button").contains("Edit Consultation Details").click(); + clickEditConsultationButton() { + cy.get("#consultation-buttons").scrollIntoView(); + cy.get("#consultation-buttons") + .contains("Edit Consultation Details") + .click(); } setSymptomsDate(date: string) { diff --git a/cypress/pageobject/Patient/PatientCreation.ts b/cypress/pageobject/Patient/PatientCreation.ts index 0cf8abd4afa..07d87e024a1 100644 --- a/cypress/pageobject/Patient/PatientCreation.ts +++ b/cypress/pageobject/Patient/PatientCreation.ts @@ -72,18 +72,6 @@ export class PatientPage { .type(address); } - typePatientPresentHealth(presentHealth: string) { - cy.get("#present_health").click().type(presentHealth); - } - - typePatientOngoingMedication(ongoingMedication: string) { - cy.get("#ongoing_medication").click().type(ongoingMedication); - } - - typePatientAllergies(allergies: string) { - cy.get("#allergies").click().type(allergies); - } - clickPermanentAddress() { cy.get("[data-testid=permanent-address] input").check(); } @@ -92,48 +80,10 @@ export class PatientPage { cy.get("#is_antenatal-0").click(); } - clickAddInsruanceDetails() { - cy.get("[data-testid=add-insurance-button]").click(); - } - - typeSubscriberId(id: string, subscriberId: string) { - cy.get(`#${id}`).within(() => { - cy.get("#subscriber_id").clear().type(subscriberId); - }); - } - - typePolicyId(id: string, policyid: string) { - cy.get(`#${id}`).within(() => { - cy.get("#policy_id").click().type(policyid); - }); - } - - typeInsurerId(id: string, insurerid: string) { - cy.get(`#${id}`).within(() => { - cy.get("#insurer_id").click().type(insurerid); - }); - } - - typeInsurerName(id: string, insurername: string) { - cy.get(`#${id}`).within(() => { - cy.get("#insurer_name").click().type(insurername); - }); - } - - clickNoneMedicialHistory() { - cy.get("[name=medical_history_check_1]").scrollIntoView(); - cy.get("[name=medical_history_check_1]").check(); - } - clickCancelButton() { cy.get("#cancel").click(); } - typeMedicalHistory(index, text) { - cy.get(`#medical_history_check_${index}`).click(); - cy.get(`#medical_history_${index}`).click().type(text); - } - selectPatientGender(gender: string) { cy.get("[data-testid=Gender] button") .click() @@ -229,55 +179,6 @@ export class PatientPage { }); } - verifyPatientMedicalDetails( - patientPresentHealth, - patientOngoingMedication, - patientAllergies, - patientSymptoms1, - patientSymptoms2, - patientSymptoms3, - patientSymptoms4, - patientSymptoms5, - patientSymptoms6, - patientSymptoms7 - ) { - cy.get("[data-testid=patient-details]").then(($dashboard) => { - cy.url().should("include", "/facility/"); - expect($dashboard).to.contain(patientPresentHealth); - expect($dashboard).to.contain(patientOngoingMedication); - expect($dashboard).to.contain(patientAllergies); - expect($dashboard).to.contain(patientSymptoms1); - expect($dashboard).to.contain(patientSymptoms2); - expect($dashboard).to.contain(patientSymptoms3); - expect($dashboard).to.contain(patientSymptoms4); - expect($dashboard).to.contain(patientSymptoms5); - expect($dashboard).to.contain(patientSymptoms6); - expect($dashboard).to.contain(patientSymptoms7); - }); - } - - verifyPatientPolicyDetails(subscriberId, policyId, insurerId, insurerName) { - cy.get("[data-testid=patient-details]").then(($dashboard) => { - cy.url().should("include", "/facility/"); - expect($dashboard).to.contain(subscriberId); - expect($dashboard).to.contain(policyId); - expect($dashboard).to.contain(insurerId); - expect($dashboard).to.contain(insurerName); - }); - } - - clickPatientInsuranceViewDetail() { - cy.get("#insurance-view-details").scrollIntoView(); - cy.get("#insurance-view-details").click(); - } - - verifyNoSymptosPresent(patientSymptoms1: string) { - cy.get("[data-testid=patient-details]").should( - "not.contain", - patientSymptoms1 - ); - } - visitUpdatePatientUrl() { cy.visit(patient_url + "/update"); } diff --git a/cypress/pageobject/Patient/PatientExternal.ts b/cypress/pageobject/Patient/PatientExternal.ts new file mode 100644 index 00000000000..138c212a377 --- /dev/null +++ b/cypress/pageobject/Patient/PatientExternal.ts @@ -0,0 +1,28 @@ +class PatientExternal { + verifyExternalListPatientName(patientName: string) { + cy.get("#external-result-table").contains(patientName).click(); + } + + verifyExternalIdVisible() { + cy.get("#patient-external-id").contains("Care external results ID"); + } + + clickImportFromExternalResultsButton() { + cy.get("#import-externalresult-button").click(); + } + + typeCareExternalResultId(externalId) { + cy.get("#care-external-results-id").scrollIntoView(); + cy.get("#care-external-results-id").should("be.visible"); + cy.get("#care-external-results-id").type(externalId); + } + + clickImportPatientData() { + cy.get("#submit-importexternalresult-button").click(); + } + + verifyExternalPatientName(patientName: string) { + cy.get("#name", { timeout: 10000 }).should("have.value", patientName); + } +} +export default PatientExternal; diff --git a/cypress/pageobject/Patient/PatientInsurance.ts b/cypress/pageobject/Patient/PatientInsurance.ts new file mode 100644 index 00000000000..be4c25c5535 --- /dev/null +++ b/cypress/pageobject/Patient/PatientInsurance.ts @@ -0,0 +1,32 @@ +class PatientInsurance { + typePatientInsuranceDetail( + containerId: string, + fieldId: string, + value: string + ) { + cy.get(`#${containerId}`).within(() => { + cy.get(`#${fieldId}`).click().type(value); + }); + } + + clickPatientInsuranceViewDetail() { + cy.get("#insurance-view-details").scrollIntoView(); + cy.get("#insurance-view-details").click(); + } + + clickAddInsruanceDetails() { + cy.get("[data-testid=add-insurance-button]").click(); + } + + verifyPatientPolicyDetails(subscriberId, policyId, insurerId, insurerName) { + cy.get("[data-testid=patient-details]").then(($dashboard) => { + cy.url().should("include", "/facility/"); + expect($dashboard).to.contain(subscriberId); + expect($dashboard).to.contain(policyId); + expect($dashboard).to.contain(insurerId); + expect($dashboard).to.contain(insurerName); + }); + } +} + +export default PatientInsurance; diff --git a/cypress/pageobject/Patient/PatientMedicalHistory.ts b/cypress/pageobject/Patient/PatientMedicalHistory.ts new file mode 100644 index 00000000000..1c9b733f3ba --- /dev/null +++ b/cypress/pageobject/Patient/PatientMedicalHistory.ts @@ -0,0 +1,59 @@ +class PatientMedicalHistory { + typePatientOngoingMedication(ongoingMedication: string) { + cy.get("#ongoing_medication").click().type(ongoingMedication); + } + + typePatientPresentHealth(presentHealth: string) { + cy.get("#present_health").click().type(presentHealth); + } + + typePatientAllergies(allergies: string) { + cy.get("#allergies").click().type(allergies); + } + + typeMedicalHistory(index, text) { + cy.get(`#medical_history_check_${index}`).click(); + cy.get(`#medical_history_${index}`).click().type(text); + } + + clickNoneMedicialHistory() { + cy.get("[name=medical_history_check_1]").scrollIntoView(); + cy.get("[name=medical_history_check_1]").check(); + } + + verifyPatientMedicalDetails( + patientPresentHealth, + patientOngoingMedication, + patientAllergies, + patientSymptoms1, + patientSymptoms2, + patientSymptoms3, + patientSymptoms4, + patientSymptoms5, + patientSymptoms6, + patientSymptoms7 + ) { + cy.get("[data-testid=patient-details]").then(($dashboard) => { + cy.url().should("include", "/facility/"); + expect($dashboard).to.contain(patientPresentHealth); + expect($dashboard).to.contain(patientOngoingMedication); + expect($dashboard).to.contain(patientAllergies); + expect($dashboard).to.contain(patientSymptoms1); + expect($dashboard).to.contain(patientSymptoms2); + expect($dashboard).to.contain(patientSymptoms3); + expect($dashboard).to.contain(patientSymptoms4); + expect($dashboard).to.contain(patientSymptoms5); + expect($dashboard).to.contain(patientSymptoms6); + expect($dashboard).to.contain(patientSymptoms7); + }); + } + + verifyNoSymptosPresent(patientSymptoms1: string) { + cy.get("[data-testid=patient-details]").should( + "not.contain", + patientSymptoms1 + ); + } +} + +export default PatientMedicalHistory; diff --git a/cypress/pageobject/Patient/PatientTransfer.ts b/cypress/pageobject/Patient/PatientTransfer.ts new file mode 100644 index 00000000000..293490a8bdd --- /dev/null +++ b/cypress/pageobject/Patient/PatientTransfer.ts @@ -0,0 +1,63 @@ +class PatientTransfer { + clickAdmitPatientRecordButton() { + cy.get("#transfer").click(); + } + + clickTransferPopupContinueButton() { + cy.get("#submit-continue-button").click(); + } + + clickTransferPatientNameList(facilityName: string) { + cy.get("#patient").click(); + cy.get("li[role=option]").contains(facilityName).click(); + } + + clickTransferPatientDob(dateOfBirth: string) { + cy.get("#dateofbirth-transferform").scrollIntoView(); + cy.get("#dateofbirth-transferform").should("be.visible").click(); + cy.get("#date-input").click().type(dateOfBirth); + } + + clickTransferSubmitButton() { + cy.get("#submit-transferpatient").click(); + } + + clickConsultationCancelButton() { + cy.get("#cancel").scrollIntoView(); + cy.get("#cancel").click(); + } + + clickAllowPatientTransferButton() { + cy.get("#patient-allow-transfer").click(); + } + + verifyFacilitySuccessfullMessage() { + cy.get(".pnotify") + .should("exist") + .within(() => { + cy.get(".pnotify-text") + .invoke("text") + .then((text) => { + expect(text.trim()).to.match( + /^Patient Dummy Patient 10 \(Male\) transferred successfully$/i + ); + }); + }); + } + + verifyFacilityErrorMessage() { + cy.get(".pnotify") + .should("exist") + .within(() => { + cy.get(".pnotify-text") + .invoke("text") + .then((text) => { + expect(text).to.match( + /Patient - Patient transfer cannot be completed because the patient has an active consultation in the same facility/ + ); + }); + }); + } +} + +export default PatientTransfer; diff --git a/src/Components/ExternalResult/ResultItem.tsx b/src/Components/ExternalResult/ResultItem.tsx index 47363e02ce1..0954f704176 100644 --- a/src/Components/ExternalResult/ResultItem.tsx +++ b/src/Components/ExternalResult/ResultItem.tsx @@ -77,13 +77,18 @@ export default function ResultItem(props: any) {

- {resultItemData.name} - {resultItemData.age}{" "} - {resultItemData.age_in} | {resultItemData.result} + {resultItemData.name} -{" "} + {resultItemData.age}{" "} + {resultItemData.age_in} |{" "} + {resultItemData.result}

{t("srf_id")}: {resultItemData.srf_id}

-

+

{t("care_external_results_id")}: {resultItemData.id}

{resultItemData.patient_created ? ( diff --git a/src/Components/ExternalResult/ResultList.tsx b/src/Components/ExternalResult/ResultList.tsx index f644c2b54e0..82a49e3a8e3 100644 --- a/src/Components/ExternalResult/ResultList.tsx +++ b/src/Components/ExternalResult/ResultList.tsx @@ -318,7 +318,10 @@ export default function ResultList() { ]} /> -
+
diff --git a/src/Components/Facility/DuplicatePatientDialog.tsx b/src/Components/Facility/DuplicatePatientDialog.tsx index 46eb4e2dd7a..7a36beac685 100644 --- a/src/Components/Facility/DuplicatePatientDialog.tsx +++ b/src/Components/Facility/DuplicatePatientDialog.tsx @@ -119,6 +119,7 @@ const DuplicatePatientDialog = (props: Props) => { label={`Cancel ${isNew ? "Registration" : "Update"}`} /> handleOk(action)} disabled={!action} label="Continue" diff --git a/src/Components/Facility/TransferPatientDialog.tsx b/src/Components/Facility/TransferPatientDialog.tsx index e6133279a9e..259d497f684 100644 --- a/src/Components/Facility/TransferPatientDialog.tsx +++ b/src/Components/Facility/TransferPatientDialog.tsx @@ -175,6 +175,7 @@ const TransferPatientDialog = (props: Props) => {
{
{
)} -
+
{!!consultation?.discharge_date && (
diff --git a/src/Components/Patient/PatientRegister.tsx b/src/Components/Patient/PatientRegister.tsx index ce63d5019de..2f18ef36dbb 100644 --- a/src/Components/Patient/PatientRegister.tsx +++ b/src/Components/Patient/PatientRegister.tsx @@ -1126,6 +1126,7 @@ export const PatientRegister = (props: PatientRegisterProps) => { />
- -
+
+
+ + +
+ +
+

+ {consultationData?.facility_name ?? ""} +

-
-

- {consultationData.facility_name} -

+

INTERIM TREATMENT SUMMARY

-

INTERIM TREATMENT SUMMARY

+
{formatDate(date)}
-
{formatDate(date)}
+
+
+
+ Name : {patientData?.name ?? ""} +
+
+ Address : {patientData?.address ?? ""} +
+
-
-
+
+
- Name : {patientData.name} + Age :{" "} + {formatAge( + patientData?.age ?? 0, + patientData?.date_of_birth ?? "", + true + )}
-
- Address : {patientData.address} +
+ OP : {consultationData?.patient_no ?? ""}
-
-
-
- Age :{" "} - {formatAge( - patientData.age, - patientData.date_of_birth, - true - )} -
-
- OP : {consultationData.patient_no} -
-
- -
- Date of admission : - - {consultationData.admitted - ? formatDateTime(consultationData.encounter_date) - : " --/--/----"} - -
+
+ Date of admission : + + {consultationData?.admitted + ? formatDateTime(consultationData.encounter_date) + : " --/--/----"} +
+
-
-
- Gender : - {GENDER_TYPES.find((i) => i.id === patientData.gender)?.text} -
+
+
+ Gender : + {GENDER_TYPES.find((i) => i.id === patientData?.gender)?.text} +
-
- Contact person : - - {" "} - {patientData.emergency_phone_number - ? patientData.emergency_phone_number - : " -"} - -
+
+ Contact person : + + {" "} + {patientData?.emergency_phone_number + ? patientData.emergency_phone_number + : " -"} +
+
-
- Comorbidities : -
-
- +
+ Comorbidities : +
+
+ + + + + + + + {patientData?.medical_history && + patientData.medical_history.length > 0 ? ( + patientData.medical_history.map( + (obj: any, index: number) => { + return ( + + + + + ); + } + ) + ) : ( - - + + - - - {patientData.medical_history && - patientData.medical_history.length > 0 ? ( - patientData.medical_history.map( - (obj: any, index: number) => { - return ( - - - - - ); - } - ) - ) : ( - - - - - )} - -
DiseaseDetails
+ {obj["disease"]} + + {obj["details"] ? obj["details"] : "---"} +
DiseaseDetails + --- + + --- +
- {obj["disease"]} - - {obj["details"] ? obj["details"] : "---"} -
- --- - - --- -
-
+ )} + +
+
-
- Diagnosis : -
-
- History of present illness : - {consultationData.history_of_present_illness - ? consultationData.history_of_present_illness - : " ---"} -
+
+ Diagnosis : +
+
+ History of present illness : + {consultationData?.history_of_present_illness + ? consultationData.history_of_present_illness + : " ---"} +
-
- Examination details and clinical conditions : - {consultationData.examination_details - ? consultationData.examination_details - : " ---"} -
+
+ Examination details and clinical conditions : + {consultationData?.examination_details + ? consultationData.examination_details + : " ---"} +
-
- Physical Examination info : - {dailyRounds.physical_examination_info - ? dailyRounds.physical_examination_info - : " ---"} -
+
+ Physical Examination info : + {consultationData?.last_daily_round?.physical_examination_info + ? consultationData.last_daily_round + ?.physical_examination_info + : " ---"}
+
-
- General Instructions : - {patientData?.last_consultation?.consultation_notes ? ( -
- {patientData.last_consultation.consultation_notes} -
- ) : ( - " ---" - )} -
+
+ General Instructions : + {patientData?.last_consultation?.consultation_notes ? ( +
+ {patientData.last_consultation.consultation_notes} +
+ ) : ( + " ---" + )} +
+ +
+ Relevant investigations : -
- Relevant investigations : +
+ + + + + + + + + + + -
-
+ Date + + Name + + Result + + Ideal value + + values range + + unit +
- + + {investigations && investigations.results.length > 0 ? ( + investigations.results.map( + (value: any, index: number) => { + return ( + + + + + + + + + ); + } + ) + ) : ( - - - - - - + + + + + + - - - - {Object.values(investigations).length > 0 ? ( - Object.values(investigations).map( - (value: any, index: number) => { - return ( - - - - - - - - - ); - } - ) - ) : ( - - - - - - - - - )} - -
+ {formatDate( + value["session_object"][ + "session_created_date" + ] + )} + + {value["investigation_object"]["name"]} + + {value["notes"] || value["value"]} + + {value["investigation_object"]["ideal_value"] || + "-"} + + {value["investigation_object"]["min_value"]} -{" "} + {value["investigation_object"]["max_value"]} + + {value["investigation_object"]["unit"] || "-"} +
- Date - - Name - - Result - - Ideal value - - values range - - unit - + --- + + --- + + --- + + --- + + --- + + --- +
- {formatDate( - value["session_object"][ - "session_created_date" - ] - )} - - {value["investigation_object"]["name"]} - - {value["notes"] || value["value"]} - - {value["investigation_object"][ - "ideal_value" - ] || "-"} - - {value["investigation_object"]["min_value"]} -{" "} - {value["investigation_object"]["max_value"]} - - {value["investigation_object"]["unit"] || "-"} -
- --- - - --- - - --- - - --- - - --- - - --- -
-
+ )} + +
+
-
- Treatment : - {consultationData.treatment_plan ? ( -

{consultationData.treatment_plan}

- ) : ( -

---

- )} - Treatment summary/Treament Plan : +
+ Treatment : + {consultationData?.treatment_plan ? ( +

{consultationData.treatment_plan}

+ ) : ( +

---

+ )} + Treatment summary/Treament Plan : -
- - +
+
+ + + + + + + + + + {consultationData?.last_daily_round ? ( - - - + + + - - - - {dailyRounds ? ( - - - - - - ) : ( - - - - - - )} - -
DateSpo2Temperature
DateSpo2Temperature + {formatDateTime( + consultationData.last_daily_round.modified_date + )} + + {consultationData.last_daily_round.ventilator_spo2 || + "-"} + + {consultationData.last_daily_round.temperature || "-"} +
- {formatDateTime(dailyRounds.modified_date)} - - {dailyRounds.ventilator_spo2 || "-"} - - {dailyRounds.temperature || "-"} -
- --- - - --- - - --- -
-
+ ) : ( + + + --- + + + --- + + + --- + + + )} + +
- )} +
); }; diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index 999c54a2e3a..de035f9ffea 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -572,3 +572,10 @@ export type InventoryLogResponse = InventorySummaryResponse & { unit: number; created_by: number; }; + +export type PatientTransferResponse = { + id: string; + patient: string; + date_of_birth: string; + facility_object: BaseFacilityModel; +}; diff --git a/src/Redux/actions.tsx b/src/Redux/actions.tsx index 8e3ae382547..280abbce5cc 100644 --- a/src/Redux/actions.tsx +++ b/src/Redux/actions.tsx @@ -102,9 +102,7 @@ export const updatePatient = (params: object, pathParam: object) => { export const patchPatient = (params: object, pathParam: object) => { return fireRequest("patchPatient", [], params, pathParam); }; -export const transferPatient = (params: object, pathParam: object) => { - return fireRequest("transferPatient", [], params, pathParam); -}; + export const getStates = () => { return fireRequest("statesList", []); }; diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index 6425ff8eab0..eed17ad3b4b 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -55,6 +55,7 @@ import { InventorySummaryResponse, InventoryLogResponse, InventoryItemsModel, + PatientTransferResponse, } from "../Components/Facility/models"; import { IDeleteBedCapacity, @@ -86,6 +87,7 @@ import { InvestigationGroup, InvestigationType, } from "../Components/Facility/Investigations"; +import { Investigation } from "../Components/Facility/Investigations/Reports/types"; import { ICD11DiagnosisModel } from "../Components/Diagnosis/types"; /** @@ -657,6 +659,7 @@ const routes = { transferPatient: { path: "/api/v1/patient/{id}/transfer/", method: "POST", + TRes: Type(), }, getPatientNotes: { path: "/api/v1/patient/{patientId}/notes/", @@ -998,6 +1001,7 @@ const routes = { getInvestigation: { path: "/api/v1/consultation/{consultation_external_id}/investigation/", method: "GET", + TRes: Type>(), }, getPatientInvestigation: { path: "/api/v1/patient/{patient_external_id}/investigation/", From 1dd0ada4312dd3c4d443e6907c2e239dfa39b84b Mon Sep 17 00:00:00 2001 From: Kshitij Verma <101321276+kshitijv256@users.noreply.github.com> Date: Wed, 7 Feb 2024 01:08:37 +0530 Subject: [PATCH 11/19] only loading discontinued prescriptions instead of all prescriptions (#7071) * only loading discontinued prescriptions instead of all prescriptions * removed useEffect hook --- .../MedicineAdministrationSheet/index.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Components/Medicine/MedicineAdministrationSheet/index.tsx b/src/Components/Medicine/MedicineAdministrationSheet/index.tsx index e94d740c0db..dba0943db20 100644 --- a/src/Components/Medicine/MedicineAdministrationSheet/index.tsx +++ b/src/Components/Medicine/MedicineAdministrationSheet/index.tsx @@ -33,7 +33,7 @@ const MedicineAdministrationSheet = ({ readonly, is_prn }: Props) => { MedicineRoutes.listPrescriptions, { pathParams: { consultation }, - query: { ...filters, discontinued: showDiscontinued ? undefined : false }, + query: { ...filters, discontinued: false }, } ); @@ -41,7 +41,7 @@ const MedicineAdministrationSheet = ({ readonly, is_prn }: Props) => { pathParams: { consultation }, query: { ...filters, - limit: showDiscontinued ? 100 : 1, + limit: 100, discontinued: true, }, prefetch: !showDiscontinued, @@ -49,16 +49,21 @@ const MedicineAdministrationSheet = ({ readonly, is_prn }: Props) => { const discontinuedCount = discontinuedPrescriptions.data?.count; + const prescriptionList = [ + ...(data?.results ?? []), + ...(showDiscontinued ? discontinuedPrescriptions.data?.results ?? [] : []), + ]; + const { activityTimelineBounds, prescriptions } = useMemo( () => ({ - prescriptions: data?.results?.sort( + prescriptions: prescriptionList.sort( (a, b) => +a.discontinued - +b.discontinued ), - activityTimelineBounds: data - ? computeActivityBounds(data.results) + activityTimelineBounds: prescriptionList + ? computeActivityBounds(prescriptionList) : undefined, }), - [data] + [prescriptionList] ); const daysPerPage = useBreakpoints({ default: 1, "2xl": 2 }); From e9f3cc5c1dc6e9447eead50e0d006c6ced231673 Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:13:26 +0530 Subject: [PATCH 12/19] Redesign Patient Info Card (#7077) * Redesign Patient Info Card * Responsive view * Fix null reference exception in LegacyDiagnosesList.tsx * Fix Cypress * Update click selector for "Edit Consultation Details" button * Remove unnecessary center alignment in PatientInfoCard * Refactor LegacyDiagnosesList component and remove unused imports * Redesign diagnosis list * Refactor to use tailwind classes * Make hide diagnoses less intrusive * Add "Manage Patient" button click in clickEditConsultationButton method --- .../pageobject/Patient/PatientConsultation.ts | 1 + .../Common/RelativeDateUserMention.tsx | 5 +- .../Common/components/AccordionV2.tsx | 12 +- .../Diagnosis/DiagnosesListAccordion.tsx | 102 ++++ .../Diagnosis/LegacyDiagnosesList.tsx | 87 ---- .../ConsultationUpdatesTab.tsx | 107 ++-- .../Facility/ConsultationDetails/index.tsx | 87 +--- .../Facility/Consultations/Mews.tsx | 66 ++- src/Components/Patient/PatientInfoCard.tsx | 490 ++++++++++-------- src/Utils/utils.ts | 6 +- 10 files changed, 508 insertions(+), 455 deletions(-) create mode 100644 src/Components/Diagnosis/DiagnosesListAccordion.tsx delete mode 100644 src/Components/Diagnosis/LegacyDiagnosesList.tsx diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index 76724d85017..bc2e8f330a3 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -151,6 +151,7 @@ export class PatientConsultationPage { clickEditConsultationButton() { cy.get("#consultation-buttons").scrollIntoView(); + cy.get("button").contains("Manage Patient").click(); cy.get("#consultation-buttons") .contains("Edit Consultation Details") .click(); diff --git a/src/Components/Common/RelativeDateUserMention.tsx b/src/Components/Common/RelativeDateUserMention.tsx index 18fb431574f..6c5a78c7f09 100644 --- a/src/Components/Common/RelativeDateUserMention.tsx +++ b/src/Components/Common/RelativeDateUserMention.tsx @@ -6,6 +6,7 @@ function RelativeDateUserMention(props: { actionDate?: string; user?: PerformedByModel; tooltipPosition?: "top" | "bottom" | "left" | "right"; + withoutSuffix?: boolean; }) { return (
@@ -15,7 +16,9 @@ function RelativeDateUserMention(props: { > {props.actionDate ? formatDateTime(props.actionDate) : "--:--"} - {props.actionDate ? relativeDate(props.actionDate) : "--:--"} + {props.actionDate + ? relativeDate(props.actionDate, props.withoutSuffix ?? false) + : "--:--"}
{props.user && (
diff --git a/src/Components/Common/components/AccordionV2.tsx b/src/Components/Common/components/AccordionV2.tsx index ef4948d8ae3..b8fa441d277 100644 --- a/src/Components/Common/components/AccordionV2.tsx +++ b/src/Components/Common/components/AccordionV2.tsx @@ -1,5 +1,4 @@ import { useRef, useState } from "react"; -import { classNames } from "../../../Utils/utils"; export default function AccordionV2(props: { children: JSX.Element | JSX.Element[]; @@ -55,15 +54,10 @@ export default function AccordionV2(props: {
{props.children}
diff --git a/src/Components/Diagnosis/DiagnosesListAccordion.tsx b/src/Components/Diagnosis/DiagnosesListAccordion.tsx new file mode 100644 index 00000000000..5f339cabc16 --- /dev/null +++ b/src/Components/Diagnosis/DiagnosesListAccordion.tsx @@ -0,0 +1,102 @@ +import { + ActiveConditionVerificationStatuses, + ConditionVerificationStatus, + ConsultationDiagnosis, +} from "./types"; +import { useTranslation } from "react-i18next"; +import { compareBy } from "../../Utils/utils"; +import { useState } from "react"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import ButtonV2 from "../Common/components/ButtonV2"; + +interface Props { + diagnoses: ConsultationDiagnosis[]; +} + +type GroupedDiagnoses = Record< + ConditionVerificationStatus, + ConsultationDiagnosis[] +>; + +function groupDiagnoses(diagnoses: ConsultationDiagnosis[]) { + const groupedDiagnoses = {} as GroupedDiagnoses; + + for (const status of ActiveConditionVerificationStatuses) { + groupedDiagnoses[status] = diagnoses + .filter((d) => d.verification_status === status) + .sort(compareBy("is_principal")); + } + + return groupedDiagnoses; +} + +export default function DiagnosesListAccordion(props: Props) { + const [isVisible, setIsVisible] = useState(true); + const diagnoses = groupDiagnoses(props.diagnoses); + + return ( +
+
+ {!isVisible && ( + { + setIsVisible((prev) => !prev); + }} + > + + Expand Diagnoses + + )} +
+
+

+ Diagnoses +

+
+ {Object.entries(diagnoses).map( + ([status, diagnoses]) => + !!diagnoses.length && ( + + ) + )} +
+ { + setIsVisible(false); + }} + > + + Hide Diagnoses + +
+
+ ); +} + +const DiagnosesOfStatus = ({ diagnoses }: Props) => { + const { t } = useTranslation(); + + return ( +
+

+ {t(diagnoses[0].verification_status)} {t("diagnoses")}{" "} + ({t("icd11_as_recommended")}) +

+
    + {diagnoses.map((diagnosis) => ( +
  • + {diagnosis.diagnosis_object?.label} +
  • + ))} +
+
+ ); +}; diff --git a/src/Components/Diagnosis/LegacyDiagnosesList.tsx b/src/Components/Diagnosis/LegacyDiagnosesList.tsx deleted file mode 100644 index 408bee7b52a..00000000000 --- a/src/Components/Diagnosis/LegacyDiagnosesList.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { useState } from "react"; -import { - ActiveConditionVerificationStatuses, - ConditionVerificationStatus, - ConsultationDiagnosis, -} from "./types"; -import { useTranslation } from "react-i18next"; -import CareIcon from "../../CAREUI/icons/CareIcon"; -import { compareBy } from "../../Utils/utils"; - -interface Props { - diagnoses: ConsultationDiagnosis[]; -} - -type GroupedDiagnoses = Record< - ConditionVerificationStatus, - ConsultationDiagnosis[] ->; - -function groupDiagnoses(diagnoses: ConsultationDiagnosis[]) { - const groupedDiagnoses = {} as GroupedDiagnoses; - - for (const status of ActiveConditionVerificationStatuses) { - groupedDiagnoses[status] = diagnoses - .filter((d) => d.verification_status === status) - .sort(compareBy("is_principal")); - } - - return groupedDiagnoses; -} - -export default function LegacyDiagnosesList(props: Props) { - const diagnoses = groupDiagnoses(props.diagnoses); - - return ( -
- {Object.entries(diagnoses).map( - ([status, diagnoses]) => - !!diagnoses.length && ( - - ) - )} -
- ); -} - -const DefaultShowLimit = 3; - -const DiagnosesOfStatus = ({ diagnoses }: Props) => { - const { t } = useTranslation(); - const [showMore, setShowMore] = useState(false); - - const queryset = showMore ? diagnoses : diagnoses.slice(0, DefaultShowLimit); - - return ( -
-

- {t(queryset[0].verification_status)} {t("diagnoses")}{" "} - ({t("icd11_as_recommended")}) -

-
    - {queryset.map((diagnosis) => ( -
  • - {diagnosis.diagnosis_object.label} - {diagnosis.is_principal && ( - - - {t("principal")} - - )} -
  • - ))} -
- - {diagnoses.length > DefaultShowLimit && ( - setShowMore(!showMore)} - className="cursor-pointer text-sm text-blue-600 hover:text-blue-300" - > - {showMore - ? t("hide") - : `... and ${diagnoses.length - queryset.length} more.`} - - )} -
- ); -}; diff --git a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx index 4158d7f6609..323715ccfb0 100644 --- a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx +++ b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx @@ -342,7 +342,7 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => { from{" "} {formatDate( - props.consultationData.last_daily_round.created_at + props.consultationData.last_daily_round.taken_at )} @@ -602,58 +602,59 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => { )} - -
-
-

- Body Details -

-
-
- Gender {" - "} - - {props.patientData.gender ?? "-"} - -
-
- Age {" - "} - - {props.patientData.age !== undefined // 0 is a valid age, so we need to check for undefined - ? formatAge( - props.patientData.age, - props.patientData.date_of_birth - ) - : "-"} - -
-
- Weight {" - "} - - {props.consultationData.weight ?? "-"} Kg - -
-
- Height {" - "} - - {props.consultationData.height ?? "-"} cm - -
-
- Body Surface Area {" - "} - - {Math.sqrt( - (Number(props.consultationData.weight) * - Number(props.consultationData.height)) / - 3600 - ).toFixed(2)}{" "} - m2 - -
-
- Blood Group {" - "} - - {props.patientData.blood_group ?? "-"} - +
+
+
+

+ Body Details +

+
+
+ Gender {" - "} + + {props.patientData.gender ?? "-"} + +
+
+ Age {" - "} + + {props.patientData.age !== undefined // 0 is a valid age, so we need to check for undefined + ? formatAge( + props.patientData.age, + props.patientData.date_of_birth + ) + : "-"} + +
+
+ Weight {" - "} + + {props.consultationData.weight ?? "-"} Kg + +
+
+ Height {" - "} + + {props.consultationData.height ?? "-"} cm + +
+
+ Body Surface Area {" - "} + + {Math.sqrt( + (Number(props.consultationData.weight) * + Number(props.consultationData.height)) / + 3600 + ).toFixed(2)}{" "} + m2 + +
+
+ Blood Group {" - "} + + {props.patientData.blood_group ?? "-"} + +
diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index c6cc9e02275..071e7bfc1af 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -15,7 +15,6 @@ import { statusType, useAbortableEffect } from "../../../Common/utils"; import { lazy, useCallback, useState } from "react"; import DoctorVideoSlideover from "../DoctorVideoSlideover"; import { make as Link } from "../../Common/components/Link.bs"; -import PatientInfoCard from "../../Patient/PatientInfoCard"; import { PatientModel } from "../../Patient/models"; import { formatDateTime, relativeTime } from "../../../Utils/utils"; @@ -37,8 +36,10 @@ import { ConsultationDialysisTab } from "./ConsultationDialysisTab"; import { ConsultationNeurologicalMonitoringTab } from "./ConsultationNeurologicalMonitoringTab"; import { ConsultationNutritionTab } from "./ConsultationNutritionTab"; import PatientNotesSlideover from "../PatientNotesSlideover"; -import LegacyDiagnosesList from "../../Diagnosis/LegacyDiagnosesList"; import { AssetBedModel } from "../../Assets/AssetTypes"; +import PatientInfoCard from "../../Patient/PatientInfoCard"; +import RelativeDateUserMention from "../../Common/RelativeDateUserMention"; +import DiagnosesListAccordion from "../../Diagnosis/DiagnosesListAccordion"; const Loading = lazy(() => import("../../Common/Loading")); const PageTitle = lazy(() => import("../../Common/PageTitle")); @@ -343,7 +344,7 @@ export const ConsultationDetails = (props: any) => { showAbhaProfile={qParams["show-abha-profile"] === "true"} /> -
+
{consultationData.admitted_to && (
@@ -374,71 +375,39 @@ export const ConsultationDetails = (props: any) => {
)}
- -
-
- {/*consultationData.other_symptoms && ( -
- - Other Symptoms:{" "} - - {consultationData.other_symptoms} -
- )*/} - - - - {(consultationData.treating_physician_object || - consultationData.deprecated_verified_by) && ( -
- - Treating Physician:{" "} - - {consultationData.treating_physician_object - ? `${consultationData.treating_physician_object.first_name} ${consultationData.treating_physician_object.last_name}` - : consultationData.deprecated_verified_by} - -
- )} -
-
-
+
-
- Created: - {consultationData.created_date - ? formatDateTime(consultationData.created_date) - : "--:--"}{" "} - | +
+ Created:   +
- {consultationData.created_by && ( -
- {` ${consultationData.created_by.first_name} ${consultationData.created_by.last_name} `} - {`@${consultationData.created_by.username} (${consultationData.created_by.user_type})`} -
- )}
-
- Last Modified: - {consultationData.modified_date - ? formatDateTime(consultationData.modified_date) - : "--:--"}{" "} - | +
+ Last Modified:   +
- {consultationData.last_edited_by && ( -
- {` ${consultationData.last_edited_by.first_name} ${consultationData.last_edited_by.last_name} `} - {`@${consultationData.last_edited_by.username} (${consultationData.last_edited_by.user_type})`} -
- )}
- +
+
+ +
+
diff --git a/src/Components/Facility/Consultations/Mews.tsx b/src/Components/Facility/Consultations/Mews.tsx index 14e7d7f9e63..8e109410958 100644 --- a/src/Components/Facility/Consultations/Mews.tsx +++ b/src/Components/Facility/Consultations/Mews.tsx @@ -1,6 +1,5 @@ import { DailyRoundsModel } from "../../Patient/models"; -import RecordMeta from "../../../CAREUI/display/RecordMeta"; -import { classNames } from "../../../Utils/utils"; +import { formatDateTime } from "../../../Utils/utils"; const getRespScore = (value?: number) => { if (typeof value !== "number") return; @@ -60,35 +59,45 @@ const getLOCRange = (value?: DailyRoundsModel["consciousness_level"]) => { }[value]; }; +const getBorderColor = (score: number) => { + if (score === undefined) return "border-gray-700"; + if (score <= 2) return "border-primary-500"; + if (score <= 3) return "border-yellow-300"; + if (score <= 5) return "border-warning-600"; + return "border-danger-500"; +}; + export const Mews = ({ dailyRound }: { dailyRound: DailyRoundsModel }) => { const mewsCard = (isMissing: boolean, data: string[] | number) => { if (isMissing) { return ( <> -
-

N/A

+
+
+ - +
+ MEWS
{(data as string[]).join(", ")}{" "} data is missing from the last log update. +
Last Updated: {formatDateTime(dailyRound.modified_date)}
-
- -
-
+
); } else { - const value = Number(data); return ( <> -
-

{data}

+
+
+ {data} +
+ MEWS

Resp. Rate: {dailyRound.resp} @@ -113,25 +122,10 @@ export const Mews = ({ dailyRound }: { dailyRound: DailyRoundsModel }) => { .toLowerCase()}

+ Last Updated: {formatDateTime(dailyRound.modified_date)}
-
- -
6 && "bg-danger-500" - )} - >
-
+
); } @@ -149,8 +143,7 @@ export const Mews = ({ dailyRound }: { dailyRound: DailyRoundsModel }) => { if (Object.values(scores).some((value) => value === undefined)) { return ( -
-

MEWS Score

+
{mewsCard( true, Object.entries(scores) @@ -162,8 +155,7 @@ export const Mews = ({ dailyRound }: { dailyRound: DailyRoundsModel }) => { } return ( -
-

MEWS Score

+
{mewsCard( false, Object.values(scores as Record).reduce((p, v) => p + v) diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index c9d4aac916d..8cbb24c61a9 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -6,29 +6,29 @@ import { PATIENT_CATEGORIES, RESPIRATORY_SUPPORT, TELEMEDICINE_ACTIONS, -} from "../../Common/constants"; -import { ConsultationModel, PatientCategory } from "../Facility/models"; +} from "../../Common/constants.js"; +import { ConsultationModel, PatientCategory } from "../Facility/models.js"; import { Switch, Menu } from "@headlessui/react"; import { Link, navigate } from "raviger"; import { useState } from "react"; -import CareIcon from "../../CAREUI/icons/CareIcon"; -import useConfig from "../../Common/hooks/useConfig"; -import dayjs from "../../Utils/dayjs"; +import CareIcon from "../../CAREUI/icons/CareIcon.js"; +import useConfig from "../../Common/hooks/useConfig.js"; +import dayjs from "../../Utils/dayjs.js"; import { classNames, formatDate, formatDateTime } from "../../Utils/utils.js"; -import ABHAProfileModal from "../ABDM/ABHAProfileModal"; -import LinkABHANumberModal from "../ABDM/LinkABHANumberModal"; -import LinkCareContextModal from "../ABDM/LinkCareContextModal"; -import DialogModal from "../Common/Dialog"; -import ButtonV2 from "../Common/components/ButtonV2"; -import Beds from "../Facility/Consultations/Beds"; -import { PatientModel } from "./models"; +import ABHAProfileModal from "../ABDM/ABHAProfileModal.js"; +import LinkABHANumberModal from "../ABDM/LinkABHANumberModal.js"; +import LinkCareContextModal from "../ABDM/LinkCareContextModal.js"; +import DialogModal from "../Common/Dialog.js"; +import ButtonV2 from "../Common/components/ButtonV2.js"; +import Beds from "../Facility/Consultations/Beds.js"; +import { PatientModel } from "./models.js"; import request from "../../Utils/request/request.js"; import routes from "../../Redux/api.js"; import DropdownMenu from "../Common/components/Menu.js"; import { triggerGoal } from "../../Integrations/Plausible.js"; -import useAuthUser from "../../Common/hooks/useAuthUser"; +import useAuthUser from "../../Common/hooks/useAuthUser.js"; import { Mews } from "../Facility/Consultations/Mews.js"; import DischargeSummaryModal from "../Facility/DischargeSummaryModal.js"; import DischargeModal from "../Facility/DischargeModal.js"; @@ -153,83 +153,86 @@ export default function PatientInfoCard(props: { )} -
-
+
+
{/* Can support for patient picture in the future */} -
-
- {consultation?.current_bed && - consultation?.discharge_date === null ? ( -
-

- { - consultation?.current_bed?.bed_object?.location_object - ?.name - } -

-

- {consultation?.current_bed?.bed_object.name} -

-
- +
+
+
+ {consultation?.current_bed && + consultation?.discharge_date === null ? ( +
+

{ consultation?.current_bed?.bed_object?.location_object ?.name } - - {consultation?.current_bed?.bed_object.name} +

+

+ {consultation?.current_bed?.bed_object.name} +

+
+ + { + consultation?.current_bed?.bed_object?.location_object + ?.name + } + + {consultation?.current_bed?.bed_object.name} +
-
- ) : ( -
- + ) : ( +
+ +
+ )} +
+ {category && ( +
+ {category.toUpperCase()}
)} + setOpen(true)} + className="mt-1 px-[10px] py-1" + > + {bedDialogTitle} +
- {category && ( +
- {category.toUpperCase()} -
- )} - setOpen(true)} className="mt-1"> - {bedDialogTitle} - -
-
-
- {patient.name} -
-
- {patient.review_time && - !consultation?.discharge_date && - Number(consultation?.review_interval) > 0 && ( -
+ {patient.age} years • {patient.gender} +
+
+ - - {(dayjs().isBefore(patient.review_time) - ? "Review before: " - : "Review Missed: ") + - formatDateTime(patient.review_time)} -
- )} + + {consultation?.facility_name} + +
+
-
+
+
+
- {consultation?.patient_no && ( - - - {`${consultation?.suggestion === "A" ? "IP" : "OP"}: ${ - consultation?.patient_no - }`} - - - )} {medicoLegalCase && ( - + MLC )}
- {!!consultation?.discharge_date && ( -

- Discharged from CARE -

- )} -
-
- {patient.action && patient.action != 10 && ( -
-
- - {" "} - { - TELEMEDICINE_ACTIONS.find( - (i) => i.id === patient.action - )?.desc - } - -
-
- )} -
-
- Age: {patient.age} years -
-
-
-
- Gender: {patient.gender} -
+
+
+ {patient.name} +
+ {patient.age} years • {patient.gender}
- {consultation?.suggestion === "DC" && ( -
+
+
+
+ {consultation?.patient_no && ( + + + {`${consultation?.suggestion === "A" ? "IP" : "OP"}: ${ + consultation?.patient_no + }`} + + + )} + {patient.action && patient.action != 10 && (
-
- Domiciliary Care - +
+ + {" "} + { + TELEMEDICINE_ACTIONS.find( + (i) => i.id === patient.action + )?.desc + } +
+ )} +
+ {patient.blood_group && ( +
+ Blood Group: {patient.blood_group} +
+ )}
- )} -
-
-
- {[ - [ - "Respiratory Support", - RESPIRATORY_SUPPORT.find( - (resp) => - resp.text === - consultation?.last_daily_round?.ventilator_interface - )?.id ?? "UNKNOWN", - consultation?.last_daily_round?.ventilator_interface, - ], - ].map((stat, i) => { - return stat[2] && stat[1] !== "NONE" ? ( -
- {stat[0]} : {stat[1]} -
- ) : ( - "" - ); - })} -
- {consultation?.discharge_date ? ( -
-
- - { - CONSULTATION_SUGGESTION.find( - (suggestion) => - suggestion.id === consultation?.suggestion - )?.text - }{" "} - on {formatDateTime(consultation.encounter_date)}, - {consultation?.new_discharge_reason === - DISCHARGE_REASONS.find((i) => i.text == "Expired")?.id ? ( - - {" "} - Expired on {formatDate(consultation?.death_datetime)} - - ) : ( - - {" "} - Discharged on{" "} - {formatDateTime(consultation?.discharge_date)} - + {patient.review_time && + !consultation?.discharge_date && + Number(consultation?.review_interval) > 0 && ( +
+
+ + {dayjs().isBefore(patient.review_time) + ? "Review before: " + : "Review Missed: "} + {formatDateTime(patient.review_time)} +
+
)} -
-
-
- ) : ( -
- - {consultation?.encounter_date && ( + {consultation?.suggestion === "DC" && (
- Admission on{" "} - {formatDateTime(consultation?.encounter_date)} +
+
+ + Domiciliary Care +
+
)} - {consultation?.icu_admission_date && ( -
- , ICU Admission on{" "} - {formatDateTime(consultation?.icu_admission_date)} + {!!consultation?.discharge_date && ( +

+ Discharged from CARE +

+ )} + {[ + [ + "Respiratory Support", + RESPIRATORY_SUPPORT.find( + (resp) => + resp.text === + consultation?.last_daily_round?.ventilator_interface + )?.id ?? "UNKNOWN", + consultation?.last_daily_round?.ventilator_interface, + ], + ].map((stat, i) => { + return stat[2] && stat[1] !== "NONE" ? ( +
+
+ {stat[0]} : {stat[1]} +
+
+ ) : ( + "" + ); + })} + {consultation?.discharge_date ? ( +
+
+ + + { + CONSULTATION_SUGGESTION.find( + (suggestion) => + suggestion.id === consultation?.suggestion + )?.text + } + {" "} + on {formatDateTime(consultation.encounter_date)}, + {consultation?.new_discharge_reason === "EXP" ? ( + + {" "} + Expired on{" "} + {formatDate(consultation?.death_datetime)} + + ) : ( + + {" "} + Discharged on{" "} + {formatDateTime(consultation?.discharge_date)} + + )} + +
+
+ ) : ( +
+ + {consultation?.encounter_date && ( +
+ Admission on:{" "} + {formatDateTime(consultation?.encounter_date)} +
+ )} + {consultation?.icu_admission_date && ( +
+ , ICU Admission on:{" "} + {formatDateTime(consultation?.icu_admission_date)} +
+ )} +
)} - +
+
+
+
+
+ {consultation?.diagnoses?.length + ? (() => { + const principal_diagnosis = consultation.diagnoses.find( + (diagnosis) => diagnosis.is_principal + ); + return principal_diagnosis ? ( +
+
+ Principal Diagnosis: +
+
+ {principal_diagnosis.diagnosis_object.label}{" "} + + +

+ {principal_diagnosis.verification_status} +

+
+
+
+ ) : null; + })() + : null} + {(consultation?.treating_physician_object || + consultation?.deprecated_verified_by) && ( +
+ + Treating Physician:{" "} + + {consultation?.treating_physician_object + ? `${consultation?.treating_physician_object.first_name} ${consultation?.treating_physician_object.last_name}` + : consultation?.deprecated_verified_by} + +
+ )}
- )} +
- {consultation?.last_daily_round && ( -
- -
- )} -
+ {consultation?.last_daily_round && ( +
+ +
+ )} {!!consultation?.discharge_date && ( -
+
Discharge Reason
-
+
{!consultation?.new_discharge_reason ? ( {consultation.suggestion === "OP" @@ -401,14 +472,6 @@ export default function PatientInfoCard(props: {
)} {[ - [ - `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/update`, - "Edit Consultation Details", - "pen", - patient.is_active && - consultation?.id && - !consultation?.discharge_date, - ], [ `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/daily-rounds`, "Log Update", @@ -431,7 +494,10 @@ export default function PatientInfoCard(props: { ].map( (action: any, i) => action[3] && ( -
+
- +

{action[1]}

{action?.[4]?.[0] && ( <> -

+

{action[4][1]}

@@ -474,11 +540,20 @@ export default function PatientInfoCard(props: { } + title={"Manage Patient"} + icon={} + containerClassName="w-full lg:w-auto mt-2 2xl:mt-0" >
{[ + [ + `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/update`, + "Edit Consultation Details", + "pen", + patient.is_active && + consultation?.id && + !consultation?.discharge_date, + ], [ `/patient/${patient.id}/investigation_reports`, "Investigation Summary", @@ -554,6 +629,7 @@ export default function PatientInfoCard(props: { ) )}
+
{enable_abdm && (patient.abha_number ? ( diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index b890672a6c1..916d32f5ba3 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -99,9 +99,11 @@ export const formatDate = (date: DateLike, format = DATE_FORMAT) => export const formatTime = (date: DateLike, format = TIME_FORMAT) => formatDateTime(date, format); -export const relativeDate = (date: DateLike) => { +export const relativeDate = (date: DateLike, withoutSuffix = false) => { const obj = dayjs(date); - return `${obj.fromNow()} at ${obj.format(TIME_FORMAT)}`; + return `${obj.fromNow(withoutSuffix)} ${ + withoutSuffix && "ago" + } at ${obj.format(TIME_FORMAT)}`; }; export const formatName = (user: { first_name: string; last_name: string }) => { From 8fb7d5946230f5b1ae563af70dce07eaffac6468 Mon Sep 17 00:00:00 2001 From: Gampa Sri Harsh <114745442+sriharsh05@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:17:30 +0530 Subject: [PATCH 13/19] limited the decimal point of location picker to 7 (#7162) --- src/Components/Facility/FacilityCreate.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Components/Facility/FacilityCreate.tsx b/src/Components/Facility/FacilityCreate.tsx index 9fbe89035c4..69f02aa91ee 100644 --- a/src/Components/Facility/FacilityCreate.tsx +++ b/src/Components/Facility/FacilityCreate.tsx @@ -252,8 +252,10 @@ export const FacilityCreate = (props: FacilityProps) => { ? "+91" + data.phone_number : data.phone_number : "", - latitude: data.latitude ? String(data.latitude) : "", - longitude: data.longitude ? String(data.longitude) : "", + latitude: data.latitude ? parseFloat(data.latitude).toFixed(7) : "", + longitude: data.longitude + ? parseFloat(data.longitude).toFixed(7) + : "", type_b_cylinders: data.type_b_cylinders, type_c_cylinders: data.type_c_cylinders, type_d_cylinders: data.type_d_cylinders, @@ -292,8 +294,8 @@ export const FacilityCreate = (props: FacilityProps) => { type: "set_form", form: { ...state.form, - latitude: location.lat().toString(), - longitude: location.lng().toString(), + latitude: location.lat().toFixed(7), + longitude: location.lng().toFixed(7), }, }); } From fd53e5e3918c033d4d6717931b0e3b5244961d5b Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Wed, 7 Feb 2024 11:19:06 +0530 Subject: [PATCH 14/19] fixes #7145; live refresh cns on middleware hostname change (#7149) --- src/Components/Assets/AssetType/HL7Monitor.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Components/Assets/AssetType/HL7Monitor.tsx b/src/Components/Assets/AssetType/HL7Monitor.tsx index 86b9565e536..a7be23baad8 100644 --- a/src/Components/Assets/AssetType/HL7Monitor.tsx +++ b/src/Components/Assets/AssetType/HL7Monitor.tsx @@ -69,6 +69,11 @@ const HL7Monitor = (props: HL7MonitorProps) => { }; if (isLoading) return ; + + const socketUrl = `wss://${ + middlewareHostname || resolvedMiddleware?.hostname + }/observations/${localipAddress}`; + return (
@@ -126,13 +131,12 @@ const HL7Monitor = (props: HL7MonitorProps) => { )} {assetType === "HL7MONITOR" && ( - + )} {assetType === "VENTILATOR" && ( )}
From cab3e97bac2d327894e1b8afa66d4a559608ca20 Mon Sep 17 00:00:00 2001 From: konavivekramakrishna Date: Wed, 7 Feb 2024 11:27:49 +0530 Subject: [PATCH 15/19] Removed 0 in Link Facility sidebar (#7144) * minor fix * draft * Revert "draft" This reverts commit 4ed54c2672a8f470c55fec4032ae653e31cfb457. --- src/Components/Users/ManageUsers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Users/ManageUsers.tsx b/src/Components/Users/ManageUsers.tsx index 597ddefba19..6f5de125600 100644 --- a/src/Components/Users/ManageUsers.tsx +++ b/src/Components/Users/ManageUsers.tsx @@ -715,7 +715,7 @@ function UserFacilities(props: { user: any }) { )} {/* Linked Facilities section */} - {userFacilities?.length && ( + {!!userFacilities?.length && (
Linked Facilities From d4ac20460b4c83b38114c96cf0e6375a682cd5da Mon Sep 17 00:00:00 2001 From: konavivekramakrishna Date: Wed, 7 Feb 2024 16:11:13 +0530 Subject: [PATCH 16/19] Fixes responsiveness in Facilty Home (#6960) * fixed styling in faciltyhome * added flex-wrap * fix ui in sm * fix ui in sm * rm un-necessary classname * Update src/Components/Facility/FacilityHome.tsx --------- Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Co-authored-by: Rithvik Nishad --- src/Components/Facility/FacilityHome.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/Facility/FacilityHome.tsx b/src/Components/Facility/FacilityHome.tsx index 6f42dab00a6..4b4754b894c 100644 --- a/src/Components/Facility/FacilityHome.tsx +++ b/src/Components/Facility/FacilityHome.tsx @@ -222,7 +222,7 @@ export const FacilityHome = (props: any) => {
-
+

@@ -242,7 +242,7 @@ export const FacilityHome = (props: any) => {

-
+

Local Body @@ -251,7 +251,7 @@ export const FacilityHome = (props: any) => { {facilityData?.local_body_object?.name}

-
+

Ward @@ -392,7 +392,7 @@ export const FacilityHome = (props: any) => { )}

-
+
Date: Wed, 7 Feb 2024 17:11:27 +0530 Subject: [PATCH 17/19] Make Update Log buttons responsive (#7185) --- .../Facility/ConsultationDetails/ConsultationUpdatesTab.tsx | 6 +++++- .../Consultations/DailyRounds/DefaultLogUpdateCard.tsx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx index 323715ccfb0..56aadcadbdb 100644 --- a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx +++ b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx @@ -126,7 +126,11 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => { )}
- +
{!props.consultationData.discharge_date && ((hl7SocketUrl && !ventilatorSocketUrl) || diff --git a/src/Components/Facility/Consultations/DailyRounds/DefaultLogUpdateCard.tsx b/src/Components/Facility/Consultations/DailyRounds/DefaultLogUpdateCard.tsx index 34518afcb9b..bb080d43179 100644 --- a/src/Components/Facility/Consultations/DailyRounds/DefaultLogUpdateCard.tsx +++ b/src/Components/Facility/Consultations/DailyRounds/DefaultLogUpdateCard.tsx @@ -32,7 +32,7 @@ const DefaultLogUpdateCard = ({ round, ...props }: Props) => { attributeKey="other_details" attributeValue={round.other_details} /> -
+
Date: Wed, 7 Feb 2024 22:17:43 +0530 Subject: [PATCH 18/19] Make log update button responsive (#7191) * Make log update button responsive * Update PatientInfoCard component styling --- src/Components/Patient/PatientInfoCard.tsx | 603 +++++++++++---------- 1 file changed, 303 insertions(+), 300 deletions(-) diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index 8cbb24c61a9..c954438e6c2 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -471,347 +471,350 @@ export default function PatientInfoCard(props: {
)} - {[ - [ - `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/daily-rounds`, - "Log Update", - "plus", - patient.is_active && - consultation?.id && - !consultation?.discharge_date, +
+ {[ [ - !(consultation?.facility !== patient.facility) && - !(consultation?.discharge_date ?? !patient.is_active) && - dayjs(consultation?.modified_date).isBefore( - dayjs().subtract(1, "day") - ), -
- No update - filed in the last 24 hours -
, + `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/daily-rounds`, + "Log Update", + "plus", + patient.is_active && + consultation?.id && + !consultation?.discharge_date, + [ + !(consultation?.facility !== patient.facility) && + !(consultation?.discharge_date ?? !patient.is_active) && + dayjs(consultation?.modified_date).isBefore( + dayjs().subtract(1, "day") + ), +
+ No + update filed in the last 24 hours +
, + ], ], - ], - ].map( - (action: any, i) => - action[3] && ( -
- + action[3] && ( +
{ - if ( + > + - - -

{action[1]}

-
-
- {action?.[4]?.[0] && ( - <> -

- {action[4][1]} -

- - )} -
- ) - )} - } - containerClassName="w-full lg:w-auto mt-2 2xl:mt-0" - > -
- {[ - [ - `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/update`, - "Edit Consultation Details", - "pen", - patient.is_active && - consultation?.id && - !consultation?.discharge_date, - ], - [ - `/patient/${patient.id}/investigation_reports`, - "Investigation Summary", - "align-alt", - true, - ], - [ - `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/treatment-summary`, - "Treatment Summary", - "file-medical", - consultation?.id, - ], - ] - .concat( - enable_hcx - ? [ - [ - `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/claims`, - "Claims", - "copy-landscape", - consultation?.id, - ], - ] - : [] + onClick={() => { + if ( + consultation?.admitted && + !consultation?.current_bed && + i === 1 + ) { + Notification.Error({ + msg: "Please assign a bed to the patient", + }); + setOpen(true); + } + }} + className="w-full" + > + + +

{action[1]}

+
+ + {action?.[4]?.[0] && ( + <> +

+ {action[4][1]} +

+ + )} +
) - .map( - (action: any, i) => - action[3] && ( -
- { - if ( + )} + } + className="xl:justify-center" + containerClassName="w-full lg:w-auto mt-2 2xl:mt-0 flex justify-center" + > +
+ {[ + [ + `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/update`, + "Edit Consultation Details", + "pen", + patient.is_active && + consultation?.id && + !consultation?.discharge_date, + ], + [ + `/patient/${patient.id}/investigation_reports`, + "Investigation Summary", + "align-alt", + true, + ], + [ + `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/treatment-summary`, + "Treatment Summary", + "file-medical", + consultation?.id, + ], + ] + .concat( + enable_hcx + ? [ + [ + `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/claims`, + "Claims", + "copy-landscape", + consultation?.id, + ], + ] + : [] + ) + .map( + (action: any, i) => + action[3] && ( +
+ - - {action[1]} - - {action?.[4]?.[0] && ( + onClick={() => { + if ( + action[1] !== "Treatment Summary" && + consultation?.admitted && + !consultation?.current_bed && + i === 1 + ) { + Notification.Error({ + msg: "Please assign a bed to the patient", + }); + setOpen(true); + } + triggerGoal("Patient Card Button Clicked", { + buttonName: action[1], + consultationId: consultation?.id, + userId: authUser?.id, + }); + }} + > + + {action[1]} + + {action?.[4]?.[0] && ( + <> +

+ {action[4][1]} +

+ + )} +
+ ) + )} +
+ +
+ {enable_abdm && + (patient.abha_number ? ( + <> + + {({ close }) => ( <> -

- {action[4][1]} -

+
{ + close(); + setShowABHAProfile(true); + triggerGoal("Patient Card Button Clicked", { + buttonName: "Show ABHA Profile", + consultationId: consultation?.id, + userId: authUser?.id, + }); + }} + > + + Show ABHA Profile +
+
{ + triggerGoal("Patient Card Button Clicked", { + buttonName: "Link Care Context", + consultationId: consultation?.id, + userId: authUser?.id, + }); + close(); + setShowLinkCareContext(true); + }} + > + + Link Care Context +
)} -
- ) - )} -
- -
- {enable_abdm && - (patient.abha_number ? ( - <> + + + ) : ( {({ close }) => ( - <> +
{ + close(); + setShowLinkABHANumber(true); + }} + > + + +

Link ABHA Number

+
+
+ )} +
+ ))} +
+
+ {!consultation?.discharge_date && ( + + {({ close }) => ( + <> + {hasActiveShiftingRequest() ? (
{ close(); - setShowABHAProfile(true); - triggerGoal("Patient Card Button Clicked", { - buttonName: "Show ABHA Profile", - consultationId: consultation?.id, - userId: authUser?.id, - }); + navigate( + `/shifting/${ + activeShiftingData[ + activeShiftingData.length - 1 + ].id + }` + ); }} > - - Show ABHA Profile + + +

Track Shifting

+
+ ) : (
{ - triggerGoal("Patient Card Button Clicked", { - buttonName: "Link Care Context", - consultationId: consultation?.id, - userId: authUser?.id, - }); close(); - setShowLinkCareContext(true); + navigate( + `/facility/${patient.facility}/patient/${patient.id}/shift/new` + ); }} > - - Link Care Context + + +

Shift Patient

+
- - )} -
- - ) : ( - - {({ close }) => ( -
{ - close(); - setShowLinkABHANumber(true); - }} - > - - -

Link ABHA Number

-
-
+ )} + )}
- ))} -
-
- {!consultation?.discharge_date && ( + )} {({ close }) => ( - <> - {hasActiveShiftingRequest() ? ( -
{ - close(); - navigate( - `/shifting/${ - activeShiftingData[ - activeShiftingData.length - 1 - ].id - }` - ); - }} - > - - -

Track Shifting

-
-
- ) : ( -
{ - close(); - navigate( - `/facility/${patient.facility}/patient/${patient.id}/shift/new` - ); - }} - > - - -

Shift Patient

-
-
- )} - +
{ + close(); + setOpenDischargeSummaryDialog(true); + }} + > + + +

{t("discharge_summary")}

+
+
)}
- )} - - {({ close }) => ( -
{ - close(); - setOpenDischargeSummaryDialog(true); - }} - > - - -

{t("discharge_summary")}

-
-
- )} -
- - {({ close }) => ( -
{ - if (!consultation?.discharge_date) { - close(); - setOpenDischargeDialog(true); - } - }} - > - - -

{t("discharge_from_care")}

-
-
- )} -
-
-
- - { - triggerGoal("Patient Card Button Clicked", { - buttonName: "Medico Legal Case", - consultationId: consultation?.id, - userId: authUser?.id, - }); - setMedicoLegalCase(checked); - switchMedicoLegalCase(checked); - }} - className={classNames( - medicoLegalCase ? "bg-primary" : "bg-gray-200", - "relative inline-flex h-4 w-8 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none " + + {({ close }) => ( +
{ + if (!consultation?.discharge_date) { + close(); + setOpenDischargeDialog(true); + } + }} + > + + +

{t("discharge_from_care")}

+
+
)} - > -
+
+ + { + triggerGoal("Patient Card Button Clicked", { + buttonName: "Medico Legal Case", + consultationId: consultation?.id, + userId: authUser?.id, + }); + setMedicoLegalCase(checked); + switchMedicoLegalCase(checked); + }} className={classNames( - medicoLegalCase ? "translate-x-4" : "translate-x-0", - "pointer-events-none inline-block h-3 w-3 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out" + medicoLegalCase ? "bg-primary" : "bg-gray-200", + "relative inline-flex h-4 w-8 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none " )} - /> - - - - Medico-Legal Case - {" "} - - -
-
+ > +
+ +
Date: Wed, 7 Feb 2024 22:23:18 +0530 Subject: [PATCH 19/19] fixes improper string interpolation in relative dates causing 'false' to be present when withoutSuffix is disabled (#7189) * fixes improper string interpolation in realtive dates causing 'false' to be present when withoutSuffix is disabled * Update src/Utils/utils.ts --------- Co-authored-by: Ashesh <3626859+Ashesh3@users.noreply.github.com> --- src/Utils/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 916d32f5ba3..4e1d1626a59 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -101,8 +101,8 @@ export const formatTime = (date: DateLike, format = TIME_FORMAT) => export const relativeDate = (date: DateLike, withoutSuffix = false) => { const obj = dayjs(date); - return `${obj.fromNow(withoutSuffix)} ${ - withoutSuffix && "ago" + return `${obj.fromNow(withoutSuffix)}${ + withoutSuffix ? " ago " : "" } at ${obj.format(TIME_FORMAT)}`; };