diff --git a/netlify.toml b/netlify.toml
index f23b951ff21..c7b76577ef8 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -9,7 +9,7 @@ NODE_OPTIONS = "--max_old_space_size=4096"
[[redirects]]
from = "/api/*"
-to = "https://careapi.ohc.network/api/:splat"
+to = "https://care-ai-poc.ohc.network/api/:splat"
status = 200
force = true
diff --git a/src/Components/Common/components/AccordionV2.tsx b/src/Components/Common/components/AccordionV2.tsx
index ef4948d8ae3..7b410e8e320 100644
--- a/src/Components/Common/components/AccordionV2.tsx
+++ b/src/Components/Common/components/AccordionV2.tsx
@@ -2,6 +2,7 @@ import { useRef, useState } from "react";
import { classNames } from "../../../Utils/utils";
export default function AccordionV2(props: {
+ prefix?: JSX.Element | JSX.Element[];
children: JSX.Element | JSX.Element[];
expandIcon?: JSX.Element;
title: JSX.Element | JSX.Element[] | string;
@@ -14,6 +15,7 @@ export default function AccordionV2(props: {
return (
+ <>{props.prefix}>
+
setOpenAIDischargeSummaryDialog(true)}>
+
+ AI {t("discharge_summary")}
+
setOpenDischargeSummaryDialog(true)}>
{t("discharge_summary")}
diff --git a/src/Components/Facility/DischargeAISummaryModal.tsx b/src/Components/Facility/DischargeAISummaryModal.tsx
new file mode 100644
index 00000000000..01d80710776
--- /dev/null
+++ b/src/Components/Facility/DischargeAISummaryModal.tsx
@@ -0,0 +1,579 @@
+import { useState } from "react";
+import DialogModal from "../Common/Dialog";
+import TextFormField from "../Form/FormFields/TextFormField";
+import { ConsultationModel } from "./models";
+import { Cancel, Submit } from "../Common/components/ButtonV2";
+import CareIcon from "../../CAREUI/icons/CareIcon";
+import {
+ EmailValidator,
+ MultiValidator,
+ RequiredFieldValidator,
+} from "../Form/FieldValidators";
+import { useDispatch } from "react-redux";
+import {
+ emailDischargeSummary,
+ generateDischargeSummary,
+} from "../../Redux/actions";
+import { Error, Success } from "../../Utils/Notifications";
+import { previewDischargeSummary } from "../../Redux/actions";
+import { useTranslation } from "react-i18next";
+import CheckBoxFormField from "../Form/FormFields/CheckBoxFormField";
+import {
+ FieldChangeEvent,
+ FieldChangeEventHandler,
+} from "../Form/FormFields/Utils";
+import CollapseV2 from "../Common/components/CollapseV2";
+import AccordionV2 from "../Common/components/AccordionV2";
+import TextAreaFormField from "../Form/FormFields/TextAreaFormField";
+
+interface Props {
+ show: boolean;
+ onClose: () => void;
+ consultation: ConsultationModel;
+}
+
+const options = [
+ {
+ category: "Generic",
+ label: "Facility Name",
+ value: "patient.facility.name",
+ },
+ {
+ category: "Patient Information",
+ label: "Patient Name",
+ value: "patient.name",
+ },
+ {
+ category: "Patient Information",
+ label: "Patient Gender",
+ value: "patient.get_gender_display",
+ },
+ {
+ category: "Patient Information",
+ label: "Patient Age",
+ value: "patient.age",
+ },
+ {
+ category: "Patient Information",
+ label: "Patient Date of Birth",
+ value: "patient.date_of_birth",
+ },
+ {
+ category: "Patient Information",
+ label: "Patient Blood Group",
+ value: "patient.blood_group",
+ },
+ {
+ category: "Patient Information",
+ label: "Patient Phone Number",
+ value: "patient.phone_number",
+ },
+ {
+ category: "Patient Information",
+ label: "Patient Address",
+ value: "patient.address",
+ },
+ {
+ category: "Consultation",
+ label: "Consultation Status",
+ value: "consultation.get_consultation_status_display",
+ },
+ {
+ category: "Consultation",
+ label: "Consultation Suggestion",
+ value: "consultation.get_suggestion_display",
+ },
+ {
+ category: "Consultation",
+ label: "Admission Date",
+ value: "consultation.admission_date.date",
+ condition: "consultation.suggestion === 'A'",
+ },
+ {
+ category: "Consultation",
+ label: "Consultation Notes",
+ value: "consultation.consultation_notes",
+ condition: "consultation.consultation_notes",
+ },
+ {
+ category: "Consultation",
+ label: "Special Instruction",
+ value: "consultation.special_instruction",
+ condition: "consultation.special_instruction",
+ },
+ {
+ category: "Consultation",
+ label: "Prescribed Medication",
+ value: "consultation.prescribed_medication",
+ condition: "consultation.prescribed_medication",
+ },
+ {
+ category: "Consultation",
+ label: "Procedure",
+ value: "consultation.procedure",
+ condition: "consultation.procedure",
+ },
+ {
+ category: "Consultation",
+ label: "Investigation",
+ value: "investigations",
+ condition: "consultation.investigation",
+ },
+ {
+ category: "Patient Information",
+ label: "Present Health",
+ value: "patient.present_health",
+ },
+ {
+ category: "Patient Information",
+ label: "Ongoing Medication",
+ value: "patient.ongoing_medication",
+ },
+ {
+ category: "Patient Information",
+ label: "Allergies",
+ value: "patient.allergies",
+ },
+ {
+ category: "Patient Information",
+ label: "IP No",
+ value: "consultation.ip_no",
+ },
+ {
+ category: "Patient Information",
+ label: "Weight",
+ value: "consultation.weight",
+ },
+ {
+ category: "Patient Information",
+ label: "Height",
+ value: "consultation.height",
+ },
+ {
+ category: "Patient Information",
+ label: "Symptoms",
+ value: "consultation.get_symptoms_display|title",
+ condition: "consultation.consultation_status !== 1",
+ },
+ {
+ category: "Patient Information",
+ label: "Symptoms Onset Date",
+ value: "consultation.symptoms_onset_date.date",
+ condition: "consultation.consultation_status !== 1",
+ },
+ {
+ category: "Patient Information",
+ label: "Date of Result",
+ value: "patient.date_of_result.date",
+ condition: "patient.disease_status === 2 && patient.date_of_result",
+ },
+ {
+ category: "Patient Information",
+ label: "Is Vaccinated",
+ value: "patient.is_vaccinated",
+ condition: "patient.disease_status === 2 && patient.is_vaccinated",
+ },
+ {
+ category: "Patient Medical History",
+ label: "Medical History",
+ value: "medical_history",
+ condition: "medical_history",
+ },
+ {
+ category: "HCX Information",
+ label: "Insurer Name",
+ value: "hcx",
+ condition: "hcx",
+ },
+ {
+ category: "Diagnosis",
+ label: "Provisional Diagnosis",
+ value: "provisional_diagnosis",
+ condition: "provisional_diagnosis",
+ },
+ {
+ category: "Diagnosis",
+ label: "Diagnosis ID",
+ value: "diagnosis",
+ condition: "diagnosis",
+ },
+ {
+ category: "Discharge",
+ label: "Discharge Notes",
+ value: "consultation.discharge_notes",
+ condition: "consultation.suggestion === 'DD'",
+ },
+ {
+ category: "Discharge",
+ label: "Death Date Time",
+ value: "consultation.death_datetime",
+ condition: "consultation.suggestion === 'DD'",
+ },
+ {
+ category: "Discharge",
+ label: "Death Confirmed By",
+ value: "consultation.death_confirmed_by",
+ condition: "consultation.suggestion === 'DD'",
+ },
+ {
+ category: "Discharge",
+ label: "Discharge Summary",
+ value: "consultation.suggestion === 'R'",
+ },
+ {
+ category: "Prescription",
+ label: "Prescription",
+ value: "prescriptions",
+ condition: "prescriptions",
+ },
+ {
+ category: "PRN Prescription",
+ label: "PRN Prescription",
+ value: "prn_prescriptions",
+ condition: "prn_prescriptions",
+ },
+ {
+ category: "Examination",
+ label: "Examination Details",
+ value: "consultation.examination_details",
+ },
+
+ {
+ category: "Sample Information",
+ label: "Sample",
+ value: "samples",
+ condition: "samples",
+ },
+ {
+ category: "Consultation",
+ label: "Treatment Plan",
+ value: "consultation.treatment_plan",
+ },
+ {
+ category: "Admission Details",
+ label: "Daily Rounds",
+ value: "dailyrounds",
+ condition: "dailyrounds",
+ },
+ {
+ category: "Discharge Information",
+ label: "Discharge Date",
+ value: "consultation.discharge_date",
+ },
+ {
+ category: "Discharge Information",
+ label: "Discharge Reason",
+ value: "consultation.get_discharge_reason_display",
+ },
+ {
+ category: "Discharge Information",
+ label: "Discharge Prescription ",
+ value: "discharge_prescriptions",
+ condition:
+ "discharge_prescriptions",
+ },
+ {
+ category: "Discharge Information",
+ label: "Discharge PRN Prescription ",
+ value: "discharge_prn_prescriptions",
+ condition:
+ "discharge_prn_prescriptions",
+ },
+
+ {
+ category: "Discharge Information",
+ label: "Discharge Notes",
+ value: "consultation.discharge_notes",
+ },
+ {
+ category: "Discharge Information",
+ label: "Verified By",
+ value: "consultation.verified_by|linebreaks",
+ },
+ {
+ category: "Discharge Information",
+ label: "Discharge Summary",
+ value: "summary.discharge_summary",
+ },
+];
+
+export default function DischargeAISummaryModal(props: Props) {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const [email, setEmail] = useState("");
+ const [additional_details, setAdditionalDetails] = useState("");
+ const [emailError, setEmailError] = useState("");
+ const [emailing, setEmailing] = useState(false);
+ const [downloading, setDownloading] = useState(false);
+ const [generating, setGenerating] = useState(false);
+ const [regenDischargeSummary, setRegenDischargeSummary] = useState(false);
+ const [selectedOptions, setSelectedOptions] = useState([]);
+
+ const handleCheckboxChange = (e: FieldChangeEvent) => {
+ const value = e.name;
+ setSelectedOptions((prevSelectedOptions) => {
+ if (prevSelectedOptions.includes(value)) {
+ return prevSelectedOptions.filter((option) => option !== value);
+ }
+ return [...prevSelectedOptions, value];
+ });
+ };
+
+ const popup = (url: string) => {
+ window.open(url, "_blank");
+ setDownloading(false);
+ props.onClose();
+ };
+
+ const waitForDischargeSummary = async () => {
+ setGenerating(true);
+ Success({ msg: t("generating_discharge_summary") + "..." });
+
+ let section_data = {}
+ if (selectedOptions.length > 0) {
+ section_data = selectedOptions.join("\n");
+ }
+
+ setTimeout(async () => {
+ setGenerating(false);
+
+ const res = await dispatch(
+ generateDischargeSummary({section_data: section_data, is_ai: true},{ external_id: props.consultation.id })
+ );
+
+ if (res.status === 200) {
+ popup(res.data.read_signed_url);
+ return;
+ }
+
+ Error({
+ msg: t("discharge_summary_not_ready") + " " + t("try_again_later"),
+ });
+ setDownloading(false);
+ }, 7000);
+ };
+
+ const handleRegenDischargeSummary = async () => {
+ setDownloading(true);
+ const res = await dispatch(
+ generateDischargeSummary({},{ external_id: props.consultation.id })
+ );
+ if (res.status === 406) {
+ Error({
+ msg:
+ res.data?.message ||
+ t("discharge_summary_not_ready") + " " + t("try_again_later"),
+ });
+ setDownloading(false);
+ return;
+ }
+ setRegenDischargeSummary(false);
+ waitForDischargeSummary();
+ };
+
+ const downloadDischargeSummary = async () => {
+ let section_data = {}
+ if (selectedOptions.length > 0) {
+ for(let selectedOption of selectedOptions) {
+ let [category, label, value] = selectedOption.split('-')
+ let value_split = value.split('.')
+ if (value_split[0] in section_data) {
+ section_data[value_split[0]] += `${label}: {{ ${value}|safe }}\n`
+ } else {
+ section_data[value_split[0]] = `${category}\n\n${label}: {{ ${value}|safe }}\n`
+ }
+ }
+ }
+
+ // returns summary or 202 if new create task started
+ const res = await dispatch(
+ generateDischargeSummary({section_data: section_data, is_ai: true},{ external_id: props.consultation.id })
+ );
+
+ if (res.status === 202) {
+ // wait for the automatic task to finish
+ //waitForDischargeSummary();
+ return;
+ }
+
+ if (res.status === 200) {
+ popup(res.data.read_signed_url);
+ return;
+ }
+
+ Error({
+ msg: t("discharge_summary_not_ready") + " " + t("try_again_later"),
+ });
+ setDownloading(false);
+ };
+
+ const handleDownload = async () => {
+ setDownloading(true);
+ downloadDischargeSummary();
+ };
+
+ const handleEmail = async () => {
+ setEmailing(true);
+
+ const emailError = MultiValidator([
+ RequiredFieldValidator(),
+ EmailValidator(),
+ ])(email);
+
+ if (emailError) {
+ setEmailError(emailError);
+ setEmailing(false);
+ return;
+ }
+
+ const res = await dispatch(
+ emailDischargeSummary({ email }, { external_id: props.consultation.id })
+ );
+
+ if (res.status === 202) {
+ Success({ msg: t("email_success") });
+ props.onClose();
+ }
+
+ setEmailing(false);
+ };
+
+ const optionsByCategory = options.reduce((acc: any, option) => {
+ // if (option.condition && !eval(option.condition)) {
+ // return acc;
+ // }
+
+ if (!acc[option.category]) {
+ acc[option.category] = [];
+ }
+ acc[option.category].push(option);
+ return acc;
+ }, {});
+
+ const handleCategoryCheckboxChange = (category: string, checked: boolean) => {
+ const optionsInCategory = optionsByCategory[category];
+ const optionValuesInCategory = optionsInCategory.map(
+ (option) => `${option.category}-${option.label}-${option.value}`
+ );
+ const newSelectedOptions = checked
+ ? [...selectedOptions, ...optionValuesInCategory]
+ : selectedOptions.filter(
+ (option) => !optionValuesInCategory.includes(option)
+ );
+ setSelectedOptions(newSelectedOptions);
+ };
+
+ return (
+
+
+
+
+ Select the fields you want to include in the discharge summary
+
+
+
+ {`${t("disclaimer")}: ${t("generated_summary_caution")}`}
+
+
+
+
+ {Object.entries(optionsByCategory).map(([category, options]) => (
+
option.category === category)
+ .every((option) =>
+ selectedOptions.includes(
+ `${option.category}-${option.label}-${option.value}`
+ )
+ )}
+ onChange={(e) =>
+ handleCategoryCheckboxChange(category, e.target.checked)
+ }
+ />
+ }
+ title={category}
+ className="mb-2 rounded-lg border border-gray-300 p-4"
+ >
+
+ {options.map((option) => (
+
+
+
+ ))}
+
+
+ ))}
+
+
+
setAdditionalDetails(e.value)}
+ />
+
+ setEmail(e.value)}
+ error={emailError}
+ />
+ {!props.consultation.discharge_date && (
+ setRegenDischargeSummary(e.value)}
+ />
+ )}
+
+
+
+ {downloading ? (
+
+ ) : (
+
+ )}
+
+ {generating
+ ? t("generating") + "..."
+ : downloading
+ ? t("downloading") + "..."
+ : t("download")}
+
+
+ {/*
+ {emailing ? (
+
+ ) : (
+
+ )}
+ {t("send_email")}
+ */}
+
+
+
+ );
+}
diff --git a/src/Components/Facility/DischargeSummaryModal.tsx b/src/Components/Facility/DischargeSummaryModal.tsx
index 36e2de8a591..d6fbcf626d6 100644
--- a/src/Components/Facility/DischargeSummaryModal.tsx
+++ b/src/Components/Facility/DischargeSummaryModal.tsx
@@ -49,7 +49,7 @@ export default function DischargeSummaryModal(props: Props) {
setGenerating(false);
const res = await dispatch(
- previewDischargeSummary({ external_id: props.consultation.id })
+ generateDischargeSummary({},{ external_id: props.consultation.id})
);
if (res.status === 200) {
@@ -67,7 +67,7 @@ export default function DischargeSummaryModal(props: Props) {
const handleRegenDischargeSummary = async () => {
setDownloading(true);
const res = await dispatch(
- generateDischargeSummary({ external_id: props.consultation.id })
+ generateDischargeSummary({},{ external_id: props.consultation.id })
);
if (res.status === 406) {
Error({
@@ -85,7 +85,7 @@ export default function DischargeSummaryModal(props: Props) {
const downloadDischargeSummary = async () => {
// returns summary or 202 if new create task started
const res = await dispatch(
- previewDischargeSummary({ external_id: props.consultation.id })
+ generateDischargeSummary({ external_id: props.consultation.id, section_data: "", is_ai: false })
);
if (res.status === 202) {
@@ -115,7 +115,6 @@ export default function DischargeSummaryModal(props: Props) {
downloadDischargeSummary();
};
-
const handleEmail = async () => {
setEmailing(true);
diff --git a/src/Redux/actions.tsx b/src/Redux/actions.tsx
index 26e006f4cea..fe9bfb7110b 100644
--- a/src/Redux/actions.tsx
+++ b/src/Redux/actions.tsx
@@ -592,8 +592,11 @@ export const deleteLastInventoryLog = (params: object) => {
return fireRequest("deleteLastInventoryLog", [], {}, params);
};
-export const generateDischargeSummary = (pathParams: object) => {
- return fireRequest("dischargeSummaryGenerate", [], {}, pathParams);
+export const generateDischargeSummary = (
+ params: object,
+ pathParams: object
+) => {
+ return fireRequest("dischargeSummaryGenerate", [], params, pathParams);
};
export const previewDischargeSummary = (pathParams: object) => {
return fireRequest(