Skip to content

Commit

Permalink
made a reusable component for table in routine and nursing care proce…
Browse files Browse the repository at this point in the history
…dures
  • Loading branch information
Sahil-Sinha-11 authored and sainak committed Nov 11, 2024
1 parent 6931845 commit 1e87eb8
Show file tree
Hide file tree
Showing 3 changed files with 236 additions and 219 deletions.
228 changes: 141 additions & 87 deletions src/components/Facility/ConsultationDetails/ConsultationNursingTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<div>
<PageTitle
title={t("nursing_information")}
hideBack
breadcrumbs={false}
/>
<div>
<h4>{t("routine")}</h4>
<RoutineSection {...props} />
</div>
<div>
<h4>{t("nursing_care")}</h4>
<NursingPlot
facilityId={props.facilityId}
patientId={props.patientId}
consultationId={props.consultationId}
/>
</div>
</div>
);
}

const REVERSE_CHOICES = {
appetite: {
Expand Down Expand Up @@ -114,6 +91,116 @@ const ROUTINE_ROWS = [
{ subField: true, field: "appetite" } as const,
];

const NursingPlot = ({ consultationId }: ConsultationTabProps) => {
const { t } = useTranslation();
const [results, setResults] = useState<DailyRoundsRes["results"]>({});
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
.map((x) =>
x.nursing
? 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: ProcedureType) => i.procedure === field,
);
return filtered.length > 0;
};

const areFieldsEmpty = () => {
let emptyFieldCount = 0;
for (const field of NURSING_CARE_PROCEDURES) {
if (!filterEmpty(field)) emptyFieldCount++;
}
return emptyFieldCount === NURSING_CARE_PROCEDURES.length;
};

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<string, any>, item: any) => {
if (!acc[item.date]) acc[item.date] = {};
acc[item.date][item.procedure] = item.description;
return acc;
},
{},
);

return (
<div>
<div>
{areFieldsEmpty() ? (
<div className="mt-1 w-full rounded-lg border bg-white p-4 shadow">
<div className="flex items-center justify-center text-2xl font-bold text-secondary-500">
{t("no_data_found")}
</div>
</div>
) : (
<LogUpdateAnalayseTable data={mappedData} rows={rows} />
)}
</div>

{totalCount > PAGINATION_LIMIT && !areFieldsEmpty() && (
<div className="mt-4 flex w-full justify-center">
<Pagination
cPage={currentPage}
defaultPerPage={PAGINATION_LIMIT}
data={{ totalCount }}
onChange={handlePagination}
/>
</div>
)}
</div>
);
};

