diff --git a/cypress/e2e/patient_spec/patient_crud.cy.ts b/cypress/e2e/patient_spec/patient_crud.cy.ts index 4fef861aeab..57bae83a880 100644 --- a/cypress/e2e/patient_spec/patient_crud.cy.ts +++ b/cypress/e2e/patient_spec/patient_crud.cy.ts @@ -111,7 +111,9 @@ describe("Patient Creation with consultation", () => { updatePatientPage.visitConsultationPage(); patientPage.verifyStatusCode(); patientConsultationPage.fillIllnessHistory("history"); - patientConsultationPage.selectConsultationStatus("Out-patient (walk in)"); + patientConsultationPage.selectConsultationStatus( + "Outpatient/Emergency Room" + ); patientConsultationPage.selectSymptoms("ASYMPTOMATIC"); patientConsultationPage.enterConsultationDetails( @@ -140,9 +142,6 @@ describe("Patient Creation with consultation", () => { updatePatientPage.visitUpdatedPatient(); patientConsultationPage.visitEditConsultationPage(); patientConsultationPage.fillIllnessHistory("editted"); - patientConsultationPage.selectConsultationStatus( - "Referred from other hospital" - ); patientConsultationPage.updateSymptoms("FEVER"); patientConsultationPage.setSymptomsDate("01082023"); patientConsultationPage.updateConsultation(); diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index ce1fdc1e393..7d2be8734dd 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -1,8 +1,8 @@ export class PatientConsultationPage { selectConsultationStatus(status: string) { - cy.get("#consultation_status").scrollIntoView(); - cy.get("#consultation_status").should("be.visible"); - cy.get("#consultation_status") + cy.get("#route_to_facility").scrollIntoView(); + cy.get("#route_to_facility").should("be.visible"); + cy.get("#route_to_facility") .click() .then(() => { cy.get("[role='option']").contains(status).click(); @@ -60,7 +60,7 @@ export class PatientConsultationPage { cy.get("#principal-diagnosis-select [role='option']").first().click(); cy.get("#consultation_notes").click().type(consulationNotes); - cy.get("#verified_by") + cy.get("#treating_physician") .click() .type(verificationBy) .then(() => { diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index 0b08b4b9a42..21dbd6763b8 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -332,14 +332,6 @@ export const CONSULTATION_SUGGESTION = [ { id: "DD", text: "Declare Death" }, ]; -export const CONSULTATION_STATUS = [ - { id: "1", text: "Brought Dead" }, - { id: "2", text: "Transferred from ward" }, - { id: "3", text: "Transferred from ICU" }, - { id: "4", text: "Referred from other hospital" }, - { id: "5", text: "Out-patient (walk in)" }, -]; - export const ADMITTED_TO = [ { id: "1", text: "Isolation" }, { id: "2", text: "ICU" }, diff --git a/src/Components/Common/RouteToFacilitySelect.tsx b/src/Components/Common/RouteToFacilitySelect.tsx new file mode 100644 index 00000000000..0f36d632e42 --- /dev/null +++ b/src/Components/Common/RouteToFacilitySelect.tsx @@ -0,0 +1,31 @@ +import { SelectFormField } from "../Form/FormFields/SelectFormField"; +import { + FormFieldBaseProps, + useFormFieldPropsResolver, +} from "../Form/FormFields/Utils"; + +export const ROUTE_TO_FACILITY_OPTIONS = { + 10: "Outpatient/Emergency Room", + 20: "Referred from another facility", + 30: "Internal Transfer within the facility", +}; + +export type RouteToFacility = keyof typeof ROUTE_TO_FACILITY_OPTIONS; + +export const keys = Object.keys(ROUTE_TO_FACILITY_OPTIONS).map((key) => + parseInt(key) +) as RouteToFacility[]; + +type Props = FormFieldBaseProps; + +export default function RouteToFacilitySelect(props: Props) { + const field = useFormFieldPropsResolver(props as any); + + return ( + ROUTE_TO_FACILITY_OPTIONS[key]} + /> + ); +} diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index 6a5a5da242c..991dbd69539 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -434,14 +434,14 @@ export const ConsultationDetails = (props: any) => { diagnoses={consultationData.diagnoses || []} /> - {(consultationData.verified_by_object || + {(consultationData.treating_physician_object || consultationData.deprecated_verified_by) && (
Treating Physician:{" "} - {consultationData.verified_by_object - ? `${consultationData.verified_by_object.first_name} ${consultationData.verified_by_object.last_name}` + {consultationData.treating_physician_object + ? `${consultationData.treating_physician_object.first_name} ${consultationData.treating_physician_object.last_name}` : consultationData.deprecated_verified_by}
diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 10397f4e79a..a56a0d587e9 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -2,7 +2,6 @@ import * as Notification from "../../Utils/Notifications.js"; import { BedModel, FacilityModel } from "./models"; import { - CONSULTATION_STATUS, CONSULTATION_SUGGESTION, PATIENT_CATEGORIES, REVIEW_AT_CHOICES, @@ -59,6 +58,11 @@ import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import useVisibility from "../../Utils/useVisibility"; import dayjs from "../../Utils/dayjs"; +import RouteToFacilitySelect, { + RouteToFacility, +} from "../Common/RouteToFacilitySelect.js"; +import { LocationSelect } from "../Common/LocationSelect.js"; +import { classNames } from "../../Utils/utils.js"; import { ConditionVerificationStatuses, ConsultationDiagnosis, @@ -79,20 +83,25 @@ type FormDetails = { other_symptoms: string; symptoms_onset_date?: Date; suggestion: string; - consultation_status: number; + route_to_facility?: RouteToFacility; patient: string; facility: string; admitted: BooleanStrings; admitted_to: string; category: string; admission_date?: Date; + icu_admission_date?: Date; discharge_date: null; referred_to?: string; referred_to_external?: string; + referred_from_facility?: string; + referred_from_facility_external?: string; + referred_by_external?: string; + transferred_from_location?: string; + treating_physician: string; + treating_physician_object: UserModel | null; create_diagnoses: CreateDiagnosis[]; diagnoses: ConsultationDiagnosis[]; - verified_by: string; - verified_by_object: UserModel | null; is_kasp: BooleanStrings; kasp_enabled_date: null; examination_details: string; @@ -124,20 +133,25 @@ const initForm: FormDetails = { other_symptoms: "", symptoms_onset_date: undefined, suggestion: "A", - consultation_status: 0, + route_to_facility: undefined, patient: "", facility: "", admitted: "false", admitted_to: "", category: "", admission_date: new Date(), + icu_admission_date: undefined, discharge_date: null, referred_to: "", referred_to_external: "", + referred_from_facility: "", + referred_from_facility_external: "", + referred_by_external: "", + transferred_from_location: "", + treating_physician: "", + treating_physician_object: null, create_diagnoses: [], diagnoses: [], - verified_by: "", - verified_by_object: null, is_kasp: "false", kasp_enabled_date: null, examination_details: "", @@ -224,7 +238,9 @@ export const ConsultationForm = (props: any) => { initialState ); const [bed, setBed] = useState(null); - const [selectedFacility, setSelectedFacility] = + const [referredToFacility, setReferredToFacility] = + useState(null); + const [referredFromFacility, setReferredFromFacility] = useState(null); const [isLoading, setIsLoading] = useState(false); const [patientName, setPatientName] = useState(""); @@ -307,26 +323,13 @@ export const ConsultationForm = (props: any) => { const isOtherSymptomsSelected = state.form.symptoms.includes(9); const handleFormFieldChange: FieldChangeEventHandler = (event) => { - if (event.name === "consultation_status" && event.value === "1") { - dispatch({ - type: "set_form", - form: { - ...state.form, - consultation_status: 1, - symptoms: [1], - symptoms_onset_date: new Date(), - category: "Critical", - suggestion: "DD", - }, - }); - } else if (event.name === "suggestion" && event.value === "DD") { + if (event.name === "suggestion" && event.value === "DD") { dispatch({ type: "set_form", form: { ...state.form, suggestion: "DD", consultation_notes: "Patient declared dead", - verified_by: "Declared Dead", }, }); } else { @@ -353,8 +356,19 @@ export const ConsultationForm = (props: any) => { }); if (res.data.suggestion === "R") { if (res.data.referred_to_external) - setSelectedFacility({ id: -1, name: res.data.referred_to_external }); - else setSelectedFacility(res.data.referred_to_object); + setReferredToFacility({ + id: -1, + name: res.data.referred_to_external, + }); + else setReferredToFacility(res.data.referred_to_object); + } + if (res.data.route_to_facility === 20) { + if (res.data.referred_from_facility_external) + setReferredFromFacility({ + id: -1, + name: res.data.referred_from_facility_external, + }); + else setReferredFromFacility(res.data.referred_from_facility_object); } if (!status.aborted) { if (res?.data) { @@ -362,6 +376,7 @@ export const ConsultationForm = (props: any) => { ...res.data, symptoms_onset_date: isoStringToDate(res.data.symptoms_onset_date), admission_date: isoStringToDate(res.data.admission_date), + icu_admission_date: isoStringToDate(res.data.icu_admission_date), admitted: res.data.admitted ? String(res.data.admitted) : "false", admitted_to: res.data.admitted_to ? res.data.admitted_to : "", category: res.data.category @@ -374,8 +389,8 @@ export const ConsultationForm = (props: any) => { is_kasp: `${res.data.is_kasp}`, assigned_to: res.data.assigned_to || "", assigned_to_object: res.data.assigned_to_object, - verified_by: res.data.verified_by || "", - verified_by_object: res.data.verified_by_object, + treating_physician: res.data.treating_physician || "", + treating_physician_object: res.data.treating_physician_object, ett_tt: res.data.ett_tt ? Number(res.data.ett_tt) : 3, special_instruction: res.data.special_instruction || "", weight: res.data.weight ? res.data.weight : "", @@ -440,9 +455,9 @@ export const ConsultationForm = (props: any) => { invalidForm = true; } return; - case "consultation_status": + case "route_to_facility": if (!state.form[field]) { - errors[field] = "Please select the consultation status"; + errors[field] = "Field is required"; invalidForm = true; } return; @@ -506,15 +521,30 @@ export const ConsultationForm = (props: any) => { invalidForm = true; } return; + case "referred_from_facility": + if ( + state.form.route_to_facility === 20 && + !state.form[field] && + !state.form["referred_from_facility_external"] + ) { + errors[field] = "Please select the referred from facility"; + invalidForm = true; + } + return; + case "transferred_from_location": + if (state.form.route_to_facility === 30 && !state.form[field]) { + errors[field] = + "Name of Ward/ICU the patient is being transferred from is required"; + invalidForm = true; + } + return; case "consultation_notes": - if (state.form.consultation_status != 1) { - if (!state.form[field]) { - errors[field] = "Required *"; - invalidForm = true; - } else if (!state.form[field].replace(/\s/g, "").length) { - errors[field] = "Consultation notes can not be empty"; - invalidForm = true; - } + if (!state.form[field]) { + errors[field] = "Field is required"; + invalidForm = true; + } else if (!state.form[field].replace(/\s/g, "").length) { + errors[field] = "Consultation notes can not be empty"; + invalidForm = true; } return; case "is_telemedicine": @@ -577,7 +607,7 @@ export const ConsultationForm = (props: any) => { return; } - case "verified_by": { + case "treating_physician": { if (state.form.suggestion !== "DD" && !state.form[field]) { errors[field] = "Please fill treating physician"; invalidForm = true; @@ -586,58 +616,6 @@ export const ConsultationForm = (props: any) => { return; } - // case "icd11_provisional_diagnoses_object": { - // if ( - // state.form[field].length === 0 && - // state.form["icd11_diagnoses_object"].length === 0 - // ) { - // for (const err_field of [field, "icd11_diagnoses_object"]) - // errors[err_field] = - // "Please select either Provisional Diagnosis or Final Diagnosis"; - // invalidForm = true; - // break; - // } - // return; - // } - - // case "icd11_principal_diagnosis": { - // if (!state.form[field]) { - // errors[field] = "Please select Principal Diagnosis"; - // invalidForm = true; - // break; - // } - - // if ( - // state.form[field] && - // state.form["icd11_diagnoses_object"].length && - // !state.form["icd11_provisional_diagnoses_object"] && - // !state.form["icd11_diagnoses_object"] - // .map((d) => d.id) - // .includes(state.form[field]!) - // ) { - // errors[field] = - // "Please select Principal Diagnosis from Final Diagnosis"; - // invalidForm = true; - // break; - // } - - // if ( - // state.form[field] && - // state.form["icd11_provisional_diagnoses_object"].length && - // !state.form["icd11_diagnoses_object"] && - // !state.form["icd11_provisional_diagnoses_object"] - // .map((d) => d.id) - // .includes(state.form[field]!) - // ) { - // errors[field] = - // "Please select Principal Diagnosis from Provisional Diagnosis"; - // invalidForm = true; - // break; - // } - - // return; - // } - default: return; } @@ -699,7 +677,7 @@ export const ConsultationForm = (props: any) => { ? state.form.symptoms_onset_date : undefined, suggestion: state.form.suggestion, - consultation_status: Number(state.form.consultation_status), + route_to_facility: state.form.route_to_facility, admitted: state.form.suggestion === "A", admission_date: ["A", "DC"].includes(state.form.suggestion) ? state.form.admission_date @@ -713,7 +691,7 @@ export const ConsultationForm = (props: any) => { discharge_date: state.form.discharge_date, patient_no: state.form.patient_no, create_diagnoses: isUpdate ? undefined : state.form.create_diagnoses, - verified_by: state.form.verified_by, + treating_physician: state.form.treating_physician, investigation: state.form.InvestigationAdvice, procedure: state.form.procedures, patient: patientId, @@ -726,6 +704,24 @@ export const ConsultationForm = (props: any) => { state.form.suggestion === "R" && !state.form.referred_to ? state.form.referred_to_external : undefined, + referred_from_facility: + state.form.route_to_facility === 20 && + !state.form.referred_from_facility_external + ? state.form.referred_from_facility + : undefined, + referred_from_facility_external: + state.form.route_to_facility === 20 && + !state.form.referred_from_facility + ? state.form.referred_from_facility_external + : undefined, + referred_by_external: + state.form.route_to_facility === 20 + ? state.form.referred_by_external + : undefined, + transferred_from_location: + state.form.route_to_facility === 30 + ? state.form.transferred_from_location + : undefined, consultation_notes: state.form.consultation_notes, is_telemedicine: state.form.is_telemedicine, action: state.form.action, @@ -824,9 +820,11 @@ export const ConsultationForm = (props: any) => { ); }; - const setFacility = (selected: FacilityModel | FacilityModel[] | null) => { + const handleReferredToFacilityChange = ( + selected: FacilityModel | FacilityModel[] | null + ) => { const selectedFacility = selected as FacilityModel; - setSelectedFacility(selectedFacility); + setReferredToFacility(selectedFacility); const form: FormDetails = { ...state.form }; if (selectedFacility?.id) { if (selectedFacility.id === -1) { @@ -840,6 +838,24 @@ export const ConsultationForm = (props: any) => { dispatch({ type: "set_form", form }); }; + const handleReferredFromFacilityChange = ( + selected: FacilityModel | FacilityModel[] | null + ) => { + const selectedFacility = selected as FacilityModel; + setReferredFromFacility(selectedFacility); + const form: FormDetails = { ...state.form }; + if (selectedFacility?.id) { + if (selectedFacility.id === -1) { + form.referred_from_facility_external = selectedFacility.name ?? ""; + delete form.referred_from_facility; + } else { + form.referred_from_facility = selectedFacility.id.toString() || ""; + delete form.referred_from_facility_external; + } + } + dispatch({ type: "set_form", form }); + }; + const field = (name: string) => { return { id: name, @@ -879,9 +895,6 @@ export const ConsultationForm = (props: any) => {
{Object.keys(sections).map((sectionTitle) => { - if (state.form.consultation_status === 1) { - return null; - } if (!isUpdate && sectionTitle === "Bed Status") { return null; } @@ -923,66 +936,119 @@ export const ConsultationForm = (props: any) => { {sectionTitle("Consultation Details")}
-
- {String(state.form.consultation_status) !== "1" && ( + {state.form.route_to_facility === 20 && ( <> -
- + + Name of the referring Facility + +
- {isOtherSymptomsSelected && ( -
- -
- )} - - {hasSymptoms && ( -
- -
- )}
-
)} + {state.form.route_to_facility === 30 && ( +
+ + Name of Ward/ICU the patient is shifted from + + + field("transferred_from_location").onChange({ + name: "transferred_from_location", + value: location, + }) + } + selected={field("transferred_from_location").value} + showAll={false} + multiple={false} + facilityId={facilityId} + errors={state.errors.transferred_from_location ?? ""} + /> +
+ )} + +
+ +
+ {isOtherSymptomsSelected && ( +
+ +
+ )} + + {hasSymptoms && ( +
+ +
+ )} +
+ +
+
{
- {String(state.form.consultation_status) !== "1" && ( -
- - A daily round already exists. -

- ) - } - required - label="Category" - {...field("category")} - /> -
- )} +
+ + A daily round already exists. +

+ ) + } + required + label="Category" + {...field("category")} + /> +
-
+
!deprecated )} @@ -1079,8 +1139,8 @@ export const ConsultationForm = (props: any) => { @@ -1131,40 +1191,71 @@ export const ConsultationForm = (props: any) => { )} {["A", "DC"].includes(state.form.suggestion) && ( - <> +
+ +
+ )} + + {state.form.route_to_facility && + [20, 30].includes(state.form.route_to_facility) && (
-
+ )} - {!isUpdate && ( -
- Bed - -
- )} - + {["A", "DC"].includes(state.form.suggestion) && !isUpdate && ( +
+ Bed + +
)} +
{
- {String(state.form.consultation_status) !== "1" && ( + {sectionTitle("Treatment Plan")} + {state.form.suggestion !== "DD" && ( <> - {sectionTitle("Treatment Plan")} - {state.form.suggestion !== "DD" && ( - <> -
- Investigations Suggestions - { - handleFormFieldChange({ - name: "InvestigationAdvice", - value: investigations, - }); - }} - /> - -
-
- Procedures - { - handleFormFieldChange({ - name: "procedures", - value: procedures, - }); - }} - /> - -
-
- -
-
- -
- - {kasp_enabled && ( - - )} -
- -
-
- -
- -
-
- -
-
- option.desc} - optionDescription={() => ""} - /> -
-
- - + Investigations Suggestions + { + handleFormFieldChange({ + name: "InvestigationAdvice", + value: investigations, + }); + }} + /> + +
+
+ Procedures + { + handleFormFieldChange({ + name: "procedures", + value: procedures, + }); + }} + /> + +
+
+ +
+
+ +
+ + {kasp_enabled && ( + + )} +
+ +
+
+ +
+ +
+
+ +
+
+ option.desc} + optionDescription={() => ""} + /> +
+
- {JSON.parse(state.form.is_telemedicine) && ( -
- -
- )} - + + + {JSON.parse(state.form.is_telemedicine) && ( +
+ +
)} )} diff --git a/src/Components/Facility/TreatmentSummary.tsx b/src/Components/Facility/TreatmentSummary.tsx index 674c161428d..3ff5d47d5e0 100644 --- a/src/Components/Facility/TreatmentSummary.tsx +++ b/src/Components/Facility/TreatmentSummary.tsx @@ -139,7 +139,7 @@ const TreatmentSummary = (props: any) => { Date of admission : {consultationData.admitted - ? formatDate(consultationData.admission_date) + ? formatDateTime(consultationData.admission_date) : " --/--/----"}
diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index bd0f4eafeda..e13947def18 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -3,6 +3,7 @@ import { ProcedureType } from "../Common/prescription-builder/ProcedureBuilder"; import { NormalPrescription, PRNPrescription } from "../Medicine/models"; import { AssetData } from "../Assets/AssetTypes"; import { UserBareMinimum } from "../Users/models"; +import { RouteToFacility } from "../Common/RouteToFacilitySelect"; import { ConsultationDiagnosis, CreateDiagnosis } from "../Diagnosis/types"; export interface LocalBodyModel { @@ -87,6 +88,7 @@ export type PatientCategory = export interface ConsultationModel { admission_date?: string; + icu_admission_date?: string; admitted?: boolean; test_id?: string; admitted_to?: string; @@ -106,19 +108,25 @@ export interface ConsultationModel { other_symptoms?: string; patient?: string; treatment_plan?: string; - referred_to?: number | null; + referred_to?: FacilityModel["id"]; referred_to_object?: FacilityModel; referred_to_external?: string; + referred_from_facility?: FacilityModel["id"]; + referred_from_facility_object?: FacilityModel; + referred_from_facility_external?: string; + referred_by_external?: string; + transferred_from_location?: LocationModel["id"]; + transferred_from_location_object?: LocationModel; suggestion?: string; patient_no?: string; - consultation_status?: number; + route_to_facility?: RouteToFacility; is_kasp?: boolean; kasp_enabled_date?: string; readonly diagnoses?: ConsultationDiagnosis[]; create_diagnoses?: CreateDiagnosis[]; // Used for bulk creating diagnoses upon consultation creation deprecated_verified_by?: string; - verified_by?: string; - verified_by_object?: UserBareMinimum; + treating_physician?: UserBareMinimum["id"]; + treating_physician_object?: UserBareMinimum; suggestion_text?: string; symptoms?: Array; symptoms_text?: string; diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index bc86b7f4c97..3b6cee7494a 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -291,7 +291,7 @@ export default function PatientInfoCard(props: { )?.text }{" "} on{" "} - {formatDate( + {formatDateTime( ["A", "DC"].includes(consultation?.suggestion ?? "") ? consultation?.admission_date : consultation?.created_date diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index 61c0b939695..37490ba5fe4 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -78,8 +78,20 @@ const DATE_TIME_FORMAT = `${TIME_FORMAT}; ${DATE_FORMAT}`; type DateLike = Parameters[0]; -export const formatDateTime = (date: DateLike, format = DATE_TIME_FORMAT) => - dayjs(date).format(format); +export const formatDateTime = (date: DateLike, format?: string) => { + const obj = dayjs(date); + + if (format) { + return obj.format(format); + } + + // If time is 00:00:00 of local timezone, format as date only + if (obj.isSame(obj.startOf("day"))) { + return obj.format(DATE_FORMAT); + } + + return obj.format(DATE_TIME_FORMAT); +}; export const formatDate = (date: DateLike, format = DATE_FORMAT) => formatDateTime(date, format);