From efff4f0a149bff1f674fbe3412406886c6d22501 Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Wed, 13 Nov 2024 15:49:20 +0530 Subject: [PATCH 1/4] made a reusable component for table in routine and nursing care procedures Co-authored-by: Sahil-Sinha-11 Co-authored-by: Aakash Singh --- .../ConsultationNursingTab.tsx | 216 +++++++++++------- .../Consultations/LogUpdateAnalayseTable.tsx | 93 ++++++++ .../Facility/Consultations/NursingPlot.tsx | 132 ----------- src/components/Facility/models.tsx | 5 +- 4 files changed, 226 insertions(+), 220 deletions(-) create mode 100644 src/components/Facility/Consultations/LogUpdateAnalayseTable.tsx delete mode 100644 src/components/Facility/Consultations/NursingPlot.tsx diff --git a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx index 81078197a45..5c2eeae6bda 100644 --- a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx +++ b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx @@ -4,43 +4,20 @@ import { useTranslation } from "react-i18next"; import Loading from "@/components/Common/Loading"; import PageTitle from "@/components/Common/PageTitle"; import Pagination from "@/components/Common/Pagination"; +import { ProcedureType } from "@/components/Common/prescription-builder/ProcedureBuilder"; import { ConsultationTabProps } from "@/components/Facility/ConsultationDetails/index"; -import { NursingPlot } from "@/components/Facility/Consultations/NursingPlot"; +import LogUpdateAnalayseTable from "@/components/Facility/Consultations/LogUpdateAnalayseTable"; import { + DailyRoundsRes, + NursingPlotFields, RoutineAnalysisRes, RoutineFields, } from "@/components/Facility/models"; -import { PAGINATION_LIMIT } from "@/common/constants"; +import { NURSING_CARE_PROCEDURES, PAGINATION_LIMIT } from "@/common/constants"; import routes from "@/Utils/request/api"; import request from "@/Utils/request/request"; -import { classNames, formatDate, formatTime } from "@/Utils/utils"; - -export default function ConsultationNursingTab(props: ConsultationTabProps) { - const { t } = useTranslation(); - return ( -
- -
-

{t("routine")}

- -
-
-

{t("nursing_care")}

- -
-
- ); -} const REVERSE_CHOICES = { appetite: { @@ -114,6 +91,104 @@ const ROUTINE_ROWS = [ { subField: true, field: "appetite" } as const, ]; +const NursingPlot = ({ consultationId }: ConsultationTabProps) => { + const { t } = useTranslation(); + const [results, setResults] = useState({}); + const [currentPage, setCurrentPage] = useState(1); + const [totalCount, setTotalCount] = useState(0); + + useEffect(() => { + const fetchDailyRounds = async ( + currentPage: number, + consultationId: string, + ) => { + const { res, data } = await request(routes.dailyRoundsAnalyse, { + body: { page: currentPage, fields: NursingPlotFields }, + pathParams: { consultationId }, + }); + if (res && res.ok && data) { + setResults(data.results); + setTotalCount(data.count); + } + }; + + fetchDailyRounds(currentPage, consultationId); + }, [consultationId, currentPage]); + + const handlePagination = (page: number) => setCurrentPage(page); + + const data = Object.entries(results).map(([date, result]) => { + if ("nursing" in result) { + return { + date: date, + nursing: result.nursing, + }; + } else { + return { + date: date, + nursing: null, + }; + } + }); + + const dataToDisplay = data.flatMap( + (x) => x.nursing?.map((f) => ({ ...f, date: x.date })) ?? [], + ); + + const filterEmpty = (field: (typeof NURSING_CARE_PROCEDURES)[number]) => { + const filtered = dataToDisplay.filter( + (i: ProcedureType) => i.procedure === field, + ); + return filtered.length > 0; + }; + + const areFieldsEmpty = () => + NURSING_CARE_PROCEDURES.every((field) => !filterEmpty(field)); + + const rows = NURSING_CARE_PROCEDURES.filter((f) => filterEmpty(f)).map( + (procedure) => ({ + field: procedure, + title: t(`NURSING_CARE_PROCEDURE__${procedure}`), + }), + ); + + const mappedData = dataToDisplay.reduce( + (acc: Record>, item) => { + if (!acc[item.date]) acc[item.date] = {}; + acc[item.date][item.procedure] = item.description; + return acc; + }, + {}, + ); + + return ( +
+
+ {areFieldsEmpty() ? ( +
+
+ {t("no_data_found")} +
+
+ ) : ( + + )} +
+ + {totalCount > PAGINATION_LIMIT && !areFieldsEmpty() && ( +
+ +
+ )} +
+ ); +}; + const RoutineSection = ({ consultationId }: ConsultationTabProps) => { const { t } = useTranslation(); const [page, setPage] = useState(1); @@ -158,65 +233,11 @@ const RoutineSection = ({ consultationId }: ConsultationTabProps) => { return (
-
- - - - - ))} - - - - {ROUTINE_ROWS.map((row) => ( - - - {row.field && - Object.values(results).map((obj, idx) => ( - - ))} - - ))} - -
- {Object.keys(results).map((date) => ( - -

{formatDate(date)}

-

{formatTime(date)}

-
- {row.title ?? t(`LOG_UPDATE_FIELD_LABEL__${row.field!}`)} - - {(() => { - const value = obj[row.field]; - if (value == null) { - return "-"; - } - if (typeof value === "boolean") { - return t(value ? "yes" : "no"); - } - const choices = REVERSE_CHOICES[row.field]; - const choice = `${row.field.toUpperCase()}__${choices[value as keyof typeof choices]}`; - return t(choice); - })()} -
-
+ {totalCount != null && totalCount > PAGINATION_LIMIT && (
@@ -231,3 +252,24 @@ const RoutineSection = ({ consultationId }: ConsultationTabProps) => {
); }; + +export default function ConsultationNursingTab(props: ConsultationTabProps) { + const { t } = useTranslation(); + return ( +
+ +
+

{t("routine")}

+ +
+
+

{t("nursing_care")}

+ +
+
+ ); +} diff --git a/src/components/Facility/Consultations/LogUpdateAnalayseTable.tsx b/src/components/Facility/Consultations/LogUpdateAnalayseTable.tsx new file mode 100644 index 00000000000..a9192b1c593 --- /dev/null +++ b/src/components/Facility/Consultations/LogUpdateAnalayseTable.tsx @@ -0,0 +1,93 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; + +import { classNames, formatDate, formatTime } from "@/Utils/utils"; + +interface SharedSectionTableProps { + data: Record>; + rows: Array<{ title?: string; field?: string; subField?: boolean }>; + choices?: Record>; +} + +const LogUpdateAnalayseTable: React.FC = ({ + data, + rows, + choices = {}, +}) => { + const { t } = useTranslation(); + + const dataValues = React.useMemo(() => Object.values(data), [data]); + + const getDisplayValue = ( + value: string | boolean | null | undefined, + field?: string, + ): string => { + if (typeof value === "boolean") { + return t(value ? "yes" : "no"); + } + + if (field && choices[field]) { + const choiceMap = choices[field]; + const choice = + typeof value === "string" || typeof value === "number" + ? choiceMap[value] + : undefined; + return choice ? t(`${field.toUpperCase()}__${choice}`) : "-"; + } + + return typeof value === "string" ? value : "-"; + }; + + return ( +
+ + + + + {Object.keys(data).map((date) => ( + + ))} + + + + {rows.map((row) => ( + + + {dataValues.map((obj, idx) => { + const value = row.field ? obj[row.field] : undefined; + return ( + + ); + })} + + ))} + +
+

{formatDate(date)}

+

{formatTime(date)}

+
+ {row.title ?? t(`LOG_UPDATE_FIELD_LABEL__${row.field!}`)} + + {row.field ? getDisplayValue(value, row.field) : "-"} +
+
+ ); +}; + +export default LogUpdateAnalayseTable; diff --git a/src/components/Facility/Consultations/NursingPlot.tsx b/src/components/Facility/Consultations/NursingPlot.tsx deleted file mode 100644 index 13f5bb64201..00000000000 --- a/src/components/Facility/Consultations/NursingPlot.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import Pagination from "@/components/Common/Pagination"; -import { NursingPlotFields } from "@/components/Facility/models"; - -import { NURSING_CARE_PROCEDURES, PAGINATION_LIMIT } from "@/common/constants"; - -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import { formatDateTime } from "@/Utils/utils"; - -export const NursingPlot = ({ consultationId }: any) => { - const { t } = useTranslation(); - const [results, setResults] = useState({}); - const [currentPage, setCurrentPage] = useState(1); - const [totalCount, setTotalCount] = useState(0); - - useEffect(() => { - const fetchDailyRounds = async ( - currentPage: number, - consultationId: string, - ) => { - const { res, data } = await request(routes.dailyRoundsAnalyse, { - body: { page: currentPage, fields: NursingPlotFields }, - pathParams: { - consultationId, - }, - }); - if (res && res.ok && data) { - setResults(data.results); - setTotalCount(data.count); - } - }; - - fetchDailyRounds(currentPage, consultationId); - }, [consultationId, currentPage]); - - const handlePagination = (page: number) => { - setCurrentPage(page); - }; - - const data = Object.entries(results).map((key: any) => { - return { - date: formatDateTime(key[0]), - nursing: key[1]["nursing"], - }; - }); - - const dataToDisplay = data - .map((x) => - x.nursing.map((f: any) => { - f["date"] = x.date; - return f; - }), - ) - .reduce((accumulator, value) => accumulator.concat(value), []); - - const filterEmpty = (field: (typeof NURSING_CARE_PROCEDURES)[number]) => { - const filtered = dataToDisplay.filter((i: any) => i.procedure === field); - return filtered.length > 0; - }; - - const areFieldsEmpty = () => { - let emptyFieldCount = 0; - for (const field of NURSING_CARE_PROCEDURES) { - if (!filterEmpty(field)) emptyFieldCount++; - } - if (emptyFieldCount === NURSING_CARE_PROCEDURES.length) return true; - else return false; - }; - - return ( -
-
-
-
- {areFieldsEmpty() && ( -
-
- {t("no_data_found")} -
-
- )} - {NURSING_CARE_PROCEDURES.map( - (f) => - filterEmpty(f) && ( -
-
-
-

- {t(`NURSING_CARE_PROCEDURE__${f}`)} -

-
-
-
- {dataToDisplay - .filter((i: any) => i.procedure === f) - .map((care: any, index: number) => ( -
-
- {care.date} -
-
- {care.description} -
-
- ))} -
-
- ), - )} -
-
-
- - {!areFieldsEmpty() && totalCount > PAGINATION_LIMIT && ( -
- -
- )} -
- ); -}; diff --git a/src/components/Facility/models.tsx b/src/components/Facility/models.tsx index 79272ac3de7..a984efe6283 100644 --- a/src/components/Facility/models.tsx +++ b/src/components/Facility/models.tsx @@ -391,7 +391,10 @@ export const NursingPlotFields = [ ] as const satisfies (keyof DailyRoundsModel)[]; export type NursingPlotRes = { - nursing: any[]; + nursing: Array<{ + procedure: string; + description: string; + }>; }; export const RoutineFields = [ From bdc62d81c0ed9f98df2a2accbeca0173d36847f2 Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Wed, 13 Nov 2024 16:29:03 +0530 Subject: [PATCH 2/4] optimize --- .../ConsultationNursingTab.tsx | 81 ++++++++----------- 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx index 5c2eeae6bda..30a2f2b4f14 100644 --- a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx +++ b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx @@ -4,12 +4,11 @@ import { useTranslation } from "react-i18next"; import Loading from "@/components/Common/Loading"; import PageTitle from "@/components/Common/PageTitle"; import Pagination from "@/components/Common/Pagination"; -import { ProcedureType } from "@/components/Common/prescription-builder/ProcedureBuilder"; import { ConsultationTabProps } from "@/components/Facility/ConsultationDetails/index"; import LogUpdateAnalayseTable from "@/components/Facility/Consultations/LogUpdateAnalayseTable"; import { - DailyRoundsRes, NursingPlotFields, + NursingPlotRes, RoutineAnalysisRes, RoutineFields, } from "@/components/Facility/models"; @@ -93,7 +92,9 @@ const ROUTINE_ROWS = [ const NursingPlot = ({ consultationId }: ConsultationTabProps) => { const { t } = useTranslation(); - const [results, setResults] = useState({}); + const [results, setResults] = useState<{ [date: string]: NursingPlotRes }>( + {}, + ); const [currentPage, setCurrentPage] = useState(1); const [totalCount, setTotalCount] = useState(0); @@ -106,8 +107,8 @@ const NursingPlot = ({ consultationId }: ConsultationTabProps) => { body: { page: currentPage, fields: NursingPlotFields }, pathParams: { consultationId }, }); - if (res && res.ok && data) { - setResults(data.results); + if (res?.ok && data) { + setResults(data.results as { [date: string]: NursingPlotRes }); setTotalCount(data.count); } }; @@ -117,65 +118,53 @@ const NursingPlot = ({ consultationId }: ConsultationTabProps) => { const handlePagination = (page: number) => setCurrentPage(page); - const data = Object.entries(results).map(([date, result]) => { - if ("nursing" in result) { - return { - date: date, - nursing: result.nursing, - }; - } else { - return { - date: date, - nursing: null, - }; - } - }); - - const dataToDisplay = data.flatMap( - (x) => x.nursing?.map((f) => ({ ...f, date: x.date })) ?? [], - ); - - const filterEmpty = (field: (typeof NURSING_CARE_PROCEDURES)[number]) => { - const filtered = dataToDisplay.filter( - (i: ProcedureType) => i.procedure === field, - ); - return filtered.length > 0; - }; - - const areFieldsEmpty = () => - NURSING_CARE_PROCEDURES.every((field) => !filterEmpty(field)); + let fieldsToDisplay = new Set(); - const rows = NURSING_CARE_PROCEDURES.filter((f) => filterEmpty(f)).map( - (procedure) => ({ - field: procedure, - title: t(`NURSING_CARE_PROCEDURE__${procedure}`), - }), - ); - - const mappedData = dataToDisplay.reduce( - (acc: Record>, item) => { - if (!acc[item.date]) acc[item.date] = {}; - acc[item.date][item.procedure] = item.description; + /** + * Transforms nursing procedure results into a structured format where dates are mapped to procedures and their descriptions. + * Groups nursing data by date, collecting unique procedures and their corresponding descriptions. + */ + const dataNew = Object.entries(results).reduce( + (acc: Record>, [date, result]) => { + if ("nursing" in result) { + result.nursing.forEach((field) => { + if (field.procedure && !acc[date]) { + acc[date] = {}; + } + acc[date][field.procedure] = field.description; + // Add procedure to the set of procedures to display + fieldsToDisplay.add(field.procedure); + }); + } return acc; }, {}, ); + fieldsToDisplay = fieldsToDisplay.intersection( + new Set(NURSING_CARE_PROCEDURES), + ); + + const rows = Array.from(fieldsToDisplay).map((procedure) => ({ + field: procedure, + title: t(`NURSING_CARE_PROCEDURE__${procedure}`), + })); + return (
- {areFieldsEmpty() ? ( + {fieldsToDisplay.size == 0 ? (
{t("no_data_found")}
) : ( - + )}
- {totalCount > PAGINATION_LIMIT && !areFieldsEmpty() && ( + {totalCount > PAGINATION_LIMIT && fieldsToDisplay.size > 0 && (
Date: Wed, 13 Nov 2024 17:01:05 +0530 Subject: [PATCH 3/4] minor refactor --- .../ConsultationDetails/ConsultationNursingTab.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx index 30a2f2b4f14..58db082fa1f 100644 --- a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx +++ b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx @@ -124,13 +124,11 @@ const NursingPlot = ({ consultationId }: ConsultationTabProps) => { * Transforms nursing procedure results into a structured format where dates are mapped to procedures and their descriptions. * Groups nursing data by date, collecting unique procedures and their corresponding descriptions. */ - const dataNew = Object.entries(results).reduce( + const tableData = Object.entries(results).reduce( (acc: Record>, [date, result]) => { if ("nursing" in result) { result.nursing.forEach((field) => { - if (field.procedure && !acc[date]) { - acc[date] = {}; - } + if (field.procedure && !acc[date]) acc[date] = {}; acc[date][field.procedure] = field.description; // Add procedure to the set of procedures to display fieldsToDisplay.add(field.procedure); @@ -160,7 +158,7 @@ const NursingPlot = ({ consultationId }: ConsultationTabProps) => {
) : ( - + )}
From 1cabe0a21b47150e17a1cba12e0954c0cbed46ed Mon Sep 17 00:00:00 2001 From: Aakash Singh Date: Wed, 13 Nov 2024 17:49:33 +0530 Subject: [PATCH 4/4] fix typo --- .../Facility/ConsultationDetails/ConsultationNursingTab.tsx | 6 +++--- ...LogUpdateAnalayseTable.tsx => LogUpdateAnalyseTable.tsx} | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/components/Facility/Consultations/{LogUpdateAnalayseTable.tsx => LogUpdateAnalyseTable.tsx} (96%) diff --git a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx index 58db082fa1f..6a7e33c6c95 100644 --- a/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx +++ b/src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx @@ -5,7 +5,7 @@ import Loading from "@/components/Common/Loading"; import PageTitle from "@/components/Common/PageTitle"; import Pagination from "@/components/Common/Pagination"; import { ConsultationTabProps } from "@/components/Facility/ConsultationDetails/index"; -import LogUpdateAnalayseTable from "@/components/Facility/Consultations/LogUpdateAnalayseTable"; +import LogUpdateAnalyseTable from "@/components/Facility/Consultations/LogUpdateAnalyseTable"; import { NursingPlotFields, NursingPlotRes, @@ -158,7 +158,7 @@ const NursingPlot = ({ consultationId }: ConsultationTabProps) => { ) : ( - + )} @@ -220,7 +220,7 @@ const RoutineSection = ({ consultationId }: ConsultationTabProps) => { return (
- >; } -const LogUpdateAnalayseTable: React.FC = ({ +const LogUpdateAnalyseTable: React.FC = ({ data, rows, choices = {}, @@ -90,4 +90,4 @@ const LogUpdateAnalayseTable: React.FC = ({ ); }; -export default LogUpdateAnalayseTable; +export default LogUpdateAnalyseTable;