const RoutineSection = ({ consultationId }: ConsultationTabProps) => {
const { t } = useTranslation();
const [page, setPage] = useState(1);
Expand Down Expand Up @@ -158,65 +245,11 @@ const RoutineSection = ({ consultationId }: ConsultationTabProps) => {

return (
<div className="pb-8 pt-4">
<div className="m-2 w-full overflow-hidden overflow-x-auto rounded-lg border border-black shadow md:w-fit">
<table className="border-collapse overflow-hidden rounded-lg border bg-secondary-100">
<thead className="bg-white shadow">
<tr>
<th className="w-48 border-b-2 border-r-2 border-black" />
{Object.keys(results).map((date) => (
<th
key={date}
className="border border-b-2 border-secondary-500 border-b-black p-1 text-sm font-semibold"
>
<p>{formatDate(date)}</p>
<p>{formatTime(date)}</p>
</th>
))}
</tr>
</thead>
<tbody className="bg-secondary-200">
{ROUTINE_ROWS.map((row) => (
<tr
key={row.field ?? row.title}
className={classNames(
row.title && "border-t-2 border-t-secondary-600",
)}
>
<td
className={classNames(
"border border-r-2 border-secondary-500 border-r-black bg-white p-2",
row.subField ? "pl-4 font-medium" : "font-bold",
)}
>
{row.title ?? t(`LOG_UPDATE_FIELD_LABEL__${row.field!}`)}
</td>
{row.field &&
Object.values(results).map((obj, idx) => (
<td
key={`${row.field}-${idx}`}
className={classNames(
"border border-secondary-500 bg-secondary-100 p-2 text-center font-medium",
)}
>
{(() => {
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);
})()}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
<LogUpdateAnalayseTable
data={results}
rows={ROUTINE_ROWS}
choices={REVERSE_CHOICES}
/>

{totalCount != null && totalCount > PAGINATION_LIMIT && (
<div className="mt-4 flex w-full justify-center">
Expand All @@ -231,3 +264,24 @@ const RoutineSection = ({ consultationId }: ConsultationTabProps) => {
</div>
);
};

export default function ConsultationNursingTab(props: ConsultationTabProps) {
const { t } = useTranslation();
return (
<div>
<PageTitle
title={t("nursing_information")}
hideBack
breadcrumbs={false}
/>
<div>
<h4>{t("routine")}</h4>
<RoutineSection {...props} />
</div>
<div>
<h4>{t("nursing_care")}</h4>
<NursingPlot {...props} />
</div>
</div>
);
}
95 changes: 95 additions & 0 deletions src/components/Facility/Consultations/LogUpdateAnalayseTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React from "react";
import { useTranslation } from "react-i18next";

import { classNames, formatDate, formatTime } from "@/Utils/utils";

interface SharedSectionTableProps {
data: Record<string, any>;
rows: Array<{ title?: string; field?: string; subField?: boolean }>;
choices?: Record<string, Record<number | string, string>>;
}

const LogUpdateAnalayseTable: React.FC<SharedSectionTableProps> = ({
data,
rows,
choices = {},
}) => {
const { t } = useTranslation();

// Helper function to get the display value
const getDisplayValue = (
value: string | boolean | null | undefined,
field?: string,
): string => {
if (value == null) {
return " ";
}

if (typeof value === "boolean") {
return t(value ? "yes" : "no");
}
if (field && choices[field]) {
const choice =
choices[field][value as keyof (typeof choices)[typeof field]];
return choice ? t(`${field.toUpperCase()}__${choice}`) : "-";
}
if (value && typeof value == "string") return value;

return "-";
};

return (
<div className="m-2 w-full overflow-hidden overflow-x-auto rounded-lg border border-black shadow md:w-fit">
<table className="border-collapse rounded-lg border bg-secondary-100">
<thead className="sticky top-0 bg-white shadow">
<tr>
<th className="sticky left-0 border-b-2 border-r-2 border-black bg-white"></th>
{Object.keys(data).map((date) => (
<>
<th
key={date}
className="w-40 border border-b-2 border-secondary-500 border-b-black p-1 text-sm font-semibold"
>
<p>{formatDate(date)}</p>
<p>{formatTime(date)}</p>
</th>
</>
))}
</tr>
</thead>
<tbody className="bg-secondary-200">
{rows.map((row) => (
<tr
key={row.field ?? row.title}
className={classNames(
row.title && "border-t-2 border-t-secondary-600",
)}
>
<th
className={classNames(
"sticky left-0 border border-r-2 border-secondary-500 border-r-black bg-white p-2",
row.subField ? "pl-4 font-medium" : "font-bold",
)}
>
{row.title ?? t(`LOG_UPDATE_FIELD_LABEL__${row.field!}`)}
</th>
{Object.values(data).map((obj, idx) => {
const value = obj[row.field!];
return (
<td
key={`${row.field}-${idx}`}
className="w-80 border border-l-2 border-secondary-500 bg-secondary-100 p-2 text-center font-medium"
>
{getDisplayValue(value, row.field)}
</td>
);
})}
</tr>
))}
</tbody>
</table>
</div>
);
};

export default LogUpdateAnalayseTable;
Loading

0 comments on commit 1e87eb8

Please sign in to comment.