Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the CSV Export button In Discharged Patients #9142

Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
914bbd9
Reverted all unwanted file chnages and handled errors with notifications
AnveshNalimela Dec 18, 2024
47c65ca
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 21, 2024
968a7f8
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 23, 2024
ac5d5a4
Merge branch 'develop' into issue/#8993/discharge-patients-export
nihal467 Dec 23, 2024
004776d
Removed some try-catch which realted to data constiency to make more …
AnveshNalimela Dec 23, 2024
25e035d
Merge branch 'issue/#8993/discharge-patients-export' of github.com:An…
AnveshNalimela Dec 23, 2024
23c4578
Chnaged Error to warn
AnveshNalimela Dec 23, 2024
6a5e6f2
Fixed the issue
AnveshNalimela Dec 23, 2024
044352d
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 23, 2024
169a0d2
Changed the warn msg to No patients found for export
AnveshNalimela Dec 23, 2024
4edd4cc
Merge branch 'issue/#8993/discharge-patients-export' of github.com:An…
AnveshNalimela Dec 23, 2024
a94ae47
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 23, 2024
6ed14f6
passed columns as args and Updated the function accordingly
AnveshNalimela Dec 24, 2024
dbaac65
changed the warn to error notification in case of any error
AnveshNalimela Dec 24, 2024
7c0ef26
Instead of Policy Id merge all columns having duplicates
AnveshNalimela Dec 24, 2024
9c5be7e
minor chnages and fixed all issues
AnveshNalimela Dec 24, 2024
468812f
removed patient ID as default parameter
AnveshNalimela Dec 24, 2024
e1613cb
Merge branch 'develop' into issue/#8993/discharge-patients-export
nihal467 Dec 24, 2024
06f122f
cahnged the calculateDataRange to calculateDaysBetween and changed to…
AnveshNalimela Dec 24, 2024
2980f72
Merge branch 'issue/#8993/discharge-patients-export' of github.com:An…
AnveshNalimela Dec 24, 2024
1e1b20b
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 24, 2024
588c7e3
Replaced buttonv2 with button,updated duration logic,dateRangeFields …
AnveshNalimela Dec 24, 2024
e96e46e
Merge branch 'develop' into issue/#8993/discharge-patients-export
AnveshNalimela Dec 26, 2024
843310b
removed >=0 and added translations for export and seven day period
AnveshNalimela Dec 26, 2024
6bf200b
Replaced with useQuery
AnveshNalimela Dec 26, 2024
0695dbb
Removed console logs
AnveshNalimela Dec 26, 2024
a1b68fc
simplified the useQuery implemnenation
AnveshNalimela Dec 26, 2024
ff2fab8
Added usePatientExport.ts
AnveshNalimela Dec 26, 2024
acfa579
Removed redudant logic in isExportAllowed
AnveshNalimela Dec 26, 2024
d4aad28
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 26, 2024
c435620
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 27, 2024
aa04ffe
Replaced all usetanstackqueryinstaed with useQuery
AnveshNalimela Dec 27, 2024
d40de85
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 28, 2024
a0af152
Merge branch 'ohcnetwork:develop' into issue/#8993/discharge-patients…
AnveshNalimela Dec 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/Utils/csvUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
export const csvGroupByColumn = (
data: string,
groupByColumn: string,
delimiter = ";",
): string => {
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
const [header, ...datalines] = data.trim().split("\n");
const headerColumns = header.split(",");
const groupByColumnIndex = headerColumns.indexOf(groupByColumn);

const groupedData = datalines.reduce(
(groupMap, line) => {
const columns = line.split(",");
const groupByKey = columns[groupByColumnIndex]?.trim();

if (!groupMap[groupByKey]) {
groupMap[groupByKey] = [];
}
groupMap[groupByKey].push(columns);
return groupMap;
},
{} as Record<string, string[][]>,
);
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved

const mergedLines = Object.values(groupedData).map((group) => {
if (!group.length) return "";

const mergedRow = [...group[0]];
headerColumns.forEach((column) => {
const index = headerColumns.indexOf(column);
const mergedValue = group
.map((columns) => columns[index]?.trim() || "")
.filter(Boolean)
.join(delimiter);

mergedRow[index] = mergedValue;
});
return mergedRow.join(",");
});

return header.concat(mergedLines.join("\n"));
};
11 changes: 11 additions & 0 deletions src/Utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,3 +571,14 @@ export const copyToClipboard = async (content: string) => {
Notification.Error({ msg: "Copying is not allowed" });
}
};

export const calculateDateRangeDuration = (
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
startDate: string,
endDate: string,
): number => {
if (!startDate && !endDate) return 0;
if (startDate && endDate) {
return Math.abs(dayjs(endDate).diff(dayjs(startDate), "days"));
}
return -1; // Invalid range when only one date is set
};
166 changes: 165 additions & 1 deletion src/components/Facility/DischargedPatientsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,20 @@ import {
} from "@/common/constants";
import { parseOptionId } from "@/common/utils";

