diff --git a/src/components/Common/Charts/ObservationChart.tsx b/src/components/Common/Charts/ObservationChart.tsx index 9d1abfd9cc5..f79d529abb4 100644 --- a/src/components/Common/Charts/ObservationChart.tsx +++ b/src/components/Common/Charts/ObservationChart.tsx @@ -51,6 +51,7 @@ interface ObservationVisualizerProps { codeGroups: CodeGroup[]; height?: number; gridCols?: number; + encounterId: string; } interface ChartData { @@ -98,6 +99,7 @@ const formatChartDate = ( export const ObservationVisualizer = ({ patientId, codeGroups, + encounterId, height = 300, gridCols = 2, }: ObservationVisualizerProps) => { @@ -108,10 +110,14 @@ export const ObservationVisualizer = ({ queryKey: [ "observations", patientId, + encounterId, allCodes.map((c) => c.code).join(","), ], queryFn: query(routes.observationsAnalyse, { pathParams: { patientId }, + queryParams: { + encounter: encounterId, + }, body: { codes: allCodes, }, @@ -380,6 +386,7 @@ export const ObservationVisualizer = ({ diff --git a/src/components/Common/Charts/ObservationHistoryTable.tsx b/src/components/Common/Charts/ObservationHistoryTable.tsx index e698309de4c..9e3940bff17 100644 --- a/src/components/Common/Charts/ObservationHistoryTable.tsx +++ b/src/components/Common/Charts/ObservationHistoryTable.tsx @@ -28,6 +28,7 @@ interface PaginatedResponse { interface ObservationHistoryTableProps { patientId: string; + encounterId: string; codes: Code[]; } @@ -45,6 +46,7 @@ const formatDate = (dateString: string) => { export const ObservationHistoryTable = ({ patientId, + encounterId, codes, }: ObservationHistoryTableProps) => { const { ref, inView } = useInView(); @@ -57,6 +59,7 @@ export const ObservationHistoryTable = ({ const response = await query(routes.listObservations, { pathParams: { patientId }, queryParams: { + encounter: encounterId, limit: String(LIMIT), codes: codes.map((c) => c.code).join(","), offset: String(pageParam), diff --git a/src/components/Facility/ConsultationDetails/ObservationsList.tsx b/src/components/Facility/ConsultationDetails/ObservationsList.tsx index 9a98c2a73fa..a71c2a0fbfa 100644 --- a/src/components/Facility/ConsultationDetails/ObservationsList.tsx +++ b/src/components/Facility/ConsultationDetails/ObservationsList.tsx @@ -1,15 +1,22 @@ +import { useInfiniteQuery } from "@tanstack/react-query"; +import { useEffect } from "react"; import { useTranslation } from "react-i18next"; +import { useInView } from "react-intersection-observer"; import CareIcon from "@/CAREUI/icons/CareIcon"; -import PaginatedList from "@/CAREUI/misc/PaginatedList"; import { Card } from "@/components/ui/card"; import routes from "@/Utils/request/api"; +import query from "@/Utils/request/query"; +import { HTTPError } from "@/Utils/request/types"; +import { PaginatedResponse } from "@/Utils/request/types"; import { formatDateTime } from "@/Utils/utils"; import { Encounter } from "@/types/emr/encounter"; import { Observation } from "@/types/emr/observation"; +const LIMIT = 20; + interface Props { encounter: Encounter; } @@ -18,63 +25,96 @@ export default function ObservationsList(props: Props) { const { t } = useTranslation(); const patientId = props.encounter.patient.id; const encounterId = props.encounter.id; + const { ref, inView } = useInView(); + + const { data, fetchNextPage, hasNextPage, isLoading, isFetchingNextPage } = + useInfiniteQuery, HTTPError>({ + queryKey: ["observations", patientId, encounterId], + queryFn: async ({ pageParam = 0 }) => { + const response = await query(routes.listObservations, { + pathParams: { patientId }, + queryParams: { + encounter: encounterId, + ignore_group: true, + limit: String(LIMIT), + offset: String(pageParam), + }, + })({ signal: new AbortController().signal }); + return response as PaginatedResponse; + }, + initialPageParam: 0, + getNextPageParam: (lastPage, allPages) => { + const currentOffset = allPages.length * LIMIT; + return currentOffset < lastPage.count ? currentOffset : null; + }, + }); + + useEffect(() => { + if (inView && hasNextPage && !isFetchingNextPage) { + fetchNextPage(); + } + }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]); + + if (isLoading) { + return ( + +
+ {t("loading")} +
+
+ ); + } + + const observations = data?.pages.flatMap((page) => page.results) ?? []; + + if (observations.length === 0) { + return ( + +
+ {t("no_observations")} +
+
+ ); + } return ( - - {() => ( -
-
- - -
- {t("no_observations")} +
+
+ {observations.map((item: Observation) => ( + +
+
+ + {formatDateTime(item.effective_datetime)} +
+
+ {item.main_code.display || item.main_code.code} +
+ {item.value.value_quantity && ( +
+ {item.value.value_quantity.value}{" "} + {item.value.value_quantity.code.display}
- - - - className="grid gap-4"> - {(item) => ( - -
-
- - {formatDateTime(item.effective_datetime)} -
-
- {item.main_code.display || item.main_code.code} -
- {item.value.value_quantity && ( -
- {item.value.value_quantity.value}{" "} - {item.value.value_quantity.code.display} -
- )} - {item.value.value && ( -
{item.value.value}
- )} - {item.note && ( -
- {item.note} -
- )} -
-
)} - - -
- + {item.value.value && ( +
{item.value.value}
+ )} + {item.note && ( +
+ {item.note} +
+ )} +
+ + ))} + {hasNextPage && ( +
+
+ {isFetchingNextPage ? t("loading_more") : t("load_more")}
-
- )} - + )} +
+
); } diff --git a/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx b/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx index b82b37aaca5..11f9ea4529b 100644 --- a/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx +++ b/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx @@ -149,7 +149,9 @@ export default function QuestionnaireResponsesList({ encounter }: Props) { route={routes.getQuestionnaireResponses} pathParams={{ patientId: encounter.patient.id, - encounterId: encounter.id, + }} + query={{ + encounter: encounter.id, }} > {() => ( @@ -264,6 +266,7 @@ export default function QuestionnaireResponsesList({ encounter }: Props) { type={type} id={response.id} patientId={encounter.patient.id} + encounterId={encounter.id} /> ); }, diff --git a/src/components/Facility/ConsultationDetails/StructuredResponseView.tsx b/src/components/Facility/ConsultationDetails/StructuredResponseView.tsx index ba4e3ba2e98..9d6b06ae2b8 100644 --- a/src/components/Facility/ConsultationDetails/StructuredResponseView.tsx +++ b/src/components/Facility/ConsultationDetails/StructuredResponseView.tsx @@ -16,9 +16,15 @@ interface Props { type: string; id: string; patientId: string; + encounterId: string; } -export function StructuredResponseView({ type, id, patientId }: Props) { +export function StructuredResponseView({ + type, + id, + patientId, + encounterId, +}: Props) { const getRouteAndParams = () => { const params: Record = { patientId }; switch (type) { @@ -26,19 +32,20 @@ export function StructuredResponseView({ type, id, patientId }: Props) { return { route: symptomApi.retrieveSymptom, pathParams: { ...params, symptomId: id }, + queryParams: { encounter: encounterId }, }; case "diagnosis": return { route: diagnosisApi.retrieveDiagnosis, pathParams: { ...params, diagnosisId: id }, + queryParams: { encounter: encounterId }, }; case "allergy_intolerance": return { route: allergyApi.retrieveAllergy, pathParams: { ...params, allergyId: id }, + queryParams: { encounter: encounterId }, }; - default: - return null; } }; @@ -47,7 +54,8 @@ export function StructuredResponseView({ type, id, patientId }: Props) { const { data, isLoading, error } = useQuery({ queryKey: [type, id], queryFn: query(routeConfig?.route as any, { - pathParams: routeConfig?.pathParams || { patientId }, + pathParams: routeConfig?.pathParams, + queryParams: routeConfig?.queryParams, }), enabled: !!id && !!routeConfig, }); diff --git a/src/pages/Encounters/tabs/EncounterPlotsTab.tsx b/src/pages/Encounters/tabs/EncounterPlotsTab.tsx index c0857b2d000..cc9c6d57689 100644 --- a/src/pages/Encounters/tabs/EncounterPlotsTab.tsx +++ b/src/pages/Encounters/tabs/EncounterPlotsTab.tsx @@ -55,6 +55,7 @@ export const EncounterPlotsTab = (props: EncounterTabProps) => { diff --git a/src/pages/Encounters/tabs/EncounterUpdatesTab.tsx b/src/pages/Encounters/tabs/EncounterUpdatesTab.tsx index f8eab9f6743..fb49046d1cb 100644 --- a/src/pages/Encounters/tabs/EncounterUpdatesTab.tsx +++ b/src/pages/Encounters/tabs/EncounterUpdatesTab.tsx @@ -5,372 +5,35 @@ import { SymptomsList } from "@/components/Patient/symptoms/list"; import { EncounterTabProps } from "@/pages/Encounters/EncounterShow"; -export const EncounterUpdatesTab = (props: EncounterTabProps) => { +export const EncounterUpdatesTab = ({ + encounter, + patient, +}: EncounterTabProps) => { return ( -
-
-
-
- +
+ {/* Main Content Area */} +
+ {/* Left Column - Symptoms, Diagnoses, and Questionnaire Responses */} +
+ {/* Symptoms Section */} +
+
-
- -
-
- -
-
- {/*
- - - - - {props.consultationData.history_of_present_illness && ( -
-
-

- History of Present Illness -

-
- -
-
-
- )} - - {props.consultationData.examination_details && ( -
-
-

- Examination details and Clinical conditions:{" "} -

-
- -
-
-
- )} - {props.consultationData.treatment_plan && ( -
-
-

- Treatment Summary -

-
- -
-
-
- )} - {props.consultationData.consultation_notes && ( -
-
-

- General Instructions -

-
- -
-
-
- )} - {(props.consultationData.operation ?? - props.consultationData.special_instruction) && ( -
-
-

- Notes -

-
- {props.consultationData.operation && ( -
-
Operation
- -
- )} - - {props.consultationData.special_instruction && ( -
-
Special Instruction
- -
- )} -
-
-
- )} + {/* Diagnoses Section */} +
+
- {props.consultationData.procedure && - props.consultationData.procedure.length > 0 && ( -
-
- - - - - - - - - - - {props.consultationData.procedure?.map( - (procedure, index) => ( - - - - - - - ), - )} - -
- Procedure - - Notes - - Repetitive - - Time / Frequency -
- {procedure.procedure} - - {procedure.notes} - - {procedure.repetitive ? "Yes" : "No"} - - {procedure.repetitive - ? procedure.frequency - : formatDateTime(String(procedure.time))} -
-
-
- )} - {props.consultationData.intubation_start_date && ( -
-
-

- Date/Size/LL:{" "} -

-
-
- Intubation Date{" - "} - - {formatDateTime( - props.consultationData.intubation_start_date, - )} - -
-
- Extubation Date{" - "} - - {props.consultationData.intubation_end_date && - formatDateTime( - props.consultationData.intubation_end_date, - )} - -
-
- ETT/TT (mmid){" - "} - - {props.consultationData.ett_tt} - -
-
- Cuff Pressure (mmhg){" - "} - - {props.consultationData.cuff_pressure} - -
-
-
-
- )} - - {props.consultationData.lines?.length > 0 && ( -
-
-

- Lines and Catheters -

-
- {props.consultationData.lines?.map( - (line: any, idx: number) => ( -
-
{line.type}
-

- Details: -
- {line.other_type} -

-

- Insertion Date:{" "} - - {formatDateTime(line.start_date)} - -

-

- Site/Level of Fixation:
- - {line.site} - -

-
- ), - )} -
-
-
- )} -
-
-
-

- Body Details -

-
-
- Gender {" - "} - - {props.patientData.gender ?? "-"} - -
-
- Age {" - "} - - {formatPatientAge(props.patientData)} - -
-
- Weight {" - "} - - {props.consultationData.weight - ? `${props.consultationData.weight} kg` - : "Unspecified"} - -
-
- Height {" - "} - - {props.consultationData.height - ? `${props.consultationData.height} cm` - : "Unspecified"} - -
-
- Body Surface Area {" - "} - - {props.consultationData.weight && - props.consultationData.height ? ( - <> - {Math.sqrt( - (Number(props.consultationData.weight) * - Number(props.consultationData.height)) / - 3600, - ).toFixed(2)} - m2 - - ) : ( - "Unspecified" - )} - -
-
- Blood Group {" - "} - - {props.patientData.blood_group ?? "-"} - -
-
-
-
- {((props.patientData.is_antenatal && - isAntenatal(props.patientData.last_menstruation_start_date)) || - isPostPartum(props.patientData.date_of_delivery)) && ( -
-

- Perinatal Status -

- -
- {props.patientData.is_antenatal && - isAntenatal( - props.patientData.last_menstruation_start_date, - ) && ( - - )} - {isPostPartum(props.patientData.date_of_delivery) && ( - - )} -
- {props.patientData.last_menstruation_start_date && ( -

- - Last Menstruation: - - {formatDate( - props.patientData.last_menstruation_start_date, - )} - -

- )} - - {props.patientData.date_of_delivery && ( -

- - Date of Delivery: - - {formatDate(props.patientData.date_of_delivery)} - -

- )} -
- )} + {/* Questionnaire Responses Section */} +
+
-
*/} -
- +
+ + {/* Right Column - Observations */} +
+