From 9fb1a9fb8a5b19d4947cb145aaede6a44315e02d Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Mon, 25 Sep 2023 19:56:34 +0530 Subject: [PATCH 1/9] request: fix/improve typesafety of `TData` (#6324) --- src/Utils/request/request.ts | 4 ++-- src/Utils/request/useQuery.ts | 6 +++--- src/Utils/request/utils.ts | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Utils/request/request.ts b/src/Utils/request/request.ts index 45c8e5ce664..c946f524ab9 100644 --- a/src/Utils/request/request.ts +++ b/src/Utils/request/request.ts @@ -2,7 +2,7 @@ import handleResponse from "./handleResponse"; import { RequestOptions, RequestResult, Route } from "./types"; import { makeHeaders, makeUrl } from "./utils"; -interface Options extends RequestOptions { +interface Options extends RequestOptions { controller?: AbortController; } @@ -16,7 +16,7 @@ export default async function request( onResponse, silent, reattempts = 3, - }: Options = {} + }: Options = {} ): Promise> { const signal = controller?.signal; const url = makeUrl(path, query, pathParams); diff --git a/src/Utils/request/useQuery.ts b/src/Utils/request/useQuery.ts index a370b909fe9..2a8cb2e2ad4 100644 --- a/src/Utils/request/useQuery.ts +++ b/src/Utils/request/useQuery.ts @@ -3,14 +3,14 @@ import { QueryRoute, RequestOptions, RequestResult } from "./types"; import request from "./request"; import { mergeRequestOptions } from "./utils"; -export interface QueryOptions extends RequestOptions { +export interface QueryOptions extends RequestOptions { prefetch?: boolean; refetchOnWindowFocus?: boolean; } export default function useQuery( route: QueryRoute, - options?: QueryOptions + options?: QueryOptions ) { const [response, setResponse] = useState>(); const [loading, setLoading] = useState(false); @@ -18,7 +18,7 @@ export default function useQuery( const controllerRef = useRef(); const runQuery = useCallback( - async (overrides?: QueryOptions) => { + async (overrides?: QueryOptions) => { controllerRef.current?.abort(); const controller = new AbortController(); diff --git a/src/Utils/request/utils.ts b/src/Utils/request/utils.ts index 5a4fb7e2b2e..f159df1b7a7 100644 --- a/src/Utils/request/utils.ts +++ b/src/Utils/request/utils.ts @@ -69,10 +69,10 @@ export function getAuthorizationHeader() { return null; } -export function mergeRequestOptions( - options: RequestOptions, - overrides: RequestOptions -): RequestOptions { +export function mergeRequestOptions( + options: RequestOptions, + overrides: RequestOptions +): RequestOptions { return { ...options, ...overrides, From 2973d6e08d520a49b411851722c4e56a2c8abae2 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Mon, 25 Sep 2023 19:57:10 +0530 Subject: [PATCH 2/9] update icd11 model (#6343) --- .../Facility/ConsultationDetails/index.tsx | 42 ++++++++----------- src/Components/Facility/models.tsx | 1 - 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index 356257f9ac6..c23bf071fa1 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -50,10 +50,26 @@ export interface ConsultationTabProps { patientData: PatientModel; } +const TABS = { + UPDATES: ConsultationUpdatesTab, + FEED: ConsultationFeedTab, + SUMMARY: ConsultationSummaryTab, + MEDICINES: ConsultationMedicinesTab, + FILES: ConsultationFilesTab, + INVESTIGATIONS: ConsultationInvestigationsTab, + ABG: ConsultationABGTab, + NURSING: ConsultationNursingTab, + NEUROLOGICAL_MONITORING: ConsultationNeurologicalMonitoringTab, + VENTILATOR: ConsultationVentilatorTab, + NUTRITION: ConsultationNursingTab, + PRESSURE_SORE: ConsultationPressureSoreTab, + DIALYSIS: ConsultationDialysisTab, +}; + export const ConsultationDetails = (props: any) => { const { t } = useTranslation(); const { facilityId, patientId, consultationId } = props; - const tab = props.tab.toUpperCase(); + const tab = props.tab.toUpperCase() as keyof typeof TABS; const dispatch: any = useDispatch(); const [isLoading, setIsLoading] = useState(false); const [showDoctors, setShowDoctors] = useState(false); @@ -142,22 +158,6 @@ export const ConsultationDetails = (props: any) => { }); }, []); - const TABS = { - UPDATES: ConsultationUpdatesTab, - FEED: ConsultationFeedTab, - SUMMARY: ConsultationSummaryTab, - MEDICINES: ConsultationMedicinesTab, - FILES: ConsultationFilesTab, - INVESTIGATIONS: ConsultationInvestigationsTab, - ABG: ConsultationABGTab, - NURSING: ConsultationNursingTab, - NEUROLOGICAL_MONITORING: ConsultationNeurologicalMonitoringTab, - VENTILATOR: ConsultationVentilatorTab, - NUTRITION: ConsultationNursingTab, - PRESSURE_SORE: ConsultationPressureSoreTab, - DIALYSIS: ConsultationDialysisTab, - }; - const consultationTabProps: ConsultationTabProps = { consultationId, facilityId, @@ -379,13 +379,7 @@ export const ConsultationDetails = (props: any) => { Date: Tue, 26 Sep 2023 15:17:19 +0530 Subject: [PATCH 3/9] Create cypress test for asset transaction and service history's (#6349) * Asset page redirection * Test for asset transaction and service history --- cypress/e2e/assets_spec/assets_manage.cy.ts | 54 ++++++++++++++ cypress/pageobject/Asset/AssetCreation.ts | 74 +++++++++++++++++++ .../pageobject/Facility/FacilityCreation.ts | 2 - src/Components/Assets/AssetManage.tsx | 17 ++++- .../Assets/AssetServiceEditModal.tsx | 15 +++- .../Form/FormFields/Autocomplete.tsx | 2 +- 6 files changed, 155 insertions(+), 9 deletions(-) diff --git a/cypress/e2e/assets_spec/assets_manage.cy.ts b/cypress/e2e/assets_spec/assets_manage.cy.ts index 1f89facd0a3..34c554b374e 100644 --- a/cypress/e2e/assets_spec/assets_manage.cy.ts +++ b/cypress/e2e/assets_spec/assets_manage.cy.ts @@ -12,6 +12,9 @@ describe("Asset", () => { const assetSearchPage = new AssetSearchPage(); const assetFilters = new AssetFilters(); const fillFacilityName = "Dummy Facility 1"; + const assetname = "Dummy Camera"; + const locationName = "Dummy Location 1"; + const initiallocationName = "Camera Location"; before(() => { loginPage.loginAsDisctrictAdmin(); @@ -23,6 +26,57 @@ describe("Asset", () => { cy.awaitUrl("/assets"); }); + it("Create & Edit a service history and verify reflection", () => { + assetSearchPage.typeSearchKeyword(assetname); + assetSearchPage.pressEnter(); + assetSearchPage.verifyBadgeContent(assetname); + assetSearchPage.clickAssetByName(assetname); + assetPage.clickupdatedetailbutton(); + assetPage.scrollintonotes(); + assetPage.enterAssetNotes("Dummy Notes"); + assetPage.enterAssetservicedate("01092023"); + assetPage.clickassetupdatebutton(); + assetPage.scrollintoservicehistory(); + assetPage.clickedithistorybutton(); + assetPage.scrollintonotes(); + assetPage.enterAssetNotes("Dummy Notes Editted"); + assetPage.clickassetupdatebutton(); + assetPage.scrollintoservicehistory(); + assetPage.viewassetservicehistorybutton(); + assetPage.openassetservicehistory(); + assetPage.verifyassetupdateservicehistory(); + assetPage.viewassetservicehistorybutton(); + }); + + it("Create a asset transaction and verify history", () => { + assetSearchPage.typeSearchKeyword(assetname); + assetSearchPage.pressEnter(); + assetSearchPage.verifyBadgeContent(assetname); + assetSearchPage.clickAssetByName(assetname); + assetPage.clickupdatedetailbutton(); + assetPage.clickassetlocation(locationName); + assetPage.clickUpdateAsset(); + assetPage.verifyassetlocation(locationName); + assetPage.verifytransactionStatus(initiallocationName, locationName); + }); + + it("Verify Facility Asset Page Redirection", () => { + cy.visit("/facility"); + assetSearchPage.typeSearchKeyword(fillFacilityName); + assetSearchPage.pressEnter(); + facilityPage.verifyFacilityBadgeContent(fillFacilityName); + facilityPage.visitAlreadyCreatedFacility(); + facilityPage.clickManageFacilityDropdown(); + facilityPage.clickCreateAssetFacilityOption(); + facilityPage.verifyfacilitycreateassetredirection(); + facilityPage.verifyassetfacilitybackredirection(); + facilityPage.clickManageFacilityDropdown(); + facilityPage.clickviewAssetFacilityOption(); + facilityPage.verifyfacilityviewassetredirection(); + assetFilters.assertFacilityText(fillFacilityName); + facilityPage.verifyassetfacilitybackredirection(); + }); + it("Delete an Asset", () => { assetPage.openCreatedAsset(); assetPage.interceptDeleteAssetApi(); diff --git a/cypress/pageobject/Asset/AssetCreation.ts b/cypress/pageobject/Asset/AssetCreation.ts index b939c31405f..45356a1a4e7 100644 --- a/cypress/pageobject/Asset/AssetCreation.ts +++ b/cypress/pageobject/Asset/AssetCreation.ts @@ -276,4 +276,78 @@ export class AssetPage { cy.get("#submit").contains("Import").click(); cy.wait("@importAsset").its("response.statusCode").should("eq", 201); } + + clickupdatedetailbutton() { + cy.get("[data-testid=asset-update-button]").click(); + } + + scrollintonotes() { + cy.get("#notes").scrollIntoView(); + } + + enterAssetNotes(text) { + cy.get("#notes").click().clear(); + cy.get("#notes").click().type(text); + } + + enterAssetservicedate(text) { + cy.get("input[name='last_serviced_on']").click(); + cy.get("#date-input").click().type(text); + } + + clickassetupdatebutton() { + cy.get("#submit").click(); + } + + viewassetservicehistorybutton() { + cy.get("#view-service-history").should("be.visible"); + } + + openassetservicehistory() { + cy.get("#view-service-history").click(); + cy.get("#view-asset-edit-history").first().click(); + } + + verifyassetupdateservicehistory() { + cy.get("#edit-history-asset-servicedon").should("have.text", "01/09/2023"); + cy.get("#edit-history-asset-note").should( + "have.text", + "Dummy Notes Editted" + ); + cy.get("#view-history-back-button").contains("Back").click(); + cy.get("#view-history-back-button").contains("Close").click(); + } + + scrollintoservicehistory() { + cy.get("#service-history").scrollIntoView(); + } + + clickedithistorybutton() { + cy.get("#edit-service-history").click(); + } + + verifytransactionStatus(initiallocationName: string, locationName: string) { + cy.get("#transaction-history").scrollIntoView(); + cy.get("#transaction-history table tbody tr:first-child td:eq(0)").should( + "contain", + initiallocationName + ); + cy.get("#transaction-history table tbody tr:first-child td:eq(1)").should( + "contain", + locationName + ); + } + + verifyassetlocation(locationName: string) { + cy.get("#asset-current-location").should("contain", locationName); + } + + clickassetlocation(locationName: string) { + cy.get("#clear-button").click(); + cy.get("[data-testid=asset-location-input] button").click(); + cy.get("[data-testid=asset-location-input] button") + .click() + .type(locationName); + cy.get("[role='option']").contains(locationName).click(); + } } diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index 0c12d4655fd..b6285bff72b 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -205,9 +205,7 @@ class FacilityPage { } verifyfacilityviewassetredirection() { - cy.intercept("GET", "**api/v1/getallfacilities/**").as("getViewAssets"); cy.url().should("include", "/assets?facility="); - cy.wait("@getViewAssets").its("response.statusCode").should("eq", 200); } clickManageInventory() { diff --git a/src/Components/Assets/AssetManage.tsx b/src/Components/Assets/AssetManage.tsx index 4565c48b33d..84325d704aa 100644 --- a/src/Components/Assets/AssetManage.tsx +++ b/src/Components/Assets/AssetManage.tsx @@ -231,6 +231,7 @@ const AssetManage = (props: AssetManageProps) => { { setServiceEditData({ ...service, open: true }); @@ -240,6 +241,7 @@ const AssetManage = (props: AssetManageProps) => { {
{item.label}
-
+
{item.content || "--"}
@@ -513,7 +518,10 @@ const AssetManage = (props: AssetManageProps) => { asset?.asset_class && asset?.asset_class != AssetClass.NONE && }
Service History
-
+
@@ -540,7 +548,10 @@ const AssetManage = (props: AssetManageProps) => {
Transaction History
-
+
diff --git a/src/Components/Assets/AssetServiceEditModal.tsx b/src/Components/Assets/AssetServiceEditModal.tsx index 75c9dd9fc60..66d44d11907 100644 --- a/src/Components/Assets/AssetServiceEditModal.tsx +++ b/src/Components/Assets/AssetServiceEditModal.tsx @@ -97,7 +97,10 @@ export const AssetServiceEditModal = (props: { {edit.edited_by.username}

-
+
@@ -124,19 +127,25 @@ export const AssetServiceEditModal = (props: {

Serviced On

-

+

{formatDate(editRecord.serviced_on)}

Notes

-

{editRecord.note || "-"}

+

+ {editRecord.note || "-"} +

)}
{ editRecord ? setEditRecord(undefined) : props.handleClose(); diff --git a/src/Components/Form/FormFields/Autocomplete.tsx b/src/Components/Form/FormFields/Autocomplete.tsx index bbc60643faf..c4b3ea3686e 100644 --- a/src/Components/Form/FormFields/Autocomplete.tsx +++ b/src/Components/Form/FormFields/Autocomplete.tsx @@ -165,7 +165,7 @@ export const Autocomplete = (props: AutocompleteProps) => { {value?.icon} {value && !props.isLoading && !props.required && ( -
+
{ From 308379ecf566eb7c641ac384b5686db54a8b36a1 Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Tue, 26 Sep 2023 15:19:46 +0530 Subject: [PATCH 4/9] Display patient age in mm dd when younger than 1y (#6342) --- .../ConsultationUpdatesTab.tsx | 9 +++++-- .../Investigations/Reports/ReportTable.tsx | 12 +++++++-- .../Facility/Investigations/Reports/index.tsx | 5 +++- src/Components/Facility/LegacyMonitorCard.tsx | 3 ++- src/Components/Facility/TreatmentSummary.tsx | 5 ++-- src/Components/Patient/ManagePatients.tsx | 6 +++-- src/Components/Patient/PatientHome.tsx | 9 +++++-- src/Components/Patient/PatientInfoCard.tsx | 4 +-- src/Components/Patient/SampleDetails.tsx | 4 +-- src/Components/Shifting/ListView.tsx | 9 +++++-- src/Components/Shifting/ShiftDetails.tsx | 14 +++++++--- src/Components/Shifting/ShiftingBoard.tsx | 9 +++++-- src/Utils/utils.ts | 27 +++++++++++++++++++ 13 files changed, 92 insertions(+), 24 deletions(-) diff --git a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx index 705b3d9479a..1b89f3980e1 100644 --- a/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx +++ b/src/Components/Facility/ConsultationDetails/ConsultationUpdatesTab.tsx @@ -10,7 +10,7 @@ import useVitalsAspectRatioConfig from "../../VitalsMonitor/useVitalsAspectRatio import { DISCHARGE_REASONS, SYMPTOM_CHOICES } from "../../../Common/constants"; import PrescriptionsTable from "../../Medicine/PrescriptionsTable"; import Chip from "../../../CAREUI/display/Chip"; -import { formatDate, formatDateTime } from "../../../Utils/utils"; +import { formatAge, formatDate, formatDateTime } from "../../../Utils/utils"; import ReadMore from "../../Common/components/Readmore"; import { DailyRoundsList } from "../Consultations/DailyRoundsList"; @@ -621,7 +621,12 @@ export const ConsultationUpdatesTab = (props: ConsultationTabProps) => {
Age {" - "} - {props.patientData.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 + ) + : "-"}
diff --git a/src/Components/Facility/Investigations/Reports/ReportTable.tsx b/src/Components/Facility/Investigations/Reports/ReportTable.tsx index 0826ff904fc..1f20ec94180 100644 --- a/src/Components/Facility/Investigations/Reports/ReportTable.tsx +++ b/src/Components/Facility/Investigations/Reports/ReportTable.tsx @@ -2,7 +2,7 @@ import { getColorIndex, rowColor, transformData } from "./utils"; import ButtonV2 from "../../../Common/components/ButtonV2"; import { InvestigationResponse } from "./types"; -import { formatDateTime } from "../../../../Utils/utils"; +import { formatAge, formatDateTime } from "../../../../Utils/utils"; import { FC } from "react"; const ReportRow = ({ data, name, min, max }: any) => { @@ -53,6 +53,7 @@ interface ReportTableProps { patientDetails?: { name: string; age: number; + date_of_birth: string; hospitalName: string; }; investigationData: InvestigationResponse; @@ -83,7 +84,14 @@ const ReportTable: FC = ({ {patientDetails && (

Name: {patientDetails.name}

-

Age: {patientDetails.age}

+

+ Age:{" "} + {formatAge( + patientDetails.age, + patientDetails.date_of_birth, + true + )} +

Hospital: {patientDetails.hospitalName}

)} diff --git a/src/Components/Facility/Investigations/Reports/index.tsx b/src/Components/Facility/Investigations/Reports/index.tsx index c4c69bc9169..ab5380c62ca 100644 --- a/src/Components/Facility/Investigations/Reports/index.tsx +++ b/src/Components/Facility/Investigations/Reports/index.tsx @@ -100,8 +100,9 @@ const InvestigationReports = ({ id }: any) => { const [patientDetails, setPatientDetails] = useState<{ name: string; age: number; + date_of_birth: string; hospitalName: string; - }>({ name: "", age: -1, hospitalName: "" }); + }>({ name: "", age: -1, date_of_birth: "", hospitalName: "" }); const [state, dispatch] = useReducer( investigationReportsReducer, initialState @@ -220,6 +221,7 @@ const InvestigationReports = ({ id }: any) => { setPatientDetails({ name: res.data.name, age: res.data.age, + date_of_birth: res.data.date_of_birth, hospitalName: res.data.facility_object.name, }); } @@ -227,6 +229,7 @@ const InvestigationReports = ({ id }: any) => { setPatientDetails({ name: "", age: -1, + date_of_birth: "", hospitalName: "", }); } diff --git a/src/Components/Facility/LegacyMonitorCard.tsx b/src/Components/Facility/LegacyMonitorCard.tsx index 9f9fb8f1ea0..61bff3d607b 100644 --- a/src/Components/Facility/LegacyMonitorCard.tsx +++ b/src/Components/Facility/LegacyMonitorCard.tsx @@ -4,6 +4,7 @@ import CareIcon from "../../CAREUI/icons/CareIcon"; import { PatientModel } from "../Patient/models"; import LegacyPatientVitalsCard from "../Patient/LegacyPatientVitalsCard"; import { AssetLocationObject } from "../Assets/AssetTypes"; +import { formatAge } from "../../Utils/utils"; interface MonitorCardProps { facilityId: string; @@ -28,7 +29,7 @@ export const LegacyMonitorCard = ({ {patient.name} - {patient.age}y |{" "} + {formatAge(patient.age, patient.date_of_birth)} |{" "} {GENDER_TYPES.find((g) => g.id === patient.gender)?.icon} diff --git a/src/Components/Facility/TreatmentSummary.tsx b/src/Components/Facility/TreatmentSummary.tsx index dbca307d38b..3fbd80ac8b2 100644 --- a/src/Components/Facility/TreatmentSummary.tsx +++ b/src/Components/Facility/TreatmentSummary.tsx @@ -10,7 +10,7 @@ import { statusType, useAbortableEffect } from "../../Common/utils"; import { PatientModel } from "../Patient/models"; import { GENDER_TYPES } from "../../Common/constants"; -import { formatDate, formatDateTime } from "../../Utils/utils"; +import { formatAge, formatDate, formatDateTime } from "../../Utils/utils"; const Loading = lazy(() => import("../Common/Loading")); const TreatmentSummary = (props: any) => { @@ -132,7 +132,8 @@ const TreatmentSummary = (props: any) => {
- Age : {patientData.age} + Age :{" "} + {formatAge(patientData.age, patientData.date_of_birth, true)}
Date of admission : diff --git a/src/Components/Patient/ManagePatients.tsx b/src/Components/Patient/ManagePatients.tsx index 423edb894c9..6e83eb9bc91 100644 --- a/src/Components/Patient/ManagePatients.tsx +++ b/src/Components/Patient/ManagePatients.tsx @@ -37,7 +37,7 @@ import SearchInput from "../Form/SearchInput"; import SortDropdownMenu from "../Common/SortDropdown"; import SwitchTabs from "../Common/components/SwitchTabs"; import { parseOptionId } from "../../Common/utils"; -import { parsePhoneNumber } from "../../Utils/utils.js"; +import { formatAge, parsePhoneNumber } from "../../Utils/utils.js"; import { useDispatch } from "react-redux"; import useFilters from "../../Common/hooks/useFilters"; import { useTranslation } from "react-i18next"; @@ -558,7 +558,9 @@ export const PatientManager = () => {
{patient.name} - {`${patient.age} yrs.`} + + {formatAge(patient.age, patient.date_of_birth, true)} +
diff --git a/src/Components/Patient/PatientHome.tsx b/src/Components/Patient/PatientHome.tsx index 8fdc0f51280..b6ceaf2e4dc 100644 --- a/src/Components/Patient/PatientHome.tsx +++ b/src/Components/Patient/PatientHome.tsx @@ -19,7 +19,7 @@ import { ConsultationModel } from "../Facility/models"; import { PatientModel, SampleTestModel } from "./models"; import { SampleTestCard } from "./SampleTestCard"; import Chip from "../../CAREUI/display/Chip"; -import { classNames, formatDateTime } from "../../Utils/utils"; +import { classNames, formatAge, formatDateTime } from "../../Utils/utils"; import ButtonV2 from "../Common/components/ButtonV2"; import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; import RelativeDateUserMention from "../Common/RelativeDateUserMention"; @@ -476,7 +476,12 @@ export const PatientHome = (props: any) => {

- {patientData.name} - {patientData.age} + {patientData.name} -{" "} + {formatAge( + patientData.age, + patientData.date_of_birth, + true + )}

{patientData.is_vaccinated ? ( diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index dbb4aac34ce..701b76b5e3a 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -20,7 +20,7 @@ import { PatientModel } from "./models"; import { getDimensionOrDash } from "../../Common/utils"; import useConfig from "../../Common/hooks/useConfig"; import { useState } from "react"; -import { formatDate, formatDateTime } from "../../Utils/utils.js"; +import { formatAge, formatDate, formatDateTime } from "../../Utils/utils.js"; import dayjs from "../../Utils/dayjs"; export default function PatientInfoCard(props: { @@ -171,7 +171,7 @@ export default function PatientInfoCard(props: {

)}

- {patient.age} years + {formatAge(patient.age, patient.date_of_birth, true)} {patient.gender} {consultation?.suggestion === "DC" && ( diff --git a/src/Components/Patient/SampleDetails.tsx b/src/Components/Patient/SampleDetails.tsx index a5f802115bd..7814109978b 100644 --- a/src/Components/Patient/SampleDetails.tsx +++ b/src/Components/Patient/SampleDetails.tsx @@ -8,7 +8,7 @@ import Card from "../../CAREUI/display/Card"; import { FileUpload } from "./FileUpload"; import Page from "../Common/components/Page"; import _ from "lodash"; -import { formatDateTime } from "../../Utils/utils"; +import { formatAge, formatDateTime } from "../../Utils/utils"; import { getTestSample } from "../../Redux/actions"; import { navigate } from "raviger"; @@ -118,7 +118,7 @@ export const SampleDetails = ({ id }: SampleDetailsProps) => { ) : (

Age: - {patientData?.age} + {formatAge(patientData.age, patientData.date_of_birth)}
)}
diff --git a/src/Components/Shifting/ListView.tsx b/src/Components/Shifting/ListView.tsx index dddfd275f9d..6d55122ea11 100644 --- a/src/Components/Shifting/ListView.tsx +++ b/src/Components/Shifting/ListView.tsx @@ -12,7 +12,7 @@ import { ExportButton } from "../Common/Export"; import ListFilter from "./ListFilter"; import Page from "../Common/components/Page"; import SearchInput from "../Form/SearchInput"; -import { formatDateTime } from "../../Utils/utils"; +import { formatAge, formatDateTime } from "../../Utils/utils"; import { formatFilter } from "./Commons"; import { navigate } from "raviger"; import useConfig from "../../Common/hooks/useConfig"; @@ -127,7 +127,12 @@ export default function ListView() {
- {shift.patient_object.name} - {shift.patient_object.age} + {shift.patient_object.name} -{" "} + {formatAge( + shift.patient_object.age, + shift.patient_object.date_of_birth, + true + )}
{shift.emergency && ( diff --git a/src/Components/Shifting/ShiftDetails.tsx b/src/Components/Shifting/ShiftDetails.tsx index 8215bd21e31..03e09702aac 100644 --- a/src/Components/Shifting/ShiftDetails.tsx +++ b/src/Components/Shifting/ShiftDetails.tsx @@ -18,7 +18,7 @@ import { CopyToClipboard } from "react-copy-to-clipboard"; import Page from "../Common/components/Page"; import QRCode from "qrcode.react"; import RecordMeta from "../../CAREUI/display/RecordMeta"; -import { formatDateTime } from "../../Utils/utils"; +import { formatAge, formatDateTime } from "../../Utils/utils"; import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import { useTranslation } from "react-i18next"; @@ -110,7 +110,13 @@ export default function ShiftDetails(props: { id: string }) { "\n" + t("age") + ":" + - data?.patient_object?.age + + +( + formatAge( + data?.patient_object?.age, + data?.patient_object?.date_of_birth, + true + ) ?? "-" + ) + "\n" + t("origin_facility") + ":" + @@ -195,7 +201,7 @@ export default function ShiftDetails(props: { id: string }) { {t("age")}:{" "} - {patientData?.age} + {formatAge(patientData?.age, patientData?.date_of_birth, true)}
)} {patientData?.gender === 2 && patientData?.is_antenatal && ( @@ -380,7 +386,7 @@ export default function ShiftDetails(props: { id: string }) { {t("age")}:{" "} - {patientData?.age} + {formatAge(patientData.age, patientData.date_of_birth, true)}
diff --git a/src/Components/Shifting/ShiftingBoard.tsx b/src/Components/Shifting/ShiftingBoard.tsx index 71a33afdda8..7c065d0c0a8 100644 --- a/src/Components/Shifting/ShiftingBoard.tsx +++ b/src/Components/Shifting/ShiftingBoard.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { classNames, formatDateTime } from "../../Utils/utils"; +import { classNames, formatAge, formatDateTime } from "../../Utils/utils"; import { completeTransfer, downloadShiftRequests, @@ -78,7 +78,12 @@ const ShiftCard = ({ shift, filter }: any) => {
- {shift.patient_object.name} - {shift.patient_object.age} + {shift.patient_object.name} -{" "} + {formatAge( + shift.patient_object?.age, + shift.patient_object?.age.date_of_birth, + true + )}
{shift.emergency && ( diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 1c702e75e86..3aef5b03d67 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -379,3 +379,30 @@ export const getCountryCode = (phoneNumber: string) => { } return undefined; }; + +export const formatAge = ( + age?: number, + date_of_birth?: string, + abbreviated = false +) => { + if (!age && !date_of_birth) return undefined; + if (!age) age = 0; + + const daySuffix = abbreviated ? "d" : "days"; + const monthSuffix = abbreviated ? "mo" : "months"; + const yearSuffix = abbreviated ? "yr" : "years"; + + if (age < 1 && date_of_birth) { + const dob = new Date(date_of_birth); + const today = new Date(); + const diffTime = Math.abs(today.getTime() - dob.getTime()); + const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); + const months = Math.floor(diffDays / 30); + const days = diffDays % 30; + if (months === 0) { + return `${days} ${daySuffix}`; + } + return `${months} ${monthSuffix} ${days} ${daySuffix}`; + } + return `${age} ${yearSuffix}`; +}; From f0d34708c664fcd37fe6fbe570495d14f7c726df Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Tue, 26 Sep 2023 15:24:28 +0530 Subject: [PATCH 5/9] Enable clearing 'referred to' in discharge modal (#6337) --- src/Components/Facility/DischargeModal.tsx | 13 +++++++------ src/Components/Form/AutoCompleteAsync.tsx | 22 +++++++++++++++++++--- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/Components/Facility/DischargeModal.tsx b/src/Components/Facility/DischargeModal.tsx index 8376a0ad299..b069b371a72 100644 --- a/src/Components/Facility/DischargeModal.tsx +++ b/src/Components/Facility/DischargeModal.tsx @@ -75,7 +75,7 @@ const DischargeModal = ({ const [latestClaim, setLatestClaim] = useState(); const [isCreateClaimLoading, setIsCreateClaimLoading] = useState(false); const [isSendingDischargeApi, setIsSendingDischargeApi] = useState(false); - const [facility, setFacility] = useState({ id: 0, name: "" }); // for referred to external + const [facility, setFacility] = useState(); const [errors, setErrors] = useState({}); const fetchLatestClaim = useCallback(async () => { @@ -186,12 +186,13 @@ const DischargeModal = ({ const prescriptionActions = PrescriptionActions(consultationData.id ?? ""); const handleFacilitySelect = (selected: FacilityModel) => { - setFacility(selected ? selected : facility); - const { id, name } = selected; + setFacility(selected); + const { id, name } = selected || {}; const isExternal = id === -1; setPreDischargeForm((prev) => ({ ...prev, - ...(isExternal ? { referred_to_external: name } : { referred_to: id }), + referred_to: isExternal ? null : id, + referred_to_external: isExternal ? name : null, })); }; @@ -238,8 +239,8 @@ const DischargeModal = ({ handleFacilitySelect(selected as FacilityModel) } selected={facility} - showAll={true} - freeText={true} + showAll + freeText multiple={false} errors={errors?.referred_to} className="mb-4" diff --git a/src/Components/Form/AutoCompleteAsync.tsx b/src/Components/Form/AutoCompleteAsync.tsx index d06067af957..5f33c6388c5 100644 --- a/src/Components/Form/AutoCompleteAsync.tsx +++ b/src/Components/Form/AutoCompleteAsync.tsx @@ -7,6 +7,7 @@ import { MultiSelectOptionChip, dropdownOptionClassNames, } from "./MultiSelectMenuV2"; +import { useTranslation } from "react-i18next"; interface Props { name?: string; @@ -23,6 +24,7 @@ interface Props { placeholder?: string; disabled?: boolean; error?: string; + required?: boolean; onBlur?: () => void; onFocus?: () => void; } @@ -42,11 +44,13 @@ const AutoCompleteAsync = (props: Props) => { className = "", placeholder, disabled = false, + required = false, error, } = props; const [data, setData] = useState([]); const [query, setQuery] = useState(""); const [loading, setLoading] = useState(false); + const { t } = useTranslation(); const hasSelection = (!multiple && selected) || (multiple && selected?.length > 0); @@ -86,9 +90,7 @@ const AutoCompleteAsync = (props: Props) => { : placeholder || "Start typing to search..." } displayValue={() => - hasSelection && !multiple - ? optionLabel && optionLabel(selected) - : "" + hasSelection && !multiple ? optionLabel?.(selected) : "" } onChange={({ target }) => setQuery(target.value)} onFocus={props.onFocus} @@ -100,6 +102,20 @@ const AutoCompleteAsync = (props: Props) => { />
+ {hasSelection && !loading && !required && ( +
+ { + e.preventDefault(); + onChange(null); + }} + /> + + {t("clear_selection")} + +
+ )} {loading ? ( ) : ( From 269d00ff74901614198bb6b2db1542291f767e00 Mon Sep 17 00:00:00 2001 From: "Tasnimul H. Tauhid" Date: Tue, 26 Sep 2023 18:52:38 +0530 Subject: [PATCH 6/9] Added logic for showing "Track Shifting" button when patient has active shifting (#6318) * logic for track shifting button * removed console log * cypress fix * cypress fix --------- Co-authored-by: Rithvik Nishad Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- cypress/e2e/patient_spec/patient_crud.cy.ts | 2 + .../pageobject/Facility/FacilityCreation.ts | 2 - .../pageobject/Patient/PatientConsultation.ts | 1 + cypress/pageobject/Patient/PatientCreation.ts | 4 ++ .../Facility/ConsultationDetails/index.tsx | 67 +++++++++++++++---- 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/cypress/e2e/patient_spec/patient_crud.cy.ts b/cypress/e2e/patient_spec/patient_crud.cy.ts index b55732fa440..b22ccdbce13 100644 --- a/cypress/e2e/patient_spec/patient_crud.cy.ts +++ b/cypress/e2e/patient_spec/patient_crud.cy.ts @@ -33,6 +33,7 @@ describe("Patient Creation with consultation", () => { it("Create a new patient with no consultation", () => { patientPage.createPatient(); patientPage.selectFacility("dummy facility"); + patientPage.patientformvisibility(); patientPage.enterPatientDetails( phone_number, emergency_phone_number, @@ -69,6 +70,7 @@ describe("Patient Creation with consultation", () => { patientPage.interceptFacilities(); patientPage.visitUpdatePatientUrl(); patientPage.verifyStatusCode(); + patientPage.patientformvisibility(); updatePatientPage.enterPatientDetails( "Test E2E User Edited", "O+", diff --git a/cypress/pageobject/Facility/FacilityCreation.ts b/cypress/pageobject/Facility/FacilityCreation.ts index b6285bff72b..42ec6d8fd7c 100644 --- a/cypress/pageobject/Facility/FacilityCreation.ts +++ b/cypress/pageobject/Facility/FacilityCreation.ts @@ -191,9 +191,7 @@ class FacilityPage { } verifyfacilitycreateassetredirection() { - cy.intercept("GET", "**/api/v1/facility/**").as("getNewAssets"); cy.url().should("include", "/assets/new"); - cy.wait("@getNewAssets").its("response.statusCode").should("eq", 200); } verifyassetfacilitybackredirection() { diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index c0ba0c260d8..b1c95d19140 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -16,6 +16,7 @@ export class PatientConsultationPage { } fillIllnessHistory(history: string) { + cy.wait(5000); cy.get("#history_of_present_illness").scrollIntoView(); cy.get("#history_of_present_illness").should("be.visible"); cy.get("#history_of_present_illness").click().type(history); diff --git a/cypress/pageobject/Patient/PatientCreation.ts b/cypress/pageobject/Patient/PatientCreation.ts index 9b8df4a287e..4fcd43dc490 100644 --- a/cypress/pageobject/Patient/PatientCreation.ts +++ b/cypress/pageobject/Patient/PatientCreation.ts @@ -124,4 +124,8 @@ export class PatientPage { verifyStatusCode() { cy.wait("@getFacilities").its("response.statusCode").should("eq", 200); } + + patientformvisibility() { + cy.get("[data-testid='current-address']").scrollIntoView(); + } } diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index c23bf071fa1..403f1752704 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -5,7 +5,11 @@ import { SYMPTOM_CHOICES, } from "../../../Common/constants"; import { ConsultationModel, ICD11DiagnosisModel } from "../models"; -import { getConsultation, getPatient } from "../../../Redux/actions"; +import { + getConsultation, + getPatient, + listShiftRequests, +} from "../../../Redux/actions"; import { statusType, useAbortableEffect } from "../../../Common/utils"; import { lazy, useCallback, useState } from "react"; import ToolTip from "../../Common/utils/Tooltip"; @@ -79,6 +83,7 @@ export const ConsultationDetails = (props: any) => { {} as ConsultationModel ); const [patientData, setPatientData] = useState({}); + const [activeShiftingData, setActiveShiftingData] = useState>([]); const [openDischargeSummaryDialog, setOpenDischargeSummaryDialog] = useState(false); const [openDischargeDialog, setOpenDischargeDialog] = useState(false); @@ -140,6 +145,15 @@ export const ConsultationDetails = (props: any) => { }; setPatientData(data); } + + // Get shifting data + const shiftingRes = await dispatch( + listShiftRequests({ patient: id }, "shift-list-call") + ); + if (shiftingRes?.data?.results) { + const data = shiftingRes.data.results; + setActiveShiftingData(data); + } } else { navigate("/not-found"); } @@ -168,6 +182,19 @@ export const ConsultationDetails = (props: any) => { const SelectedTab = TABS[tab]; + const hasActiveShiftingRequest = () => { + if (activeShiftingData.length > 0) { + return [ + "PENDING", + "APPROVED", + "DESTINATION APPROVED", + "PATIENT TO BE PICKED UP", + ].includes(activeShiftingData[activeShiftingData.length - 1].status); + } + + return false; + }; + if (isLoading) { return ; } @@ -265,17 +292,33 @@ export const ConsultationDetails = (props: any) => {
{!consultationData.discharge_date && (
- - navigate( - `/facility/${patientData.facility}/patient/${patientData.id}/shift/new` - ) - } - className="btn btn-primary m-1 w-full hover:text-white" - > - - Shift Patient - + {hasActiveShiftingRequest() ? ( + + navigate( + `/shifting/${ + activeShiftingData[activeShiftingData.length - 1].id + }` + ) + } + className="btn btn-primary m-1 w-full hover:text-white" + > + + Track Shifting + + ) : ( + + navigate( + `/facility/${patientData.facility}/patient/${patientData.id}/shift/new` + ) + } + className="btn btn-primary m-1 w-full hover:text-white" + > + + Shift Patient + + )}