import * as Notification from "@/Utils/Notifications";
import { csvGroupByColumn } from "@/Utils/csvUtils";
import routes from "@/Utils/request/api";
import request from "@/Utils/request/request";
import useTanStackQueryInstead from "@/Utils/request/useQuery";
import { formatPatientAge, humanizeStrings } from "@/Utils/utils";
import {
calculateDateRangeDuration,
formatPatientAge,
humanizeStrings,
parsePhoneNumber,
} from "@/Utils/utils";

import ButtonV2 from "../Common/ButtonV2";
import ExportMenu from "../Common/Export";
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved

const DischargedPatientsList = ({
facility_external_id,
Expand All @@ -55,6 +66,7 @@ const DischargedPatientsList = ({
updateQuery,
advancedFilter,
FilterBadges,
resultsPerPage,
updatePage,
clearSearch,
} = useFilters({
Expand Down Expand Up @@ -124,6 +136,71 @@ const DischargedPatientsList = ({
[updateQuery],
);

const params = {
page: qParams.page || 1,
limit: resultsPerPage,
name: qParams.name || undefined,
patient_no: qParams.patient_no || undefined,
phone_number: qParams.phone_number
? parsePhoneNumber(qParams.phone_number)
: undefined,
emergency_phone_number: qParams.emergency_phone_number
? parsePhoneNumber(qParams.emergency_phone_number)
: undefined,
offset: (qParams.page ? qParams.page - 1 : 0) * resultsPerPage,
ordering: qParams.ordering || undefined,

gender: qParams.gender || undefined,
category: qParams.category || undefined,
age_min: qParams.age_min || undefined,
age_max: qParams.age_max || undefined,
last_consultation_admitted_bed_type_list:
qParams.last_consultation_admitted_bed_type_list || undefined,
last_consultation__consent_types:
qParams.last_consultation__consent_types || undefined,
last_consultation__new_discharge_reason:
qParams.last_consultation__new_discharge_reason || undefined,
last_consultation_is_telemedicine:
qParams.last_consultation_is_telemedicine || undefined,
ventilator_interface: qParams.ventilator_interface || undefined,
last_consultation_medico_legal_case:
qParams.last_consultation_medico_legal_case || undefined,
ration_card_category: qParams.ration_card_category || undefined,

diagnoses: qParams.diagnoses || undefined,
diagnoses_confirmed: qParams.diagnoses_confirmed || undefined,
diagnoses_provisional: qParams.diagnoses_provisional || undefined,
diagnoses_unconfirmed: qParams.diagnoses_unconfirmed || undefined,
diagnoses_differential: qParams.diagnoses_differential || undefined,

created_date_before: qParams.created_date_before || undefined,
created_date_after: qParams.created_date_after || undefined,
modified_date_before: qParams.modified_date_before || undefined,
modified_date_after: qParams.modified_date_after || undefined,
last_consultation_encounter_date_before:
qParams.last_consultation_encounter_date_before || undefined,
last_consultation_encounter_date_after:
qParams.last_consultation_encounter_date_after || undefined,
last_consultation_discharge_date_before:
qParams.last_consultation_discharge_date_before || undefined,
last_consultation_discharge_date_after:
qParams.last_consultation_discharge_date_after || undefined,

local_body: qParams.lsgBody || undefined,
district: qParams.district || undefined,

number_of_doses: qParams.number_of_doses || undefined,
is_declared_positive: qParams.is_declared_positive || undefined,
covin_id: qParams.covin_id || undefined,
date_declared_positive_before:
qParams.date_declared_positive_before || undefined,
date_declared_positive_after:
qParams.date_declared_positive_after || undefined,
last_vaccinated_date_before:
qParams.last_vaccinated_date_before || undefined,
last_vaccinated_date_after: qParams.last_vaccinated_date_after || undefined,
};

useEffect(() => {
if (!qParams.phone_number && phone_number.length >= 13) {
setPhoneNumber("+91");
Expand All @@ -136,6 +213,29 @@ const DischargedPatientsList = ({
}
}, [qParams]);

const date_range_fields = [
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
[params.created_date_before, params.created_date_after],
[params.modified_date_before, params.modified_date_after],
[params.date_declared_positive_before, params.date_declared_positive_after],
[params.last_vaccinated_date_before, params.last_vaccinated_date_after],
[
params.last_consultation_encounter_date_before,
params.last_consultation_encounter_date_after,
],
[
params.last_consultation_discharge_date_before,
params.last_consultation_discharge_date_after,
],
];

const durations = date_range_fields.map(([startDate, endDate]) =>
calculateDateRangeDuration(startDate, endDate),
);

const isExportAllowed =
durations.every((x) => x >= 0 && x <= 7) &&
!durations.every((x) => x === 0);

AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
const { data: districtData } = useTanStackQueryInstead(routes.getDistrict, {
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
pathParams: {
id: qParams.district,
Expand Down Expand Up @@ -293,6 +393,70 @@ const DischargedPatientsList = ({
selected={qParams.ordering}
onSelect={(e) => updateQuery({ ordering: e.ordering })}
/>
<div className="tooltip w-full md:w-auto" id="patient-export">
{!isExportAllowed ? (
<ButtonV2
onClick={() => {
advancedFilter.setShow(true);
setTimeout(() => {
const element =
document.getElementById("bed-type-select");
if (element)
element.scrollIntoView({ behavior: "smooth" });
Notification.Warn({
msg: "Please select a seven day period.",
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
});
}, 500);
}}
className="mr-5 w-full lg:w-fit"
>
<CareIcon icon="l-export" />
<span className="lg:my-[3px]">Export</span>
</ButtonV2>
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
) : (
<ExportMenu
disabled={!isExportAllowed}
exportItems={[
{
label: "Export Discharged patients",
action: async () => {
const query = {
...params,
csv: true,
};
const pathParams = { facility_external_id };
const { data } = await request(
routes.listFacilityDischargedPatients,
{
query,
pathParams,
},
);
return data ?? null;
},
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
parse: (data) => {
try {
return csvGroupByColumn(data, "Patient ID");
} catch (e) {
if (e instanceof Error) {
Notification.Error({
msg: e.message,
});
}
return "";
}
},
},
]}
/>
)}

{!isExportAllowed && (
<span className="tooltip-text tooltip-bottom -translate-x-1/2">
Select a seven day period
</span>
)}
</div>
</div>
</>
}
Expand Down
80 changes: 17 additions & 63 deletions src/components/Patient/ManagePatients.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
} from "@/common/constants";
import { parseOptionId } from "@/common/utils";

import { csvGroupByColumn } from "@/Utils/csvUtils";
import routes from "@/Utils/request/api";

import Chip from "../../CAREUI/display/Chip";
Expand All @@ -40,6 +41,7 @@ import * as Notification from "../../Utils/Notifications";
import request from "../../Utils/request/request";
import useTanStackQueryInstead from "../../Utils/request/useQuery";
import {
calculateDateRangeDuration,
formatPatientAge,
humanizeStrings,
isAntenatal,
Expand Down Expand Up @@ -221,74 +223,15 @@ export const PatientManager = () => {
],
];

const durations = date_range_fields.map((field: string[]) => {
// XOR (checks if only one of the dates is set)
if (!field[0] !== !field[1]) {
return -1;
}
if (field[0] && field[1]) {
return dayjs(field[0]).diff(dayjs(field[1]), "days");
}
return 0;
});
const durations = date_range_fields.map(([startDate, endDate]) =>
calculateDateRangeDuration(startDate, endDate),
);

const isExportAllowed =
durations.every((x) => x >= 0 && x <= 7) &&
!durations.every((x) => x === 0);

let managePatients: any = null;
const preventDuplicatePatientsDuetoPolicyId = (data: any) => {
// Generate a array which contains imforamation of duplicate patient IDs and there respective linenumbers
const lines = data.split("\n"); // Split the data into individual lines
const idsMap = new Map(); // To store indices of lines with the same patient ID

lines.map((line: any, i: number) => {
const patientId = line.split(",")[0]; // Extract the patient ID from each line
if (idsMap.has(patientId)) {
idsMap.get(patientId).push(i); // Add the index to the existing array
} else {
idsMap.set(patientId, [i]); // Create a new array with the current index
}
});

const linesWithSameId = Array.from(idsMap.entries())
.filter(([_, indices]) => indices.length > 1)
.map(([patientId, indices]) => ({
patientId,
indexSame: indices,
}));

// after getting the array of duplicate patient IDs and there respective linenumbers we will merge the policy IDs of the duplicate patients

linesWithSameId.map((lineInfo) => {
const indexes = lineInfo.indexSame;
//get policyid of all the duplicate patients and merge them by seperating them with a semicolon
const mergedPolicyId = `${indexes.map((currentIndex: number) => {
return `${lines[currentIndex].split(",")[5]};`;
})}`.replace(/,/g, "");
// replace the policy ID of the first patient with the merged policy ID
const arrayOfCurrentLine = lines[indexes[0]].split(",");
arrayOfCurrentLine[5] = mergedPolicyId;
const lineAfterMerge = arrayOfCurrentLine.join(",");
lines[indexes[0]] = `${lineAfterMerge}`;
});

// after merging the policy IDs of the duplicate patients we will remove the duplicate patients from the data
const uniqueLines = [];
const ids = new Set(); // To keep track of unique patient IDs

for (const line of lines) {
const patientId = line.split(",")[0]; // Extract the patient ID from each line
if (!ids.has(patientId)) {
uniqueLines.push(line);
ids.add(patientId);
}
}

const cleanedData = uniqueLines.join("\n"); // Join the unique lines back together
return cleanedData;
};

const { loading: isLoading, data } = useTanStackQueryInstead(
routes.patientList,
{
Expand Down Expand Up @@ -948,7 +891,18 @@ export const PatientManager = () => {
});
return data ?? null;
},
parse: preventDuplicatePatientsDuetoPolicyId,
parse: (data) => {
AnveshNalimela marked this conversation as resolved.
Show resolved Hide resolved
try {
return csvGroupByColumn(data, "Patient ID");
} catch (e) {
if (e instanceof Error) {
Notification.Error({
msg: e.message,
});
}
return "";
}
},
},
]}
/>
Expand Down
Loading