From bb472f4e456daf1ad44fd98ddf9909a0ae98b7ae Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Sun, 23 Apr 2023 14:19:37 +0530 Subject: [PATCH 01/38] UI changes to shifting form (#5323) * UI changes to shifting form * Refactor code and bug fixes * More bug fixes * Add additional fields * made shifting_approving_facility required in wartime_shifting * hide shifting_approving_facility in peacetime shifting --------- Co-authored-by: khavinshankar --- .../Patient/PatientCategorySelect.tsx | 4 +- src/Components/Patient/ShiftCreate.tsx | 382 +++++++++++------- src/Components/Resource/ResourceDetails.tsx | 2 +- src/Components/Shifting/BadgesList.tsx | 7 +- src/Components/Shifting/ListFilter.tsx | 38 +- src/Components/Shifting/ListView.tsx | 56 +-- src/Components/Shifting/ShiftDetails.tsx | 154 ++++--- .../Shifting/ShiftDetailsUpdate.tsx | 291 ++++++++----- src/Components/Shifting/ShiftingBoard.tsx | 48 ++- src/Locale/en/Shifting.json | 6 +- 10 files changed, 624 insertions(+), 364 deletions(-) diff --git a/src/Components/Patient/PatientCategorySelect.tsx b/src/Components/Patient/PatientCategorySelect.tsx index 5a5ea4fece5..24add33cf95 100644 --- a/src/Components/Patient/PatientCategorySelect.tsx +++ b/src/Components/Patient/PatientCategorySelect.tsx @@ -3,7 +3,7 @@ import { SelectFormField } from "../Form/FormFields/SelectFormField"; import { FormFieldBaseProps } from "../Form/FormFields/Utils"; /** - * A `FormField` component to select patient category and is always a mandatory + * A `FormField` component to select patient category and is by default a mandatory * field. */ export default function PatientCategorySelect( @@ -12,7 +12,7 @@ export default function PatientCategorySelect( return ( option.id} optionLabel={(option) => option.text} diff --git a/src/Components/Patient/ShiftCreate.tsx b/src/Components/Patient/ShiftCreate.tsx index 97bc13ac91b..01ba23e4a55 100644 --- a/src/Components/Patient/ShiftCreate.tsx +++ b/src/Components/Patient/ShiftCreate.tsx @@ -1,37 +1,43 @@ -import { useReducer, useState, useEffect } from "react"; -import loadable from "@loadable/component"; -import { FacilitySelect } from "../Common/FacilitySelect"; -import { - LegacyErrorHelperText, - LegacySelectField, -} from "../Common/HelperInputFields"; import * as Notification from "../../Utils/Notifications.js"; -import { useDispatch } from "react-redux"; -import { navigate } from "raviger"; + import { + BREATHLESSNESS_LEVEL, FACILITY_TYPES, + PATIENT_CATEGORIES, SHIFTING_VEHICLE_CHOICES, - BREATHLESSNESS_LEVEL, } from "../../Common/constants"; -import { parsePhoneNumberFromString } from "libphonenumber-js"; import { + Box, Card, CardContent, + FormControlLabel, Radio, RadioGroup, - Box, - FormControlLabel, } from "@material-ui/core"; -import { phonePreg } from "../../Common/validation"; - -import { createShift, getPatient } from "../../Redux/actions"; import { Cancel, Submit } from "../Common/components/ButtonV2"; -import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField"; +import { + LegacyErrorHelperText, + LegacySelectField, +} from "../Common/HelperInputFields"; +import { createShift, getPatient } from "../../Redux/actions"; +import { useEffect, useReducer, useState } from "react"; + +import { FacilitySelect } from "../Common/FacilitySelect"; import { FieldChangeEvent } from "../Form/FormFields/Utils"; -import TextFormField from "../Form/FormFields/TextFormField"; import { FieldLabel } from "../Form/FormFields/FormField"; +import PatientCategorySelect from "./PatientCategorySelect"; +import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField"; import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; +import TextFormField from "../Form/FormFields/TextFormField"; +import loadable from "@loadable/component"; +import { navigate } from "raviger"; +import { parsePhoneNumberFromString } from "libphonenumber-js"; +import { phonePreg } from "../../Common/validation"; import useAppHistory from "../../Common/hooks/useAppHistory"; +import useConfig from "../../Common/hooks/useConfig"; +import { useDispatch } from "react-redux"; +import { useTranslation } from "react-i18next"; + const PageTitle = loadable(() => import("../Common/PageTitle")); const Loading = loadable(() => import("../Common/Loading")); @@ -40,57 +46,6 @@ interface patientShiftProps { patientId: number; } -const initForm: any = { - shifting_approving_facility: null, - assigned_facility: null, - emergency: "false", - is_up_shift: "true", - reason: "", - vehicle_preference: "", - comments: "", - refering_facility_contact_name: "", - refering_facility_contact_number: "", - assigned_facility_type: "", - preferred_vehicle_choice: "", - breathlessness_level: "", -}; - -const requiredFields: any = { - shifting_approving_facility: { - errorText: "Name of the referring facility", - }, - refering_facility_contact_name: { - errorText: "Name of contact of the referring facility", - }, - refering_facility_contact_number: { - errorText: "Phone number of contact of the referring facility", - invalidText: "Please enter valid phone number", - }, - reason: { - errorText: "Reason for shifting in mandatory", - invalidText: "Please enter reason for shifting", - }, - assigned_facility_type: { - errorText: "Please Select Facility Type", - }, - preferred_vehicle_choice: { - errorText: "Please Preferred Vehicle Type", - }, - breathlessness_level: { - errorText: "Severity of Breathlessness is required", - }, -}; - -const initError = Object.assign( - {}, - ...Object.keys(initForm).map((k) => ({ [k]: "" })) -); - -const initialState = { - form: { ...initForm }, - errors: { ...initError }, -}; - export const ShiftCreate = (props: patientShiftProps) => { const { goBack } = useAppHistory(); const { facilityId, patientId } = props; @@ -98,12 +53,86 @@ export const ShiftCreate = (props: patientShiftProps) => { const [isLoading, setIsLoading] = useState(false); const [facilityName, setFacilityName] = useState(""); const [patientName, setPatientName] = useState(""); + const [patientCategory, setPatientCategory] = useState(); + const { t } = useTranslation(); + const { wartime_shifting } = useConfig(); + + const initForm: any = { + shifting_approving_facility: null, + assigned_facility: null, + emergency: "false", + is_up_shift: "true", + reason: "", + vehicle_preference: "", + comments: "", + refering_facility_contact_name: "", + refering_facility_contact_number: "", + assigned_facility_type: null, + preferred_vehicle_choice: null, + breathlessness_level: null, + patient_category: "", + ambulance_driver_name: "", + ambulance_phone_number: "", + ambulance_number: "", + }; + + let requiredFields: any = { + refering_facility_contact_name: { + errorText: "Name of contact of the referring facility", + }, + refering_facility_contact_number: { + errorText: "Phone number of contact of the referring facility", + invalidText: "Please enter valid phone number", + }, + reason: { + errorText: "Reason for shifting in mandatory", + invalidText: "Please enter reason for shifting", + }, + ambulance_number: { + errorText: "Ambulance Number is required", + invalidText: "Please enter valid Ambulance Number", + }, + }; + + if (wartime_shifting) { + requiredFields = { + ...requiredFields, + shifting_approving_facility: { + errorText: "Name of the referring facility", + }, + assigned_facility_type: { + errorText: "Please Select Facility Type", + }, + preferred_vehicle_choice: { + errorText: "Please Preferred Vehicle Type", + }, + breathlessness_level: { + errorText: "Severity of Breathlessness is required", + }, + }; + } + + const initError = Object.assign( + {}, + ...Object.keys(initForm).map((k) => ({ [k]: "" })) + ); + + const initialState = { + form: { ...initForm }, + errors: { ...initError }, + }; useEffect(() => { async function fetchPatientName() { if (patientId) { const res = await dispatchAction(getPatient({ id: patientId })); if (res.data) { + const patient_category = + res.data.last_consultation?.last_daily_round?.patient_category ?? + res.data.last_consultation?.category; + setPatientCategory( + PATIENT_CATEGORIES.find((c) => c.text === patient_category)?.id + ); setPatientName(res.data.name); setFacilityName(res.data.facility_object.name); } @@ -209,7 +238,14 @@ export const ShiftCreate = (props: patientShiftProps) => { shifting_approving_facility: ( state.form.shifting_approving_facility || {} ).id, - assigned_facility: (state.form.assigned_facility || {}).id, + assigned_facility: + state.form?.assigned_facility?.id != -1 + ? state.form?.assigned_facility?.id + : null, + assigned_facility_external: + state.form?.assigned_facility?.id === -1 + ? state.form?.assigned_facility?.name + : null, patient: props.patientId, emergency: state.form.emergency === "true", is_up_shift: state.form.is_up_shift === "true", @@ -224,6 +260,12 @@ export const ShiftCreate = (props: patientShiftProps) => { state.form.refering_facility_contact_number )?.format("E.164"), breathlessness_level: state.form.breathlessness_level, + patient_category: patientCategory, + ambulance_driver_name: state.form.ambulance_driver_name, + ambulance_phone_number: parsePhoneNumberFromString( + state.form.ambulance_phone_number + )?.format("E.164"), + ambulance_number: state.form.ambulance_number, }; const res = await dispatchAction(createShift(data)); @@ -262,7 +304,7 @@ export const ShiftCreate = (props: patientShiftProps) => {
{ />
-
- - Name of shifting approving facility{" "} - * - - - handleValueChange(value, "shifting_approving_facility") - } - errors={state.errors.shifting_approving_facility} - /> -
- -
+ {wartime_shifting && ( +
+ + Name of shifting approving facility{" "} + * + + + handleValueChange(value, "shifting_approving_facility") + } + errors={state.errors.shifting_approving_facility} + /> +
+ )} + +
- What facility would you like to assign the patient to + {t("what_facility_assign_the_patient_to")} { setSelected={(value: any) => handleValueChange(value, "assigned_facility") } + freeText={true} errors={state.errors.assigned_facility} />
@@ -365,69 +410,73 @@ export const ShiftCreate = (props: patientShiftProps) => {
- {/*
- Vehicle preference - -
*/} -
- - Preferred Vehicle * - - -
-
- - Preferred Facility Type{" "} - * - - -
-
- - Severity of Breathlessness{" "} - * - - + { + setPatientCategory(value); + }} + label="Patient Category" />
+ {wartime_shifting && ( + <> +
+ + Preferred Vehicle * + + +
+
+ + Preferred Facility Type{" "} + * + + +
+
+ + Severity of Breathlessness{" "} + * + + +
+ + )} +
{ />
+
+ +
+ +
+ { + handleFormFieldChange(event); + }} + error={state.errors.ambulance_phone_number} + /> +
+ +
+ +
- Contact person at the facility:{" "} + Contact person at the current facility:{" "} {data.refering_facility_contact_name || "--"}
diff --git a/src/Components/Shifting/BadgesList.tsx b/src/Components/Shifting/BadgesList.tsx index bf378aa8e80..ff6144776f2 100644 --- a/src/Components/Shifting/BadgesList.tsx +++ b/src/Components/Shifting/BadgesList.tsx @@ -1,8 +1,9 @@ -import { useState, useEffect } from "react"; -import { getUserList, getAnyFacility } from "../../Redux/actions"; +import { getAnyFacility, getUserList } from "../../Redux/actions"; +import { useEffect, useState } from "react"; + +import { SHIFTING_FILTER_ORDER } from "../../Common/constants"; import { useDispatch } from "react-redux"; import { useTranslation } from "react-i18next"; -import { SHIFTING_FILTER_ORDER } from "../../Common/constants"; export default function BadgesList(props: any) { const { qParams, FilterBadges } = props; diff --git a/src/Components/Shifting/ListFilter.tsx b/src/Components/Shifting/ListFilter.tsx index f8dce323208..f5db87ead82 100644 --- a/src/Components/Shifting/ListFilter.tsx +++ b/src/Components/Shifting/ListFilter.tsx @@ -302,25 +302,27 @@ export default function ListFilter(props: any) {
-
- {t("shifting_approving_facility")} -
- {isShiftingLoading ? ( - - ) : ( - - setFacility(obj, "shifting_approving_facility") - } - className="shifting-page-filter-dropdown" - errors={""} - /> - )} + {wartime_shifting && ( +
+ {t("shifting_approving_facility")} +
+ {isShiftingLoading ? ( + + ) : ( + + setFacility(obj, "shifting_approving_facility") + } + className="shifting-page-filter-dropdown" + errors={""} + /> + )} +
-
+ )}
{t("assigned_facility")} diff --git a/src/Components/Shifting/ListView.tsx b/src/Components/Shifting/ListView.tsx index fefff000758..82124ba5662 100644 --- a/src/Components/Shifting/ListView.tsx +++ b/src/Components/Shifting/ListView.tsx @@ -1,29 +1,32 @@ -import { useState, useEffect } from "react"; -import loadable from "@loadable/component"; -import { navigate } from "raviger"; -import { useDispatch } from "react-redux"; -import moment from "moment"; import { - listShiftRequests, completeTransfer, downloadShiftRequests, + listShiftRequests, } from "../../Redux/actions"; -import ListFilter from "./ListFilter"; -import { formatFilter } from "./Commons"; -import { formatDate } from "../../Utils/utils"; -import SearchInput from "../Form/SearchInput"; -import useFilters from "../../Common/hooks/useFilters"; +import { useEffect, useState } from "react"; + import BadgesList from "./BadgesList"; -import { ExportButton } from "../Common/Export"; -import { useTranslation } from "react-i18next"; import ButtonV2 from "../Common/components/ButtonV2"; import ConfirmDialogV2 from "../Common/ConfirmDialogV2"; +import { ExportButton } from "../Common/Export"; +import ListFilter from "./ListFilter"; import Page from "../Common/components/Page"; +import SearchInput from "../Form/SearchInput"; +import { formatDate } from "../../Utils/utils"; +import { formatFilter } from "./Commons"; +import loadable from "@loadable/component"; +import moment from "moment"; +import { navigate } from "raviger"; +import useConfig from "../../Common/hooks/useConfig"; +import { useDispatch } from "react-redux"; +import useFilters from "../../Common/hooks/useFilters"; +import { useTranslation } from "react-i18next"; const Loading = loadable(() => import("../Common/Loading")); export default function ListView() { const dispatch: any = useDispatch(); + const { wartime_shifting } = useConfig(); const { qParams, updateQuery, @@ -165,17 +168,19 @@ export default function ListView() {
-
-
- -
- {(shift.shifting_approving_facility_object || {}).name} -
- -
+ {wartime_shifting && ( +
+
+ +
+ {(shift.shifting_approving_facility_object || {}).name} +
+ +
+ )}
- {(shift.assigned_facility_object || {}).name || + {shift.assigned_facility_external || + shift.assigned_facility_object?.name || t("yet_to_be_decided")}
diff --git a/src/Components/Shifting/ShiftDetails.tsx b/src/Components/Shifting/ShiftDetails.tsx index 4ea8abe7d59..5b9d0af62b2 100644 --- a/src/Components/Shifting/ShiftDetails.tsx +++ b/src/Components/Shifting/ShiftDetails.tsx @@ -1,26 +1,29 @@ -import React, { useState, useCallback } from "react"; -import loadable from "@loadable/component"; -import { useDispatch } from "react-redux"; -import { statusType, useAbortableEffect } from "../../Common/utils"; -import { getShiftDetails, deleteShiftRecord } from "../../Redux/actions"; -import { navigate, Link } from "raviger"; -import QRCode from "qrcode.react"; -import { GENDER_TYPES, TEST_TYPE_CHOICES } from "../../Common/constants"; import * as Notification from "../../Utils/Notifications.js"; -import { CopyToClipboard } from "react-copy-to-clipboard"; + +import { GENDER_TYPES, TEST_TYPE_CHOICES } from "../../Common/constants"; +import { Link, navigate } from "raviger"; +import React, { useCallback, useState } from "react"; +import { deleteShiftRecord, getShiftDetails } from "../../Redux/actions"; +import { statusType, useAbortableEffect } from "../../Common/utils"; + +import ButtonV2 from "../Common/components/ButtonV2"; import CommentSection from "./CommentsSection"; +import ConfirmDialogV2 from "../Common/ConfirmDialogV2"; +import { CopyToClipboard } from "react-copy-to-clipboard"; +import Page from "../Common/components/Page"; +import QRCode from "qrcode.react"; +import RecordMeta from "../../CAREUI/display/RecordMeta"; import { formatDate } from "../../Utils/utils"; +import loadable from "@loadable/component"; import useConfig from "../../Common/hooks/useConfig"; +import { useDispatch } from "react-redux"; import { useTranslation } from "react-i18next"; -import RecordMeta from "../../CAREUI/display/RecordMeta"; -import ButtonV2 from "../Common/components/ButtonV2"; -import ConfirmDialogV2 from "../Common/ConfirmDialogV2"; -import Page from "../Common/components/Page"; const Loading = loadable(() => import("../Common/Loading")); export default function ShiftDetails(props: { id: string }) { - const { static_header_logo, kasp_full_string } = useConfig(); + const { static_header_logo, kasp_full_string, wartime_shifting } = + useConfig(); const dispatch: any = useDispatch(); const initialData: any = {}; const [data, setData] = useState(initialData); @@ -89,7 +92,7 @@ export default function ShiftDetails(props: { id: string }) { }; const copyContent = (data: any) => { - const formattedText = + let formattedText = t("disease_status") + ": *" + data?.patient_object?.disease_status + @@ -114,13 +117,13 @@ export default function ShiftDetails(props: { id: string }) { ":" + data?.patient_object?.address + "\n" + - t("facility_preference") + - ":" + - data?.assigned_facility_type + - "\n" + t("reason") + ":" + data?.reason; + if (wartime_shifting) { + formattedText += + t("facility_preference") + ": " + data?.assigned_facility_type + "\n"; + } return formattedText; }; @@ -565,7 +568,9 @@ export default function ShiftDetails(props: { id: string }) { {t("referred_to")}:{" "} - {data.assigned_facility_object?.name || "--"} + {data.assigned_facility_external || + data.assigned_facility_object?.name || + "--"}
@@ -688,17 +693,21 @@ export default function ShiftDetails(props: { id: string }) { {data.orgin_facility_object?.name || "--"} -
- - {t("shifting_approving_facility")}:{" "} - - {data.shifting_approving_facility_object?.name || "--"} -
+ {wartime_shifting && ( +
+ + {t("shifting_approving_facility")}:{" "} + + {data.shifting_approving_facility_object?.name || "--"} +
+ )}
{t("assigned_facility")}:{" "} - {data.assigned_facility_object?.name || "--"} + {data.assigned_facility_external || + data.assigned_facility_object?.name || + "--"}
@@ -737,6 +746,15 @@ export default function ShiftDetails(props: { id: string }) { {data.is_up_shift ? t("yes") : t("no")}
+
+ + {t("patient_category")}:{" "} + + + {" "} + {data.patient_category} + +
{kasp_full_string}:{" "} @@ -746,32 +764,63 @@ export default function ShiftDetails(props: { id: string }) { {data.is_kasp ? t("yes") : t("no")}
-
+ {wartime_shifting && ( + <> +
+ + {t("vehicle_preference")}:{" "} + + {data.vehicle_preference || data.preferred_vehicle_choice} +
+
+ + {t("facility_preference")}:{" "} + + {data.assigned_facility_type || "--"} +
+
+ + {t("severity_of_breathlessness")}:{" "} + + {data.breathlessness_level || "--"} +
{" "} + + )} + +
- {t("vehicle_preference")}:{" "} + {t("reason")}:{" "} - {data.vehicle_preference || data.preferred_vehicle_choice} + {data.reason || "--"}
-
+
- {t("facility_preference")}:{" "} + {t("ambulance_driver_name")}:{" "} + + + {data.ambulance_driver_name || "--"} - {data.assigned_facility_type || "--"}
-
+
- {t("severity_of_breathlessness")}:{" "} + {t("ambulance_phone_number")}:{" "} + + + {data.ambulance_phone_number ? ( + + {data.ambulance_phone_number} + + ) : ( + "--" + )} - {data.breathlessness_level || "--"}
-
- {t("reason")}:{" "} + {t("ambulance_number")}:{" "} - {data.reason || "--"} + {data.ambulance_number || "--"}
-
{t("comments")}:{" "} @@ -869,17 +918,20 @@ export default function ShiftDetails(props: { id: string }) { {showFacilityCard(data.orgin_facility_object)}
-
-

{t("details_of_assigned_facility")}

- {showFacilityCard(data.assigned_facility_object)} -
- -
-

- {t("details_of_shifting_approving_facility")} -

- {showFacilityCard(data.shifting_approving_facility_object)} -
+ {!data.assigned_facility_external && ( +
+

{t("details_of_assigned_facility")}

+ {showFacilityCard(data.assigned_facility_object)} +
+ )} + {wartime_shifting && ( +
+

+ {t("details_of_shifting_approving_facility")} +

+ {showFacilityCard(data.shifting_approving_facility_object)} +
+ )}
diff --git a/src/Components/Shifting/ShiftDetailsUpdate.tsx b/src/Components/Shifting/ShiftDetailsUpdate.tsx index 8abcd842048..fc8393e4de6 100644 --- a/src/Components/Shifting/ShiftDetailsUpdate.tsx +++ b/src/Components/Shifting/ShiftDetailsUpdate.tsx @@ -3,6 +3,7 @@ import * as Notification from "../../Utils/Notifications.js"; import { BREATHLESSNESS_LEVEL, FACILITY_TYPES, + PATIENT_CATEGORIES, SHIFTING_CHOICES, SHIFTING_VEHICLE_CHOICES, } from "../../Common/constants"; @@ -27,9 +28,13 @@ import { FacilitySelect } from "../Common/FacilitySelect"; import { FieldLabel } from "../Form/FormFields/FormField"; import { LegacyErrorHelperText } from "../Common/HelperInputFields"; import { LegacySelectField } from "../Common/HelperInputFields"; +import PatientCategorySelect from "../Patient/PatientCategorySelect"; +import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField"; import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; +import TextFormField from "../Form/FormFields/TextFormField"; import { UserSelect } from "../Common/UserSelect"; import loadable from "@loadable/component"; +import { parsePhoneNumberFromString } from "libphonenumber-js"; import useAppHistory from "../../Common/hooks/useAppHistory"; import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; @@ -42,31 +47,6 @@ interface patientShiftProps { id: string; } -const initForm: any = { - shifting_approving_facility_object: null, - assigned_facility_object: null, - emergency: "false", - is_kasp: "false", - is_up_shift: "true", - reason: "", - vehicle_preference: "", - comments: "", - assigned_facility_type: "", - preferred_vehicle_choice: "", - assigned_to: "", - initial_status: "", -}; - -const initError = Object.assign( - {}, - ...Object.keys(initForm).map((k) => ({ [k]: "" })) -); - -const initialState = { - form: { ...initForm }, - errors: { ...initError }, -}; - export const ShiftDetailsUpdate = (props: patientShiftProps) => { const { goBack } = useAppHistory(); const { kasp_full_string, wartime_shifting } = useConfig(); @@ -81,25 +61,65 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { const [showDischargeModal, setShowDischargeModal] = useState(false); const { t } = useTranslation(); + const initForm: any = { + shifting_approving_facility_object: null, + assigned_facility_object: null, + emergency: "false", + is_kasp: "false", + is_up_shift: "true", + reason: "", + vehicle_preference: "", + comments: "", + assigned_facility_type: null, + preferred_vehicle_choice: null, + assigned_to: "", + initial_status: "", + patient_category: "", + ambulance_driver_name: "", + ambulance_phone_number: "", + ambulance_number: "", + }; + + const initError = Object.assign( + {}, + ...Object.keys(initForm).map((k) => ({ [k]: "" })) + ); + + const initialState = { + form: { ...initForm }, + errors: { ...initError }, + }; + const shiftStatusOptions = SHIFTING_CHOICES.map((obj) => obj.text).filter( (choice) => wartime_shifting || choice !== "PENDING" ); - const requiredFields: any = { - shifting_approving_facility_object: { - errorText: t("shifting_approving_facility_can_not_be_empty"), - }, - assigned_facility_type: { - errorText: t("please_select_facility_type"), - }, - preferred_vehicle_choice: { - errorText: t("please_select_preferred_vehicle_type"), - }, + let requiredFields: any = { reason: { errorText: t("please_enter_a_reason_for_the_shift"), }, + + ambulance_number: { + errorText: "Ambulance Number is required", + invalidText: "Please enter valid Ambulance Number", + }, }; + if (wartime_shifting) { + requiredFields = { + ...requiredFields, + shifting_approving_facility_object: { + errorText: t("shifting_approving_facility_can_not_be_empty"), + }, + assigned_facility_type: { + errorText: t("please_select_facility_type"), + }, + preferred_vehicle_choice: { + errorText: t("please_select_preferred_vehicle_type"), + }, + }; + } + const shiftFormReducer = (state = initialState, action: any) => { switch (action.type) { case "set_form": { @@ -173,6 +193,20 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { dispatch({ type: "set_form", form }); }; + const handleFormFieldChange = (event: FieldChangeEvent) => { + dispatch({ + type: "set_form", + form: { ...state.form, [event.name]: event.value }, + }); + }; + + const handleTextFormFieldChange = (e: any) => { + const form = { ...state.form }; + const { name, value } = e; + form[name] = value; + dispatch({ type: "set_form", form }); + }; + const setFacility = (selected: any, name: string) => { const form = { ...state.form }; form[name] = selected; @@ -189,7 +223,14 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { orgin_facility: state.form.orgin_facility_object?.id, shifting_approving_facility: state.form?.shifting_approving_facility_object?.id, - assigned_facility: state.form?.assigned_facility_object?.id, + assigned_facility: + state.form?.assigned_facility_object?.id != -1 + ? state.form?.assigned_facility_object?.id + : null, + assigned_facility_external: + state.form?.assigned_facility_object?.id === -1 + ? state.form?.assigned_facility_object?.name + : null, patient: state.form.patient_object?.id, emergency: [true, "true"].includes(state.form.emergency), is_kasp: [true, "true"].includes(state.form.is_kasp), @@ -201,6 +242,12 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { preferred_vehicle_choice: state.form.preferred_vehicle_choice, assigned_to: state.form.assigned_to, breathlessness_level: state.form.breathlessness_level, + patient_category: state.form.patient_category, + ambulance_driver_name: state.form.ambulance_driver_name, + ambulance_phone_number: parsePhoneNumberFromString( + state.form.ambulance_phone_number + )?.format("E.164"), + ambulance_number: state.form.ambulance_number, }; if (state.form.status !== state.form.initial_status) { @@ -235,8 +282,16 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { if (res && res.data) { const d = res.data; setConsultationData(d.patient.last_consultation); + if (d.assigned_facility_external) + d["assigned_facility_object"] = { + id: -1, + name: res.data.assigned_facility_external, + }; d["initial_status"] = res.data.status; d["status"] = qParams.status || res.data.status; + d["patient_category"] = PATIENT_CATEGORIES.find( + (c) => c.text === res.data.patient_category + )?.id; dispatch({ type: "set_form", form: d }); } setIsLoading(false); @@ -311,21 +366,23 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { )}
-
- - {t("name_of_shifting_approving_facility")} - - - setFacility(obj, "shifting_approving_facility_object") - } - errors={state.errors.shifting_approving_facility_object} - /> -
+ {wartime_shifting && ( +
+ + {t("name_of_shifting_approving_facility")} + + + setFacility(obj, "shifting_approving_facility_object") + } + errors={state.errors.shifting_approving_facility_object} + /> +
+ )}
@@ -333,6 +390,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { @@ -418,48 +476,63 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => {
-
- {t("preferred_vehicle")} - -
-
- {t("preferred_facility_type")}* - -
-
- {t("severity_of_breathlessness")}* - +
-
+ + {wartime_shifting && ( + <> +
+ {t("preferred_vehicle")} + +
+
+ {t("preferred_facility_type")}* + +
+
+ {t("severity_of_breathlessness")}* + +
{" "} + + )} +
{ />
-
+
+ +
+ +
+ { + handleFormFieldChange(event); + }} + error={state.errors.ambulance_phone_number} + /> +
+ +
+ +
+ +
{ const ShiftCard = ({ shift, filter }: any) => { const dispatch: any = useDispatch(); + const { wartime_shifting } = useConfig(); const [modalFor, setModalFor] = useState({ externalId: undefined, loading: false, @@ -109,17 +112,19 @@ const ShiftCard = ({ shift, filter }: any) => {
-
-
- -
- {(shift.shifting_approving_facility_object || {}).name} -
- -
+ {wartime_shifting && ( +
+
+ +
+ {(shift.shifting_approving_facility_object || {}).name} +
+ +
+ )}
{
- {(shift.assigned_facility_object || {}).name || + {shift.assigned_facility_external || + shift.assigned_facility_object?.name || t("yet_to_be_decided")}
diff --git a/src/Locale/en/Shifting.json b/src/Locale/en/Shifting.json index d33a8b3f9c0..ed983b0bf1c 100644 --- a/src/Locale/en/Shifting.json +++ b/src/Locale/en/Shifting.json @@ -40,8 +40,12 @@ "facility_preference": "Facility preference", "vehicle_preference": "Vehicle preference", "is_up_shift": "Is up shift", + "patient_category": "Patient Category", + "ambulance_driver_name": "Name of ambulance driver", + "ambulance_phone_number": "Phone number of Ambulance", + "ambulance_number": "Ambulance No.", "is_emergency": "Is emergency", - "contact_person_at_the_facility": "Contact person at the facility", + "contact_person_at_the_facility": "Contact person at the current facility", "update_status_details": "Update Status/Details", "shifting_details": "Shifting details", "auto_generated_for_care": "Auto Generated for Care", From 0d005d6f4669163f917bc049b7ec9793abd9d00a Mon Sep 17 00:00:00 2001 From: Gokulram A Date: Wed, 26 Apr 2023 09:30:54 +0530 Subject: [PATCH 02/38] Made ambulance no. not mandatory in shift request create (#5383) * made ambulance no. non-mandatory in shift request create * Made ambulance no optional in shifting update form --------- Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- src/Components/Patient/ShiftCreate.tsx | 5 ----- src/Components/Shifting/ShiftDetailsUpdate.tsx | 8 +------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/Components/Patient/ShiftCreate.tsx b/src/Components/Patient/ShiftCreate.tsx index 01ba23e4a55..a8589b2ec90 100644 --- a/src/Components/Patient/ShiftCreate.tsx +++ b/src/Components/Patient/ShiftCreate.tsx @@ -88,10 +88,6 @@ export const ShiftCreate = (props: patientShiftProps) => { errorText: "Reason for shifting in mandatory", invalidText: "Please enter reason for shifting", }, - ambulance_number: { - errorText: "Ambulance Number is required", - invalidText: "Please enter valid Ambulance Number", - }, }; if (wartime_shifting) { @@ -515,7 +511,6 @@ export const ShiftCreate = (props: patientShiftProps) => {
{ reason: { errorText: t("please_enter_a_reason_for_the_shift"), }, - - ambulance_number: { - errorText: "Ambulance Number is required", - invalidText: "Please enter valid Ambulance Number", - }, }; if (wartime_shifting) { @@ -193,7 +188,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { dispatch({ type: "set_form", form }); }; - const handleFormFieldChange = (event: FieldChangeEvent) => { + const handleFormFieldChange = (event: any) => { dispatch({ type: "set_form", form: { ...state.form, [event.name]: event.value }, @@ -570,7 +565,6 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => {
Date: Wed, 26 Apr 2023 09:31:36 +0530 Subject: [PATCH 03/38] Show all locations in CNS page by default and added a cancel button to setLoaction Modal (#5378) * Show all locations in CNS page by default and added a cancel button to setLoaction Modal * reduce one iteration * added key to MonitorCard Component * added location name to monitor card --- src/Components/Facility/FacilityCNS.tsx | 190 ++++++++++++++---------- src/Components/Facility/MonitorCard.tsx | 46 ++++++ 2 files changed, 161 insertions(+), 75 deletions(-) create mode 100644 src/Components/Facility/MonitorCard.tsx diff --git a/src/Components/Facility/FacilityCNS.tsx b/src/Components/Facility/FacilityCNS.tsx index e5480cdfe2f..7a1890436af 100644 --- a/src/Components/Facility/FacilityCNS.tsx +++ b/src/Components/Facility/FacilityCNS.tsx @@ -1,8 +1,7 @@ -import { Link, navigate } from "raviger"; +import { navigate } from "raviger"; import { useEffect, useState } from "react"; import { useDispatch } from "react-redux"; import CareIcon from "../../CAREUI/icons/CareIcon"; -import { GENDER_TYPES } from "../../Common/constants"; import { getAllPatient, getPermittedFacility, @@ -10,16 +9,16 @@ import { } from "../../Redux/actions"; import { classNames } from "../../Utils/utils"; import { AssetData, AssetLocationObject } from "../Assets/AssetTypes"; -import ButtonV2, { Submit } from "../Common/components/ButtonV2"; +import ButtonV2, { Cancel, Submit } from "../Common/components/ButtonV2"; import Page from "../Common/components/Page"; import Loading from "../Common/Loading"; import Pagination from "../Common/Pagination"; import { PatientModel } from "../Patient/models"; -import PatientVitalsCard from "../Patient/PatientVitalsCard"; import { FacilityModel } from "./models"; import AutocompleteFormField from "../Form/FormFields/Autocomplete"; import { uniqBy } from "lodash"; import DialogModal from "../Common/Dialog"; +import { MonitorCard } from "./MonitorCard"; interface Monitor { patient: PatientModel; @@ -36,6 +35,7 @@ export default function FacilityCNS({ facilityId }: { facilityId: string }) { const [monitors, setMonitors] = useState(); const [facility, setFacility] = useState(); const [currentPage, setCurrentPage] = useState(1); + const [defaultShowAllLocation, setDefaultShowAllLocation] = useState(true); const searchParams = new URLSearchParams(window.location.search); // this wil set ?page=1 param in url if it is not present @@ -45,7 +45,7 @@ export default function FacilityCNS({ facilityId }: { facilityId: string }) { } }, []); const [location, setLocation] = useState(); - const [showSelectLocation, setShowSelectLocation] = useState(true); + const [showSelectLocation, setShowSelectLocation] = useState(false); useEffect(() => { const onFullscreenChange = () => @@ -131,43 +131,63 @@ export default function FacilityCNS({ facilityId }: { facilityId: string }) { if (!monitors) return ; return ( - setShowSelectLocation(true)} - > - Change Location - - { - if (isFullscreen) { - document.exitFullscreen(); - } else { - document.documentElement.requestFullscreen(); - } - }} - className="tooltip !h-11" - > - - - {isFullscreen ? "Exit Fullscreen" : "Fullscreen"} - - + {monitors?.length > 0 ? ( + <> + setShowSelectLocation(true)} + > + + Change Location + + { + if (isFullscreen) { + document.exitFullscreen(); + } else { + document.documentElement.requestFullscreen(); + } + }} + className="tooltip !h-11" + > + + + {isFullscreen ? "Exit Fullscreen" : "Fullscreen"} + + + + ) : ( + <> + history.go(-2)} + > + Go Back + + + )} + m.asset.location_object.id === location?.id + ).length, + }} defaultPerPage={PER_PAGE_LIMIT} />
@@ -183,18 +209,11 @@ export default function FacilityCNS({ facilityId }: { facilityId: string }) { > setShowSelectLocation(false)} className="w-full max-w-md" > {!monitors && } - {monitors.length === 0 && ( -
-

- No vitals monitors present -

-
- )}
location} disabled={!monitors} /> -
+
+ { + setDefaultShowAllLocation(true); + setShowSelectLocation(false); + }} + > + Show All Locations + setShowSelectLocation(false)} + onClick={() => { + setDefaultShowAllLocation(false); + setShowSelectLocation(false); + }} + className="mr-2 my-2" label="Confirm" /> + setShowSelectLocation(false)} + className="mr-2 my-2" + />
@@ -236,33 +273,36 @@ export default function FacilityCNS({ facilityId }: { facilityId: string }) {
)}
- {monitors - ?.filter((m) => m.asset.location_object.id === location?.id) - ?.slice( - (currentPage - 1) * PER_PAGE_LIMIT, - currentPage * PER_PAGE_LIMIT - ) - .map(({ patient, socketUrl }) => ( -
-
- - {patient.name} - - - {patient.age}y |{" "} - {GENDER_TYPES.find((g) => g.id === patient.gender)?.icon} - - - - {patient.last_consultation?.current_bed?.bed_object?.name} - -
- -
- ))} + {defaultShowAllLocation + ? monitors + ?.slice( + (currentPage - 1) * PER_PAGE_LIMIT, + currentPage * PER_PAGE_LIMIT + ) + .map(({ patient, socketUrl, asset }) => ( + + )) + : monitors + ?.filter((m) => m.asset.location_object.id === location?.id) + ?.slice( + (currentPage - 1) * PER_PAGE_LIMIT, + currentPage * PER_PAGE_LIMIT + ) + .map(({ patient, socketUrl, asset }) => ( + + ))}
); diff --git a/src/Components/Facility/MonitorCard.tsx b/src/Components/Facility/MonitorCard.tsx new file mode 100644 index 00000000000..8f517881125 --- /dev/null +++ b/src/Components/Facility/MonitorCard.tsx @@ -0,0 +1,46 @@ +import { GENDER_TYPES } from "../../Common/constants"; +import { Link } from "raviger"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import { PatientModel } from "../Patient/models"; +import PatientVitalsCard from "../Patient/PatientVitalsCard"; +import { AssetLocationObject } from "../Assets/AssetTypes"; + +interface MonitorCardProps { + facilityId: string; + patient: PatientModel; + socketUrl: string; + location: AssetLocationObject; +} + +export const MonitorCard = ({ + facilityId, + patient, + socketUrl, + location, +}: MonitorCardProps) => { + return ( +
+
+ + {patient.name} + + + {patient.age}y |{" "} + {GENDER_TYPES.find((g) => g.id === patient.gender)?.icon} + + + + {patient.last_consultation?.current_bed?.bed_object?.name} + + + + {location.name} + +
+ +
+ ); +}; From 210dd935234ed30753e4cf778612e64cb5d94012 Mon Sep 17 00:00:00 2001 From: ARYAN PATEL Date: Wed, 26 Apr 2023 09:32:00 +0530 Subject: [PATCH 04/38] Fixed Bed capacity malfunctioning in the facility create page (#5377) --- src/Components/Facility/FacilityCreate.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Facility/FacilityCreate.tsx b/src/Components/Facility/FacilityCreate.tsx index 510f980d756..d6c8a4bc6d4 100644 --- a/src/Components/Facility/FacilityCreate.tsx +++ b/src/Components/Facility/FacilityCreate.tsx @@ -595,7 +595,7 @@ export const FacilityCreate = (props: FacilityProps) => { const res = capacityData.find((data) => { return data.room_type === x.id; }); - if (res && res.current_capacity && res.total_capacity) { + if (res) { const removeCurrentBedType = (bedTypeId: number | undefined) => { setCapacityData((state) => state.filter((i) => i.id !== bedTypeId) @@ -609,8 +609,8 @@ export const FacilityCreate = (props: FacilityProps) => { key={`bed_${res.id}`} room_type={res.room_type} label={x.text} - used={res.current_capacity} - total={res.total_capacity} + used={res.current_capacity || 0} + total={res.total_capacity || 0} lastUpdated={res.modified_date} removeBedType={removeCurrentBedType} handleUpdate={async () => { From bea295b6f5b150d4f942eb650c41affb0835b839 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Wed, 26 Apr 2023 13:00:43 +0530 Subject: [PATCH 05/38] Shift Request Update form: KASP only when wartime enabled (#5386) * fixes #5384 * Revert "fixes #5384" This reverts commit 5b2f4f5af985f3f285a4d207463b7220a1859833. * make kasp field enabled only in wartime * kasp indpependent of wartime config * Hide KASP reflection in Shifting Detail page --------- Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- src/Components/Shifting/ShiftDetails.tsx | 28 +++++---- .../Shifting/ShiftDetailsUpdate.tsx | 57 ++++++++++--------- 2 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/Components/Shifting/ShiftDetails.tsx b/src/Components/Shifting/ShiftDetails.tsx index 5b9d0af62b2..8521338d40b 100644 --- a/src/Components/Shifting/ShiftDetails.tsx +++ b/src/Components/Shifting/ShiftDetails.tsx @@ -22,8 +22,12 @@ import { useTranslation } from "react-i18next"; const Loading = loadable(() => import("../Common/Loading")); export default function ShiftDetails(props: { id: string }) { - const { static_header_logo, kasp_full_string, wartime_shifting } = - useConfig(); + const { + static_header_logo, + kasp_full_string, + wartime_shifting, + kasp_enabled, + } = useConfig(); const dispatch: any = useDispatch(); const initialData: any = {}; const [data, setData] = useState(initialData); @@ -755,15 +759,17 @@ export default function ShiftDetails(props: { id: string }) { {data.patient_category}
-
- - {kasp_full_string}:{" "} - - - {" "} - {data.is_kasp ? t("yes") : t("no")} - -
+ {kasp_enabled && ( +
+ + {kasp_full_string}:{" "} + + + {" "} + {data.is_kasp ? t("yes") : t("no")} + +
+ )} {wartime_shifting && ( <>
diff --git a/src/Components/Shifting/ShiftDetailsUpdate.tsx b/src/Components/Shifting/ShiftDetailsUpdate.tsx index 4f0f873dad6..a9a49d5d5c2 100644 --- a/src/Components/Shifting/ShiftDetailsUpdate.tsx +++ b/src/Components/Shifting/ShiftDetailsUpdate.tsx @@ -39,6 +39,7 @@ import useAppHistory from "../../Common/hooks/useAppHistory"; import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import { useTranslation } from "react-i18next"; +import { FieldChangeEvent } from "../Form/FormFields/Utils.js"; const Loading = loadable(() => import("../Common/Loading")); const PageTitle = loadable(() => import("../Common/PageTitle")); @@ -49,7 +50,7 @@ interface patientShiftProps { export const ShiftDetailsUpdate = (props: patientShiftProps) => { const { goBack } = useAppHistory(); - const { kasp_full_string, wartime_shifting } = useConfig(); + const { kasp_full_string, kasp_enabled, wartime_shifting } = useConfig(); const dispatchAction: any = useDispatch(); const [qParams, _] = useQueryParams(); const [isLoading, setIsLoading] = useState(true); @@ -420,32 +421,34 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => {
-
- - {t("is")} {kasp_full_string}? - - - - } - label={t("yes")} - /> - } - label={t("no")} - /> - - - -
+ {kasp_enabled && ( +
+ + {t("is")} {kasp_full_string}? + + + + } + label={t("yes")} + /> + } + label={t("no")} + /> + + + +
+ )}
{t("is_this_an_upshift")} From ba817376354b6d5f7107886dcc6a7a9d63b0e896 Mon Sep 17 00:00:00 2001 From: Abhiuday Gupta <77210185+cp-Coder@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:17:01 +0530 Subject: [PATCH 06/38] fix: clean up of shifting request (#5391) * fix(shifting): removed unnecessary fields from shifting details page * fix(shifting): removed more unnecessary fields --- src/Components/Shifting/ShiftDetails.tsx | 108 +++-------------------- src/Locale/en/Shifting.json | 6 +- 2 files changed, 12 insertions(+), 102 deletions(-) diff --git a/src/Components/Shifting/ShiftDetails.tsx b/src/Components/Shifting/ShiftDetails.tsx index 8521338d40b..b9757fb6e37 100644 --- a/src/Components/Shifting/ShiftDetails.tsx +++ b/src/Components/Shifting/ShiftDetails.tsx @@ -168,28 +168,12 @@ export default function ShiftDetails(props: { id: string }) { {patientData?.disease_status}
- -
- - {t("srf_id")}:{" "} - - {(patientData?.srf_id && patientData?.srf_id) || "-"} -
{t("test_type")}:{" "} {(patientData?.test_type && testType) || "-"}
-
- - {t("date_of_test")}:{" "} - - {(patientData?.date_of_test && - formatDate(patientData?.date_of_test)) || - "-"} -
-
{t("facility")}:{" "} @@ -281,71 +265,6 @@ export default function ShiftDetails(props: { id: string }) { {patientData?.address || "-"}
-
- - {t("contact_with_confirmed_carrier")}:{" "} - - {patientData?.contact_with_confirmed_carrier ? ( - {t("yes")} - ) : ( - - {t("no")} - - )} -
-
- - {t("contact_with_suspected_carrier")}:{" "} - - {patientData?.contact_with_suspected_carrier ? ( - {t("yes")} - ) : ( - - {t("no")} - - )} -
- {patientData?.estimated_contact_date && ( -
- - {t("estimated_contact_date")}:{" "} - - {formatDate(patientData?.estimated_contact_date)} -
- )} -
- - {t("has_sari_severe_acute_respiratory_illness")}{" "} - - {patientData?.has_SARI ? ( - {t("yes")} - ) : ( - - {t("no")} - - )} -
-
- - {t("travel_within_last_28_days")}{" "} - - {patientData?.past_travel ? ( - {t("yes")} - ) : ( - - {t("no")} - - )} -
- {patientData?.countries_travelled && - !!patientData?.countries_travelled.length && ( -
- - {t("countries_travelled")}:{" "} - - {patientData?.countries_travelled.join(", ")} -
- )} {patientData?.ongoing_medication && (
@@ -362,22 +281,6 @@ export default function ShiftDetails(props: { id: string }) { {patientData?.allergies}
)} - {!!patientData?.number_of_aged_dependents && ( -
- - {t("number_of_aged_dependents_above_60")}:{" "} - - {patientData?.number_of_aged_dependents} -
- )} - {!!patientData?.number_of_chronic_diseased_dependents && ( -
- - {t("number_of_chronic_diseased_dependents")}:{" "} - - {patientData?.number_of_chronic_diseased_dependents} -
- )}
); @@ -721,7 +624,7 @@ export default function ShiftDetails(props: { id: string }) {
- {t("contact_person_number")}:{" "} + {t("phone_number_at_current_facility")}:{" "} {data.refering_facility_contact_number ? ( @@ -772,6 +675,15 @@ export default function ShiftDetails(props: { id: string }) { )} {wartime_shifting && ( <> +
+ + {kasp_full_string}:{" "} + + + {" "} + {data.is_kasp ? t("yes") : t("no")} + +
{t("vehicle_preference")}:{" "} diff --git a/src/Locale/en/Shifting.json b/src/Locale/en/Shifting.json index ed983b0bf1c..2d31d1397a2 100644 --- a/src/Locale/en/Shifting.json +++ b/src/Locale/en/Shifting.json @@ -7,7 +7,7 @@ "disease_status": "Disease status", "breathlessness_level": "Breathlessness level", "assigned_facility": "Facility assigned", - "origin_facility": "Origin facility", + "origin_facility": "Current facility", "shifting_approval_facility": "Shifting approval facility", "shifting": "Shifting", "search_patient": "Search Patient", @@ -34,6 +34,7 @@ "details_of_origin_facility": "Details of origin facility", "details_of_patient": "Details of patient", "record_delete_confirm": "Are you sure you want to delete this record?", + "phone_number_at_current_facility": "Phone Number of Contact person at current Facility", "authorize_shift_delete": "Authorize shift delete", "delete_record": "Delete Record", "severity_of_breathlessness": "Severity of Breathlessness", @@ -56,9 +57,6 @@ "covid_19_cat_gov": "Covid_19 Clinical Category as per Govt. of Kerala guideline (A/B/C)", "district_program_management_supporting_unit": "District Program Management Supporting Unit", "name_of_hospital": "Name of Hospital", - "has_sari_severe_acute_respiratory_illness": "Has SARI (Severe Acute Respiratory illness)?", - "contact_with_suspected_carrier": "Contact with suspected carrier", - "contact_with_confirmed_carrier": "Contact with confirmed carrier", "passport_number": "Passport Number", "test_type": "Test Type", "medical_worker": "Medical Worker", From 3790a4891aa57e84bdff9233c78d637d6f89c798 Mon Sep 17 00:00:00 2001 From: ARYAN PATEL Date: Wed, 26 Apr 2023 19:34:46 +0530 Subject: [PATCH 07/38] made the assigned to field only available to wartime mode (#5411) * made the assigned to field only available to wartime mode * added classNames from utility --------- Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- .../Shifting/ShiftDetailsUpdate.tsx | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/Components/Shifting/ShiftDetailsUpdate.tsx b/src/Components/Shifting/ShiftDetailsUpdate.tsx index a9a49d5d5c2..7926c248f47 100644 --- a/src/Components/Shifting/ShiftDetailsUpdate.tsx +++ b/src/Components/Shifting/ShiftDetailsUpdate.tsx @@ -40,6 +40,7 @@ import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import { useTranslation } from "react-i18next"; import { FieldChangeEvent } from "../Form/FormFields/Utils.js"; +import { classNames } from "../../Utils/utils.js"; const Loading = loadable(() => import("../Common/Loading")); const PageTitle = loadable(() => import("../Common/PageTitle")); @@ -341,27 +342,33 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { value={state.form.status} options={shiftStatusOptions} onChange={handleChange} - className="bg-white h-14 w-full shadow-sm md:text-sm md:leading-5 mt-2" + className={classNames( + "bg-white", + wartime_shifting ? " h-14 " : " h-12 ", + "w-full shadow-sm md:text-sm md:leading-5 mt-2" + )} />
-
- {t("assigned_to")} -
- {assignedUserLoading ? ( - - ) : ( - - )} + {wartime_shifting && ( +
+ {t("assigned_to")} +
+ {assignedUserLoading ? ( + + ) : ( + + )} +
-
+ )} {wartime_shifting && (
@@ -388,6 +395,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { multiple={false} freeText={true} name="assigned_facility" + className={classNames(!wartime_shifting && " mt-6 ")} selected={state.form.assigned_facility_object} setSelected={(obj) => setFacility(obj, "assigned_facility_object") From c4de2b5960499b8f096b8dd6926bcc6a9e09d6ff Mon Sep 17 00:00:00 2001 From: Khavin Shankar Date: Wed, 26 Apr 2023 19:52:00 +0530 Subject: [PATCH 08/38] Mark patient as expired only after discharge in shifting (#5404) Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Co-authored-by: Gigin George --- .../Shifting/ShiftDetailsUpdate.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Components/Shifting/ShiftDetailsUpdate.tsx b/src/Components/Shifting/ShiftDetailsUpdate.tsx index 7926c248f47..17387e40d39 100644 --- a/src/Components/Shifting/ShiftDetailsUpdate.tsx +++ b/src/Components/Shifting/ShiftDetailsUpdate.tsx @@ -25,6 +25,7 @@ import { CircularProgress } from "@material-ui/core"; import { ConsultationModel } from "../Facility/models.js"; import DischargeModal from "../Facility/DischargeModal.js"; import { FacilitySelect } from "../Common/FacilitySelect"; +import { FieldChangeEvent } from "../Form/FormFields/Utils.js"; import { FieldLabel } from "../Form/FormFields/FormField"; import { LegacyErrorHelperText } from "../Common/HelperInputFields"; import { LegacySelectField } from "../Common/HelperInputFields"; @@ -210,10 +211,15 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { dispatch({ type: "set_form", form }); }; - const handleSubmit = async () => { + const handleSubmit = async (discharged = false) => { const validForm = validateForm(); if (validForm) { + if (!discharged && state.form.status === "PATIENT EXPIRED") { + setShowDischargeModal(true); + return; + } + setIsLoading(true); const data: any = { @@ -260,11 +266,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { msg: t("shift_request_updated_successfully"), }); - if (data.status === "PATIENT EXPIRED") { - setShowDischargeModal(true); - } else { - navigate(`/shifting/${props.id}`); - } + navigate(`/shifting/${props.id}`); } else { setIsLoading(false); } @@ -319,9 +321,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { consultationData={consultationData} discharge_reason="EXP" afterSubmit={() => { - navigate( - `/facility/${consultationData.facility}/patient/${consultationData.patient}/consultation/${consultationData.id}` - ); + handleSubmit(true); }} /> {
goBack()} /> - + handleSubmit()} />
From f013a27bed98b187c5f50f8326bc74c5fd1d34d9 Mon Sep 17 00:00:00 2001 From: Khavin Shankar Date: Wed, 26 Apr 2023 20:07:04 +0530 Subject: [PATCH 09/38] Kanban flow (#5406) Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Co-authored-by: Gigin George --- src/Common/constants.tsx | 15 +++++- src/Components/Common/components/ButtonV2.tsx | 27 +++++++++-- src/Components/Patient/ShiftCreate.tsx | 2 +- src/Components/Shifting/BoardView.tsx | 46 +++++++++++++------ src/Components/Shifting/ListFilter.tsx | 11 +++-- src/Components/Shifting/ShiftDetails.tsx | 24 +++++++++- .../Shifting/ShiftDetailsUpdate.tsx | 31 +++++++------ src/Components/Shifting/ShiftingBoard.tsx | 8 ++-- src/Locale/en/Common.json | 2 +- 9 files changed, 119 insertions(+), 47 deletions(-) diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index 42b43167ceb..ac0fa92bd12 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -17,6 +17,7 @@ export const LocalStorageKeys = { export interface OptionsType { id: number; text: string; + label?: string; desc?: string; disabled?: boolean; } @@ -135,7 +136,7 @@ export const FACILITY_TYPES: Array = [ // { id: 1600, text: "District War Room" }, ]; -export const SHIFTING_CHOICES: Array = [ +export const SHIFTING_CHOICES_WARTIME: Array = [ { id: 10, text: "PENDING" }, { id: 15, text: "ON HOLD" }, { id: 20, text: "APPROVED" }, @@ -147,6 +148,18 @@ export const SHIFTING_CHOICES: Array = [ { id: 70, text: "TRANSFER IN PROGRESS" }, { id: 80, text: "COMPLETED" }, { id: 90, text: "PATIENT EXPIRED" }, + { id: 100, text: "CANCELLED" }, +]; + +export const SHIFTING_CHOICES_PEACETIME: Array = [ + { id: 20, text: "APPROVED", label: "PATIENTS TO BE SHIFTED" }, + { id: 40, text: "DESTINATION APPROVED" }, + // { id: 50, text: "DESTINATION REJECTED" }, + { id: 60, text: "PATIENT TO BE PICKED UP", label: "TRANSPORTATION ARRANGED" }, + { id: 70, text: "TRANSFER IN PROGRESS" }, + { id: 80, text: "COMPLETED" }, + { id: 90, text: "PATIENT EXPIRED" }, + { id: 100, text: "CANCELLED" }, ]; export const SHIFTING_VEHICLE_CHOICES: Array = [ diff --git a/src/Components/Common/components/ButtonV2.tsx b/src/Components/Common/components/ButtonV2.tsx index a8aa548fe15..22722268ead 100644 --- a/src/Components/Common/components/ButtonV2.tsx +++ b/src/Components/Common/components/ButtonV2.tsx @@ -1,9 +1,9 @@ -import { Link } from "raviger"; -import { useTranslation } from "react-i18next"; -import CareIcon from "../../../CAREUI/icons/CareIcon"; import AuthorizedChild from "../../../CAREUI/misc/AuthorizedChild"; import { AuthorizedElementProps } from "../../../Utils/AuthorizeFor"; +import CareIcon from "../../../CAREUI/icons/CareIcon"; +import { Link } from "raviger"; import { classNames } from "../../../Utils/utils"; +import { useTranslation } from "react-i18next"; export type ButtonSize = "small" | "default" | "large"; export type ButtonShape = "square" | "circle"; @@ -75,6 +75,14 @@ export type ButtonProps = RawButtonProps & * Whether the button should be having a Id. */ id?: string | undefined; + /** + * Tooltip showed when hovered over. + */ + tooltip?: string; + /** + * Class for tooltip + */ + tooltipClassName?: string; }; const ButtonV2 = ({ @@ -91,6 +99,8 @@ const ButtonV2 = ({ children, href, target, + tooltip, + tooltipClassName, ...props }: ButtonProps) => { const className = classNames( @@ -132,7 +142,16 @@ const ButtonV2 = ({ } return ( - ); diff --git a/src/Components/Patient/ShiftCreate.tsx b/src/Components/Patient/ShiftCreate.tsx index a8589b2ec90..d9a99b3fc45 100644 --- a/src/Components/Patient/ShiftCreate.tsx +++ b/src/Components/Patient/ShiftCreate.tsx @@ -229,7 +229,7 @@ export const ShiftCreate = (props: patientShiftProps) => { setIsLoading(true); const data = { - status: "PENDING", + status: wartime_shifting ? "PENDING" : "APPROVED", orgin_facility: props.facilityId, shifting_approving_facility: ( state.form.shifting_approving_facility || {} diff --git a/src/Components/Shifting/BoardView.tsx b/src/Components/Shifting/BoardView.tsx index db2db299140..79c85fb7572 100644 --- a/src/Components/Shifting/BoardView.tsx +++ b/src/Components/Shifting/BoardView.tsx @@ -1,9 +1,11 @@ -import React, { useState } from "react"; +import { + SHIFTING_CHOICES_PEACETIME, + SHIFTING_CHOICES_WARTIME, +} from "../../Common/constants"; import BadgesList from "./BadgesList"; import { ExportButton } from "../Common/Export"; import ListFilter from "./ListFilter"; -import { SHIFTING_CHOICES } from "../../Common/constants"; import SearchInput from "../Form/SearchInput"; import ShiftingBoard from "./ShiftingBoard"; import { downloadShiftRequests } from "../../Redux/actions"; @@ -12,6 +14,7 @@ import loadable from "@loadable/component"; import { navigate } from "raviger"; import useConfig from "../../Common/hooks/useConfig"; import useFilters from "../../Common/hooks/useFilters"; +import { useState } from "react"; import { useTranslation } from "react-i18next"; import withScrolling from "react-dnd-scrolling"; @@ -25,16 +28,28 @@ export default function BoardView() { }); const { wartime_shifting } = useConfig(); - const shiftStatusOptions = SHIFTING_CHOICES.map((obj) => obj.text).filter( - (choice) => wartime_shifting || choice !== "PENDING" - ); + const shiftStatusOptions = wartime_shifting + ? SHIFTING_CHOICES_WARTIME + : SHIFTING_CHOICES_PEACETIME; + + const COMPLETED = wartime_shifting + ? [ + "COMPLETED", + "REJECTED", + "CANCELLED", + "DESTINATION REJECTED", + "PATIENT EXPIRED", + ] + : ["CANCELLED", "PATIENT EXPIRED"]; - const COMPLETED = ["COMPLETED", "REJECTED", "DESTINATION REJECTED"]; - const ACTIVE = shiftStatusOptions.filter( - (option) => !COMPLETED.includes(option) + const completedBoards = shiftStatusOptions.filter((option) => + COMPLETED.includes(option.text) + ); + const activeBoards = shiftStatusOptions.filter( + (option) => !COMPLETED.includes(option.text) ); - const [boardFilter, setBoardFilter] = useState(ACTIVE); + const [boardFilter, setBoardFilter] = useState(activeBoards); const [isLoading] = useState(false); const { t } = useTranslation(); @@ -68,22 +83,22 @@ export default function BoardView() { @@ -116,9 +131,10 @@ export default function BoardView() { ) : ( boardFilter.map((board) => ( )) diff --git a/src/Components/Shifting/ListFilter.tsx b/src/Components/Shifting/ListFilter.tsx index f5db87ead82..099926f78e4 100644 --- a/src/Components/Shifting/ListFilter.tsx +++ b/src/Components/Shifting/ListFilter.tsx @@ -5,6 +5,10 @@ import { } from "../../Common/constants"; import { DateRangePicker, getDate } from "../Common/DateRangePicker"; import React, { useEffect, useState } from "react"; +import { + SHIFTING_CHOICES_PEACETIME, + SHIFTING_CHOICES_WARTIME, +} from "../../Common/constants"; import { getAnyFacility, getUserList } from "../../Redux/actions"; import { CircularProgress } from "@material-ui/core"; @@ -14,7 +18,6 @@ import { FieldLabel } from "../Form/FormFields/FormField"; import FiltersSlideover from "../../CAREUI/interactive/FiltersSlideover"; import { LegacySelectField } from "../Common/HelperInputFields"; import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField"; -import { SHIFTING_CHOICES } from "../../Common/constants"; import { UserSelect } from "../Common/UserSelect2"; import moment from "moment"; import { navigate } from "raviger"; @@ -57,9 +60,9 @@ export default function ListFilter(props: any) { const [isAssignedUserLoading, setAssignedUserLoading] = useState(false); const { t } = useTranslation(); - const shiftStatusOptions = SHIFTING_CHOICES.map((obj) => obj.text).filter( - (choice) => wartime_shifting || choice !== "PENDING" - ); + const shiftStatusOptions = ( + wartime_shifting ? SHIFTING_CHOICES_WARTIME : SHIFTING_CHOICES_PEACETIME + ).map((option) => option.text); const [filterState, setFilterState] = useMergeState({ orgin_facility: filter.orgin_facility || "", diff --git a/src/Components/Shifting/ShiftDetails.tsx b/src/Components/Shifting/ShiftDetails.tsx index b9757fb6e37..2653f141592 100644 --- a/src/Components/Shifting/ShiftDetails.tsx +++ b/src/Components/Shifting/ShiftDetails.tsx @@ -1,6 +1,11 @@ import * as Notification from "../../Utils/Notifications.js"; -import { GENDER_TYPES, TEST_TYPE_CHOICES } from "../../Common/constants"; +import { + GENDER_TYPES, + SHIFTING_CHOICES_PEACETIME, + SHIFTING_CHOICES_WARTIME, + TEST_TYPE_CHOICES, +} from "../../Common/constants"; import { Link, navigate } from "raviger"; import React, { useCallback, useState } from "react"; import { deleteShiftRecord, getShiftDetails } from "../../Redux/actions"; @@ -38,6 +43,10 @@ export default function ShiftDetails(props: { id: string }) { React.useState(false); const { t } = useTranslation(); + const shiftStatusOptions = wartime_shifting + ? SHIFTING_CHOICES_WARTIME + : SHIFTING_CHOICES_PEACETIME; + const fetchData = useCallback( async (status: statusType) => { setIsLoading(true); @@ -552,6 +561,15 @@ export default function ShiftDetails(props: { id: string }) { options={
navigate(`/shifting/${data.external_id}/update`)} > {t("update_status_details")} @@ -591,7 +609,9 @@ export default function ShiftDetails(props: { id: string }) {
Status: - {data.status} + {shiftStatusOptions.find( + (option) => data.status === option.text + )?.label || data.status}
diff --git a/src/Components/Shifting/ShiftDetailsUpdate.tsx b/src/Components/Shifting/ShiftDetailsUpdate.tsx index 17387e40d39..af4f9cd012e 100644 --- a/src/Components/Shifting/ShiftDetailsUpdate.tsx +++ b/src/Components/Shifting/ShiftDetailsUpdate.tsx @@ -4,7 +4,8 @@ import { BREATHLESSNESS_LEVEL, FACILITY_TYPES, PATIENT_CATEGORIES, - SHIFTING_CHOICES, + SHIFTING_CHOICES_PEACETIME, + SHIFTING_CHOICES_WARTIME, SHIFTING_VEHICLE_CHOICES, } from "../../Common/constants"; import { @@ -31,17 +32,17 @@ import { LegacyErrorHelperText } from "../Common/HelperInputFields"; import { LegacySelectField } from "../Common/HelperInputFields"; import PatientCategorySelect from "../Patient/PatientCategorySelect"; import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField"; +import { SelectFormField } from "../Form/FormFields/SelectFormField.js"; import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; import TextFormField from "../Form/FormFields/TextFormField"; import { UserSelect } from "../Common/UserSelect"; +import { classNames } from "../../Utils/utils.js"; import loadable from "@loadable/component"; import { parsePhoneNumberFromString } from "libphonenumber-js"; import useAppHistory from "../../Common/hooks/useAppHistory"; import useConfig from "../../Common/hooks/useConfig"; import { useDispatch } from "react-redux"; import { useTranslation } from "react-i18next"; -import { FieldChangeEvent } from "../Form/FormFields/Utils.js"; -import { classNames } from "../../Utils/utils.js"; const Loading = loadable(() => import("../Common/Loading")); const PageTitle = loadable(() => import("../Common/PageTitle")); @@ -93,9 +94,9 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { errors: { ...initError }, }; - const shiftStatusOptions = SHIFTING_CHOICES.map((obj) => obj.text).filter( - (choice) => wartime_shifting || choice !== "PENDING" - ); + const shiftStatusOptions = wartime_shifting + ? SHIFTING_CHOICES_WARTIME + : SHIFTING_CHOICES_PEACETIME; let requiredFields: any = { reason: { @@ -177,6 +178,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { form[name] = value; dispatch({ type: "set_form", form }); }; + const handleTextAreaChange = (e: any) => { const form = { ...state.form }; const { name, value } = e; @@ -191,7 +193,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { dispatch({ type: "set_form", form }); }; - const handleFormFieldChange = (event: any) => { + const handleFormFieldChange = (event: FieldChangeEvent) => { dispatch({ type: "set_form", form: { ...state.form, [event.name]: event.value }, @@ -333,15 +335,16 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => {
- {t("status")} - option.label || option.text} + optionValue={(option) => option.text} + optionSelectedLabel={(option) => option.label || option.text} + onChange={handleFormFieldChange} className={classNames( "bg-white", wartime_shifting ? " h-14 " : " h-12 ", diff --git a/src/Components/Shifting/ShiftingBoard.tsx b/src/Components/Shifting/ShiftingBoard.tsx index 5d838f63f7b..6dc76fe0ea0 100644 --- a/src/Components/Shifting/ShiftingBoard.tsx +++ b/src/Components/Shifting/ShiftingBoard.tsx @@ -22,6 +22,7 @@ const limit = 14; interface boardProps { board: string; + title?: string; filterProp: any; formatFilter: any; } @@ -211,7 +212,6 @@ const ShiftCard = ({ shift, filter }: any) => {
setModalFor(shift.external_id)} > @@ -242,6 +242,7 @@ const ShiftCard = ({ shift, filter }: any) => { export default function ShiftingBoard({ board, + title, filterProp, formatFilter, }: boardProps) { @@ -343,9 +344,6 @@ export default function ShiftingBoard({ )); }; - const renderBoardTitle = (board: string) => - board === "APPROVED" ? t("awaiting_destination_approval") : board; - return (

- {renderBoardTitle(board)}{" "} + {title || board}{" "} {downloadLoading ? ( ) : ( diff --git a/src/Locale/en/Common.json b/src/Locale/en/Common.json index ffc0508f60d..f0d7e302b41 100644 --- a/src/Locale/en/Common.json +++ b/src/Locale/en/Common.json @@ -83,7 +83,7 @@ "filters": "Filters", "unknown": "Unknown", "active": "Active", - "completed": "Completed", + "completed": "Archived", "on": "On", "open": "Open", "features": "Features", From 33b25309bf66f3b96e4b20dedd2df114b44b51c7 Mon Sep 17 00:00:00 2001 From: Khavin Shankar Date: Wed, 26 Apr 2023 20:09:06 +0530 Subject: [PATCH 10/38] changed the discharged logic in patient consultation dashboard (#5379) --- .../Facility/ConsultationDetails.tsx | 7 +--- src/Components/Patient/PatientInfoCard.tsx | 38 +++++++++++-------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/Components/Facility/ConsultationDetails.tsx b/src/Components/Facility/ConsultationDetails.tsx index 3b6ce20d87c..75cd6611a2a 100644 --- a/src/Components/Facility/ConsultationDetails.tsx +++ b/src/Components/Facility/ConsultationDetails.tsx @@ -355,7 +355,7 @@ export const ConsultationDetails = (props: any) => { backUrl="/patients" />
- {patientData.is_active && ( + {!consultationData.discharge_date && (
@@ -493,10 +493,7 @@ export const ConsultationDetails = (props: any) => {
- {!patient.is_active && ( + {!!consultation?.discharge_date && (

Discharged from CARE

@@ -199,7 +201,7 @@ export default function PatientInfoCard(props: { ); })}
- {patient.is_active === false && ( + {!!consultation?.discharge_date && (
@@ -241,7 +243,7 @@ export default function PatientInfoCard(props: {
- {patient.is_active === false && ( + {!!consultation?.discharge_date && (
Discharge Reason @@ -264,13 +266,17 @@ export default function PatientInfoCard(props: { `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/update`, "Edit Consultation Details", "pen", - patient.is_active && consultation?.id, + patient.is_active && + consultation?.id && + !consultation?.discharge_date, ], [ `/facility/${patient.facility}/patient/${patient.id}/consultation/${consultation?.id}/daily-rounds`, "Log Update", "plus", - patient.is_active && consultation?.id, + patient.is_active && + consultation?.id && + !consultation?.discharge_date, [ !(consultation?.facility !== patient.facility) && !(consultation?.discharge_date || !patient.is_active) && From 1346a4f016d7440b00e1c9d9e22c8e7c9e3ed713 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Fri, 28 Apr 2023 10:47:33 +0530 Subject: [PATCH 11/38] tailwind shift update request form (#5415) * fixes #4999 * fix responsiveness issues --- src/Components/Facility/ConsultationForm.tsx | 2 +- .../Shifting/ShiftDetailsUpdate.tsx | 530 ++++++++---------- 2 files changed, 221 insertions(+), 311 deletions(-) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 9bc52331372..b295ff47412 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -876,7 +876,7 @@ export const ConsultationForm = (props: any) => { })}
-
+
import("../Common/Loading")); -const PageTitle = loadable(() => import("../Common/PageTitle")); interface patientShiftProps { id: string; @@ -94,10 +84,6 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { errors: { ...initError }, }; - const shiftStatusOptions = wartime_shifting - ? SHIFTING_CHOICES_WARTIME - : SHIFTING_CHOICES_PEACETIME; - let requiredFields: any = { reason: { errorText: t("please_enter_a_reason_for_the_shift"), @@ -172,20 +158,6 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { return !isInvalidForm; }; - const handleChange = (e: any) => { - const form = { ...state.form }; - const { name, value } = e.target; - form[name] = value; - dispatch({ type: "set_form", form }); - }; - - const handleTextAreaChange = (e: any) => { - const form = { ...state.form }; - const { name, value } = e; - form[name] = value; - dispatch({ type: "set_form", form }); - }; - const handleOnSelect = (user: any) => { const form = { ...state.form }; form["assigned_to"] = user?.id; @@ -316,7 +288,7 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { } return ( -
+ setShowDischargeModal(false)} @@ -326,287 +298,225 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { handleSubmit(true); }} /> - -
- - -
-
- option.label || option.text} - optionValue={(option) => option.text} - optionSelectedLabel={(option) => option.label || option.text} - onChange={handleFormFieldChange} - className={classNames( - "bg-white", - wartime_shifting ? " h-14 " : " h-12 ", - "w-full shadow-sm md:text-sm md:leading-5 mt-2" - )} - /> -
- {wartime_shifting && ( -
- {t("assigned_to")} -
- {assignedUserLoading ? ( - - ) : ( - - )} -
-
- )} - {wartime_shifting && ( -
- - {t("name_of_shifting_approving_facility")} - - - setFacility(obj, "shifting_approving_facility_object") - } - errors={state.errors.shifting_approving_facility_object} - /> -
- )} - -
- - {t("what_facility_assign_the_patient_to")} - - +
+ option.text} + optionValue={(option) => option.text} + optionSelectedLabel={(option) => option.text} + onChange={handleFormFieldChange} + className="bg-white w-full md:leading-5 mt-2 md:col-span-1" + /> + + {wartime_shifting && ( +
+ {t("assigned_to")} + {assignedUserLoading ? ( + + ) : ( + - setFacility(obj, "assigned_facility_object") + selected={assignedUser} + setSelected={handleOnSelect} + errors={""} + facilityId={ + state.form?.shifting_approving_facility_object?.id } - errors={state.errors.assigned_facility} - /> -
- -
- {t("is_this_an_emergency")} - - - } - label={t("yes")} - /> - } - label={t("no")} - /> - - - -
- - {kasp_enabled && ( -
- - {t("is")} {kasp_full_string}? - - - - } - label={t("yes")} - /> - } - label={t("no")} - /> - - - -
- )} - -
- {t("is_this_an_upshift")} - - - } - label={t("yes")} - /> - } - label={t("no")} - /> - - - -
- -
- -
- - {wartime_shifting && ( - <> -
- {t("preferred_vehicle")} - -
-
- {t("preferred_facility_type")}* - -
-
- {t("severity_of_breathlessness")}* - -
{" "} - )} -
- -
- -
- -
- -
- { - handleFormFieldChange(event); - }} - error={state.errors.ambulance_phone_number} - /> -
- -
- -
- -
- -
- -
- goBack()} /> - handleSubmit()} /> -
- - -
-
+ )} + + {wartime_shifting && ( +
+ + {t("name_of_shifting_approving_facility")} + + + setFacility(obj, "shifting_approving_facility_object") + } + errors={state.errors.shifting_approving_facility_object} + /> +
+ )} + +
+ {t("what_facility_assign_the_patient_to")} + + setFacility(obj, "assigned_facility_object") + } + errors={state.errors.assigned_facility} + /> +
+ + option.label} + optionValue={(option) => option.value} + /> + + {kasp_enabled && ( + option.value} + optionDisplay={(option) => option.label} + onChange={handleFormFieldChange} + /> + )} + + option.value} + optionDisplay={(option) => option.label} + onChange={handleFormFieldChange} + /> + + + + {wartime_shifting && ( + <> + option} + optionValue={(option) => option} + onChange={handleFormFieldChange} + className="bg-white h-11 w-full mt-2 shadow-sm md:leading-5" + error={state.errors.preferred_vehicle_choice} + /> + option} + optionValue={(option) => option} + onChange={handleFormFieldChange} + className="bg-white h-11 w-full mt-2 shadow-sm md:leading-5 md:col-span-1" + error={state.errors.assigned_facility_type} + /> + option} + optionValue={(option) => option} + onChange={handleFormFieldChange} + className="bg-white h-11 w-full mt-2 shadow-sm md:leading-5 md:col-span-1" + /> + + )} + + + + + + { + handleFormFieldChange(event); + }} + error={state.errors.ambulance_phone_number} + /> + + + + + +
+ goBack()} /> + handleSubmit()} /> +
+
+ +
); }; From 9150a028897b5c35b4110ff11bf57791ba01e8ce Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Fri, 28 Apr 2023 20:21:20 +0530 Subject: [PATCH 12/38] Update ShiftCreate.tsx (#5419) --- src/Components/Patient/ShiftCreate.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/Patient/ShiftCreate.tsx b/src/Components/Patient/ShiftCreate.tsx index d9a99b3fc45..a569bdf950e 100644 --- a/src/Components/Patient/ShiftCreate.tsx +++ b/src/Components/Patient/ShiftCreate.tsx @@ -78,10 +78,10 @@ export const ShiftCreate = (props: patientShiftProps) => { let requiredFields: any = { refering_facility_contact_name: { - errorText: "Name of contact of the referring facility", + errorText: "Name of contact of the current facility", }, refering_facility_contact_number: { - errorText: "Phone number of contact of the referring facility", + errorText: "Phone number of contact of the current facility", invalidText: "Please enter valid phone number", }, reason: { From c990a9889aa0068db5c15b7aa74df02db05eb457 Mon Sep 17 00:00:00 2001 From: Abhiuday Gupta <77210185+cp-Coder@users.noreply.github.com> Date: Fri, 28 Apr 2023 22:19:49 +0530 Subject: [PATCH 13/38] fix: patient category shifting form (#5392) * fix(shifting): updated logic to select patient category value * Fix patient category display --------- Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Co-authored-by: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> --- src/Components/Patient/ShiftCreate.tsx | 4 ++-- src/Components/Shifting/ShiftDetails.tsx | 4 +++- src/Components/Shifting/ShiftDetailsUpdate.tsx | 5 ++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Components/Patient/ShiftCreate.tsx b/src/Components/Patient/ShiftCreate.tsx index a569bdf950e..e863ae3fd84 100644 --- a/src/Components/Patient/ShiftCreate.tsx +++ b/src/Components/Patient/ShiftCreate.tsx @@ -411,8 +411,8 @@ export const ShiftCreate = (props: patientShiftProps) => { required={false} name="patient_category" value={patientCategory} - onChange={(value) => { - setPatientCategory(value); + onChange={(e) => { + setPatientCategory(e.value); }} label="Patient Category" /> diff --git a/src/Components/Shifting/ShiftDetails.tsx b/src/Components/Shifting/ShiftDetails.tsx index 2653f141592..8305f06b9a9 100644 --- a/src/Components/Shifting/ShiftDetails.tsx +++ b/src/Components/Shifting/ShiftDetails.tsx @@ -679,7 +679,9 @@ export default function ShiftDetails(props: { id: string }) { {" "} - {data.patient_category} + {data.patient_object.last_consultation?.last_daily_round + ?.patient_category ?? + data.patient_object.last_consultation?.category}
{kasp_enabled && ( diff --git a/src/Components/Shifting/ShiftDetailsUpdate.tsx b/src/Components/Shifting/ShiftDetailsUpdate.tsx index aa7a38e62c5..36c64efbd45 100644 --- a/src/Components/Shifting/ShiftDetailsUpdate.tsx +++ b/src/Components/Shifting/ShiftDetailsUpdate.tsx @@ -262,8 +262,11 @@ export const ShiftDetailsUpdate = (props: patientShiftProps) => { }; d["initial_status"] = res.data.status; d["status"] = qParams.status || res.data.status; + const patient_category = + d.patient.last_consultation?.last_daily_round?.patient_category ?? + d.patient.last_consultation?.category; d["patient_category"] = PATIENT_CATEGORIES.find( - (c) => c.text === res.data.patient_category + (c) => c.text === patient_category )?.id; dispatch({ type: "set_form", form: d }); } From 627e38807cbac2c4cea3188b84251cb4af1a7a26 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Tue, 2 May 2023 15:01:58 +0530 Subject: [PATCH 14/38] closes #5397 (#5421) --- src/Common/constants.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index ac0fa92bd12..c6c12f1cd3f 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -137,7 +137,7 @@ export const FACILITY_TYPES: Array = [ ]; export const SHIFTING_CHOICES_WARTIME: Array = [ - { id: 10, text: "PENDING" }, + { id: 10, text: "PENDING", label: "SHIFTING APPROVAL PENDING" }, { id: 15, text: "ON HOLD" }, { id: 20, text: "APPROVED" }, { id: 30, text: "REJECTED" }, From ecf8cb438ed069dba48904ffb846a6acae2bd46c Mon Sep 17 00:00:00 2001 From: Pranshu Aggarwal <70687348+Pranshu1902@users.noreply.github.com> Date: Tue, 2 May 2023 15:03:27 +0530 Subject: [PATCH 15/38] added success notification (#5409) --- src/Components/Users/SkillsSlideOver.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Components/Users/SkillsSlideOver.tsx b/src/Components/Users/SkillsSlideOver.tsx index 973f7ed559f..785a2513a18 100644 --- a/src/Components/Users/SkillsSlideOver.tsx +++ b/src/Components/Users/SkillsSlideOver.tsx @@ -55,6 +55,10 @@ export default ({ show, setShow, username }: IProps) => { Notification.Error({ msg: "Error while adding skill", }); + } else { + Notification.Success({ + msg: "Skill added successfully", + }); } setSelectedSkill(null); setIsLoading(false); From a9ed3746385ab2e97cfca7329ca63fad36a1c796 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Tue, 2 May 2023 15:04:42 +0530 Subject: [PATCH 16/38] Consultation Form: Navigate to Create Shift on submit if "Decision after consultation" is "Refer to another Hospital" (#5298) * fixes #5296 * move to consultation page before moving to create shift --------- Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- src/Components/Facility/ConsultationForm.tsx | 27 ++++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index b295ff47412..2a7e18a468c 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -693,6 +693,7 @@ export const ConsultationForm = (props: any) => { setIsLoading(false); if (res && res.data && res.status !== 400) { dispatch({ type: "set_form", form: initForm }); + if (data.suggestion === "DD") { await declareThePatientDead( state.form.cause_of_death, @@ -700,20 +701,18 @@ export const ConsultationForm = (props: any) => { state.form.death_confirmed_doctor ); } - if (id) { - Notification.Success({ - msg: "Consultation updated successfully", - }); - navigate( - `/facility/${facilityId}/patient/${patientId}/consultation/${id}` - ); - } else { - Notification.Success({ - msg: "Consultation created successfully", - }); - navigate( - `/facility/${facilityId}/patient/${patientId}/consultation/${res.data.id}` - ); + + Notification.Success({ + msg: `Consultation ${id ? "updated" : "created"} successfully`, + }); + + navigate( + `/facility/${facilityId}/patient/${patientId}/consultation/${res.data.id}` + ); + + if (data.suggestion === "R") { + navigate(`/facility/${facilityId}/patient/${patientId}/shift/new`); + return; } } } From 29e08dbdc27f54161e3ee4ca2f3438c0ddaaf995 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Tue, 2 May 2023 17:43:43 +0530 Subject: [PATCH 17/38] Disables multiple buttons for read only users (#5425) * fixes #5424 * fix `ButtonV2`'s Authorized wrapper not returned * disable for Asset Delete Button --------- Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- src/Components/Assets/AssetManage.tsx | 12 ++-- src/Components/Assets/AssetsList.tsx | 7 +- src/Components/Common/components/ButtonV2.tsx | 64 ++++++++++--------- .../Facility/ConsultationDetails.tsx | 6 +- .../Facility/Investigations/index.tsx | 4 +- src/Components/Patient/FileUpload.tsx | 21 +++--- src/Locale/en/Asset.json | 3 + src/Locale/en/Common.json | 8 ++- src/Locale/en/Consultation.json | 1 + src/Locale/en/index.js | 2 + src/Utils/VoiceRecorder.tsx | 20 ++++-- 11 files changed, 92 insertions(+), 56 deletions(-) create mode 100644 src/Locale/en/Asset.json diff --git a/src/Components/Assets/AssetManage.tsx b/src/Components/Assets/AssetManage.tsx index 5a48526c8f8..4d8de391c41 100644 --- a/src/Components/Assets/AssetManage.tsx +++ b/src/Components/Assets/AssetManage.tsx @@ -25,6 +25,7 @@ import { useTranslation } from "react-i18next"; const PageTitle = loadable(() => import("../Common/PageTitle")); const Loading = loadable(() => import("../Common/Loading")); import * as Notification from "../../Utils/Notifications.js"; +import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; interface AssetManageProps { assetId: string; @@ -324,9 +325,10 @@ const AssetManage = (props: AssetManageProps) => { ) } id="update-asset" + authorizeFor={NonReadOnlyUsers} > - Update + {t("update")} {asset?.asset_class && ( { ) } id="configure-asset" + authorizeFor={NonReadOnlyUsers} > - Configure + {t("configure")} )} {checkAuthority(user_type, "DistrictAdmin") && ( setShowDeleteDialog(true)} - variant={"danger"} + variant="danger" className="inline-flex" > - Delete + {t("delete")} )}
diff --git a/src/Components/Assets/AssetsList.tsx b/src/Components/Assets/AssetsList.tsx index 89d4ae5afc3..dd7f62a3c2b 100644 --- a/src/Components/Assets/AssetsList.tsx +++ b/src/Components/Assets/AssetsList.tsx @@ -20,7 +20,7 @@ import useFilters from "../../Common/hooks/useFilters"; import { FacilityModel } from "../Facility/models"; import CareIcon from "../../CAREUI/icons/CareIcon"; import { useIsAuthorized } from "../../Common/hooks/useIsAuthorized"; -import AuthorizeFor from "../../Utils/AuthorizeFor"; +import AuthorizeFor, { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; import ButtonV2 from "../Common/components/ButtonV2"; import FacilitiesSelectDialogue from "../ExternalResult/FacilitiesSelectDialogue"; import ExportMenu from "../Common/Export"; @@ -28,10 +28,12 @@ import CountBlock from "../../CAREUI/display/Count"; import AssetImportModal from "./AssetImportModal"; import Page from "../Common/components/Page"; import { AdvancedFilterButton } from "../../CAREUI/interactive/FiltersSlideover"; +import { useTranslation } from "react-i18next"; const Loading = loadable(() => import("../Common/Loading")); const AssetsList = () => { + const { t } = useTranslation(); const { qParams, updateQuery, @@ -361,6 +363,7 @@ const AssetsList = () => {
{ if (qParams.facility) { @@ -371,7 +374,7 @@ const AssetsList = () => { }} > - Create Asset + {t("create_asset")}
diff --git a/src/Components/Common/components/ButtonV2.tsx b/src/Components/Common/components/ButtonV2.tsx index 22722268ead..a236ec96135 100644 --- a/src/Components/Common/components/ButtonV2.tsx +++ b/src/Components/Common/components/ButtonV2.tsx @@ -111,47 +111,51 @@ const ButtonV2 = ({ `button-shape-${circle ? "circle" : "square"}`, ghost ? `button-${variant}-ghost` : `button-${variant}-default`, border && `button-${variant}-border`, - shadow && "shadow enabled:hover:shadow-lg" + shadow && "shadow enabled:hover:shadow-lg", + tooltip && "tooltip" ); - if (authorizeFor) { - - {({ isAuthorized }) => ( - - )} - ; + if (tooltip) { + children = ( + <> + {tooltip && ( + + {tooltip} + + )} + {children} + + ); } if (href && !(disabled || loading)) { return ( - - {children} + + ); } + if (authorizeFor) { + return ( + + {({ isAuthorized }) => ( + + )} + + ); + } + return ( - ); diff --git a/src/Components/Facility/ConsultationDetails.tsx b/src/Components/Facility/ConsultationDetails.tsx index 75cd6611a2a..7ac160c1623 100644 --- a/src/Components/Facility/ConsultationDetails.tsx +++ b/src/Components/Facility/ConsultationDetails.tsx @@ -50,12 +50,15 @@ import loadable from "@loadable/component"; import moment from "moment"; import { navigate } from "raviger"; import { validateEmailAddress } from "../../Common/validation"; +import { useTranslation } from "react-i18next"; +import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; const Loading = loadable(() => import("../Common/Loading")); const PageTitle = loadable(() => import("../Common/PageTitle")); const symptomChoices = [...SYMPTOM_CHOICES]; export const ConsultationDetails = (props: any) => { + const { t } = useTranslation(); const { facilityId, patientId, consultationId } = props; const tab = props.tab.toUpperCase(); const dispatch: any = useDispatch(); @@ -1322,6 +1325,7 @@ export const ConsultationDetails = (props: any) => { />
navigate( @@ -1330,7 +1334,7 @@ export const ConsultationDetails = (props: any) => { } > - Log Lab Result + {t("log_lab_results")}
diff --git a/src/Components/Facility/Investigations/index.tsx b/src/Components/Facility/Investigations/index.tsx index b74e0c37c87..b0180dc0942 100644 --- a/src/Components/Facility/Investigations/index.tsx +++ b/src/Components/Facility/Investigations/index.tsx @@ -12,6 +12,7 @@ import { import * as Notification from "../../../Utils/Notifications.js"; import { navigate, useQueryParams } from "raviger"; import loadable from "@loadable/component"; +import { useTranslation } from "react-i18next"; const Loading = loadable(() => import("../../Common/Loading")); const PageTitle = loadable(() => import("../../Common/PageTitle")); @@ -74,6 +75,7 @@ const Investigation = (props: { patientId: string; facilityId: string; }) => { + const { t } = useTranslation(); const { patientId, facilityId } = props; const [{ investigations: queryInvestigationsRaw = undefined }] = useQueryParams(); @@ -282,7 +284,7 @@ const Investigation = (props: { return (
import("../Common/Loading")); const PageTitle = loadable(() => import("../Common/PageTitle")); @@ -1389,24 +1390,24 @@ export const FileUpload = (props: FileUploadProps) => { ) : (
- - + + {t("upload")} +
)} {file && ( diff --git a/src/Locale/en/Asset.json b/src/Locale/en/Asset.json new file mode 100644 index 00000000000..24a44ff187c --- /dev/null +++ b/src/Locale/en/Asset.json @@ -0,0 +1,3 @@ +{ + "create_asset": "Create Asset" +} \ No newline at end of file diff --git a/src/Locale/en/Common.json b/src/Locale/en/Common.json index f0d7e302b41..1f1129118a7 100644 --- a/src/Locale/en/Common.json +++ b/src/Locale/en/Common.json @@ -20,12 +20,16 @@ "care": "CARE", "something_went_wrong": "Something went wrong..!", "stop": "Stop", + "record": "Record", + "recording": "Recording", "yes": "Yes", "no": "No", "status": "Status", "created": "Created", "modified": "Modified", "updated": "Updated", + "update": "Update", + "configure": "Configure", "assigned_to": "Assigned to", "cancel": "Cancel", "clear": "Clear", @@ -104,6 +108,7 @@ "recommended_aspect_ratio_for": "Recommended aspect ratio for", "drag_drop_image_to_upload": "Drag & drop image to upload", "upload_an_image": "Upload an image", + "upload": "Upload", "uploading": "Uploading", "switch": "Switch", "capture": "Capture", @@ -121,5 +126,6 @@ "RESPIRATORY_SUPPORT_UNKNOWN": "None", "RESPIRATORY_SUPPORT_OXYGEN_SUPPORT": "O2 Support", "RESPIRATORY_SUPPORT_NON_INVASIVE": "NIV", - "RESPIRATORY_SUPPORT_INVASIVE": "IV" + "RESPIRATORY_SUPPORT_INVASIVE": "IV", + "choose_file": "Choose File" } \ No newline at end of file diff --git a/src/Locale/en/Consultation.json b/src/Locale/en/Consultation.json index a8c1adf685f..16e03486fd0 100644 --- a/src/Locale/en/Consultation.json +++ b/src/Locale/en/Consultation.json @@ -2,6 +2,7 @@ "no_consultation_updates": "No consultation updates", "consultation_updates": "Consultation updates", "update_log": "Update Log", + "log_lab_results": "Log Lab Results", "no_log_update_delta": "No changes since previous log update", "virtual_nursing_assistant": "Virtual Nursing Assistant" } \ No newline at end of file diff --git a/src/Locale/en/index.js b/src/Locale/en/index.js index b77b0a9f041..505e4418e90 100644 --- a/src/Locale/en/index.js +++ b/src/Locale/en/index.js @@ -1,4 +1,5 @@ import Auth from "./Auth.json"; +import Asset from "./Asset.json"; import Common from "./Common.json"; import Consultation from "./Consultation.json"; import Entities from "./Entities.json"; @@ -13,6 +14,7 @@ import SortOptions from "./SortOptions.json"; export default { ...Auth, + ...Asset, ...Common, ...Consultation, ...CoverImageEdit, diff --git a/src/Utils/VoiceRecorder.tsx b/src/Utils/VoiceRecorder.tsx index 758e8c47f1f..fdf45e819d0 100644 --- a/src/Utils/VoiceRecorder.tsx +++ b/src/Utils/VoiceRecorder.tsx @@ -3,7 +3,10 @@ import useRecorder from "./useRecorder"; import { useEffect, useState } from "react"; import ButtonV2 from "../Components/Common/components/ButtonV2"; import CareIcon from "../CAREUI/icons/CareIcon"; +import { NonReadOnlyUsers } from "./AuthorizeFor"; +import { useTranslation } from "react-i18next"; export const VoiceRecorder = (props: any) => { + const { t } = useTranslation(); const { createAudioBlob, confirmAudioBlobExists, reset, setResetRecording } = props; const [ @@ -40,8 +43,8 @@ export const VoiceRecorder = (props: any) => { <>
- - Recording... + + {t("recording") + "..."}
{ @@ -49,8 +52,8 @@ export const VoiceRecorder = (props: any) => { confirmAudioBlobExists(); }} > - - Stop + + {t("stop")}
@@ -61,9 +64,12 @@ export const VoiceRecorder = (props: any) => { ) : (
{!audioURL && ( - - - Record + + + {t("record")} )}
From beeeec0205d51691d489d163e49d48965e997751 Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Tue, 2 May 2023 17:44:31 +0530 Subject: [PATCH 18/38] Permissions for 'Transfer to Rec. Facility button' (#5422) --- src/Components/Patient/PatientHome.tsx | 39 +++++++++++----- src/Components/Shifting/ListView.tsx | 54 ++++++++++++++--------- src/Components/Shifting/ShiftingBoard.tsx | 15 ++++++- 3 files changed, 72 insertions(+), 36 deletions(-) diff --git a/src/Components/Patient/PatientHome.tsx b/src/Components/Patient/PatientHome.tsx index 733c77e61ec..76b388b596e 100644 --- a/src/Components/Patient/PatientHome.tsx +++ b/src/Components/Patient/PatientHome.tsx @@ -2,7 +2,7 @@ import { CircularProgress } from "@material-ui/core"; import { navigate } from "raviger"; import moment from "moment"; import React, { useCallback, useEffect, useState } from "react"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { GENDER_TYPES, SAMPLE_TEST_STATUS } from "../../Common/constants"; import loadable from "@loadable/component"; import { statusType, useAbortableEffect } from "../../Common/utils"; @@ -64,6 +64,11 @@ export const PatientHome = (props: any) => { const [isConsultationLoading, setIsConsultationLoading] = useState(false); const [isSampleLoading, setIsSampleLoading] = useState(false); const [sampleFlag, callSampleList] = useState(false); + const rootState: any = useSelector((rootState) => rootState); + const { currentUser } = rootState; + const userHomeFacilityId = currentUser.data.home_facility; + const userType = currentUser.data.user_type; + const { t } = useTranslation(); const [selectedStatus, setSelectedStatus] = useState<{ status: number; sample: any; @@ -651,16 +656,17 @@ export const PatientHome = (props: any) => {
)} - {patientData.is_vaccinated && patientData.last_vaccinated_date && ( -
-
- Last Vaccinated on -
-
- {formatDate(patientData.last_vaccinated_date)} + {patientData.is_vaccinated && + patientData.last_vaccinated_date && ( +
+
+ Last Vaccinated on +
+
+ {formatDate(patientData.last_vaccinated_date)} +
-
- )} + )} {patientData.countries_travelled && !!patientData.countries_travelled.length && (
@@ -933,15 +939,24 @@ export const PatientHome = (props: any) => { All Details
- {shift.status === "TRANSFER IN PROGRESS" && + {shift.status === "COMPLETED" && shift.assigned_facility && (
setModalFor(shift.external_id)} > - TRANSFER TO RECEIVING FACILITY + {t("transfer_to_receiving_facility")} rootState); + const { currentUser } = rootState; + const userHomeFacilityId = currentUser.data.home_facility; + const userType = currentUser.data.user_type; const { t } = useTranslation(); const handleTransferComplete = (shift: any) => { @@ -239,27 +243,33 @@ export default function ListView() { {t("all_details")}
- {shift.status === "TRANSFER IN PROGRESS" && - shift.assigned_facility && ( -
- setModalFor(shift.external_id)} - > - {t("transfer_to_receiving_facility")} - - - setModalFor({ externalId: undefined, loading: false }) - } - onConfirm={() => handleTransferComplete(shift)} - /> -
- )} + {shift.status === "COMPLETED" && shift.assigned_facility && ( +
+ setModalFor(shift.external_id)} + > + {t("transfer_to_receiving_facility")} + + + setModalFor({ externalId: undefined, loading: false }) + } + onConfirm={() => handleTransferComplete(shift)} + /> +
+ )}
diff --git a/src/Components/Shifting/ShiftingBoard.tsx b/src/Components/Shifting/ShiftingBoard.tsx index 6dc76fe0ea0..c7806c0eabb 100644 --- a/src/Components/Shifting/ShiftingBoard.tsx +++ b/src/Components/Shifting/ShiftingBoard.tsx @@ -15,7 +15,7 @@ import ConfirmDialogV2 from "../Common/ConfirmDialogV2"; import moment from "moment"; import { navigate } from "raviger"; import useConfig from "../../Common/hooks/useConfig"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; const limit = 14; @@ -52,6 +52,10 @@ const ShiftCard = ({ shift, filter }: any) => { item: shift, collect: (monitor) => ({ isDragging: !!monitor.isDragging() }), })); + const rootState: any = useSelector((rootState) => rootState); + const { currentUser } = rootState; + const userHomeFacilityId = currentUser.data.home_facility; + const userType = currentUser.data.user_type; const { t } = useTranslation(); const handleTransferComplete = (shift: any) => { @@ -208,11 +212,18 @@ const ShiftCard = ({ shift, filter }: any) => { {t("all_details")}

- {filter === "TRANSFER IN PROGRESS" && shift.assigned_facility && ( + {filter === "COMPLETED" && shift.assigned_facility && (
setModalFor(shift.external_id)} > {t("transfer_to_receiving_facility")} From 0bcf2d0496eb111ecf1f425a4c5064ed2c0ecd83 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Wed, 3 May 2023 19:30:07 +0530 Subject: [PATCH 19/38] fixes #5426 (#5427) --- src/Components/Patient/PatientHome.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/Patient/PatientHome.tsx b/src/Components/Patient/PatientHome.tsx index 76b388b596e..f48a1a95b7f 100644 --- a/src/Components/Patient/PatientHome.tsx +++ b/src/Components/Patient/PatientHome.tsx @@ -34,6 +34,7 @@ import ButtonV2 from "../Common/components/ButtonV2"; import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; import RelativeDateUserMention from "../Common/RelativeDateUserMention"; import CareIcon from "../../CAREUI/icons/CareIcon"; +import { useTranslation } from "react-i18next"; const Loading = loadable(() => import("../Common/Loading")); const PageTitle = loadable(() => import("../Common/PageTitle")); From bf54e6045a754cd8bad1775c62cca1ab76e65d7f Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Thu, 4 May 2023 09:24:23 +0530 Subject: [PATCH 20/38] Add "None" to patient action (#5355) * fix(log_update): updated action and review_interval to copy from previous log * fix(log_update): removed console logs * Add None to patient action * Change NONE to NO_ACTION --------- Co-authored-by: cp-Coder Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- src/Common/constants.tsx | 3 +- src/Components/Facility/ConsultationForm.tsx | 2 +- src/Components/Patient/DailyRounds.tsx | 65 ++++++++++---------- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index c6c12f1cd3f..258352a65fd 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -488,7 +488,8 @@ export const ICMR_CATEGORY = [ ]; export const TELEMEDICINE_ACTIONS = [ - { id: 10, text: "PENDING", desc: "Pending" }, + { id: 10, text: "NO_ACTION", desc: "No Action" }, + { id: 20, text: "PENDING", desc: "Pending" }, { id: 30, text: "SPECIALIST_REQUIRED", desc: "Specialist Required" }, { id: 40, text: "PLAN_FOR_HOME_CARE", desc: "Plan for Home Care" }, { id: 50, text: "FOLLOW_UP_NOT_REQUIRED", desc: "Follow Up Not Required" }, diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index 2a7e18a468c..18df8d86738 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -148,7 +148,7 @@ const initForm: FormDetails = { prn_prescription: [], investigation: [], is_telemedicine: "false", - action: undefined, + action: "NO_ACTION", assigned_to: "", assigned_to_object: null, special_instruction: "", diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx index ad786186b25..0ba60f4cf5c 100644 --- a/src/Components/Patient/DailyRounds.tsx +++ b/src/Components/Patient/DailyRounds.tsx @@ -52,7 +52,7 @@ const initForm: any = { patient_category: "Comfort", current_health: 0, recommend_discharge: false, - actions: null, + action: null, review_interval: 0, admitted_to: "", taken_at: null, @@ -110,10 +110,33 @@ export const DailyRounds = (props: any) => { const [facilityName, setFacilityName] = useState(""); const [patientName, setPatientName] = useState(""); const [prevReviewInterval, setPreviousReviewInterval] = useState(-1); + const [prevAction, setPreviousAction] = useState("NO_ACTION"); const [hasPreviousLog, setHasPreviousLog] = useState(false); const headerText = !id ? "Add Consultation Update" : "Info"; const buttonText = !id ? "Save" : "Continue"; + useEffect(() => { + (async () => { + if (patientId) { + const res = await dispatchAction(getPatient({ id: patientId })); + if (res.data) { + setPatientName(res.data.name); + setFacilityName(res.data.facility_object.name); + setPreviousReviewInterval( + Number(res.data.last_consultation.review_interval) + ); + setPreviousAction( + TELEMEDICINE_ACTIONS.find((action) => action.id === res.data.action) + ?.text || "NO_ACTION" + ); + } + } else { + setPatientName(""); + setFacilityName(""); + } + })(); + }, [dispatchAction, patientId]); + const fetchRoundDetails = useCallback( async (status: statusType) => { setIsLoading(true); @@ -149,26 +172,7 @@ export const DailyRounds = (props: any) => { ); useEffect(() => { - async function fetchPatientName() { - if (patientId) { - const res = await dispatchAction(getPatient({ id: patientId })); - if (res.data) { - setPatientName(res.data.name); - setFacilityName(res.data.facility_object.name); - setPreviousReviewInterval( - Number(res.data.last_consultation.review_interval) - ); - } - } else { - setPatientName(""); - setFacilityName(""); - } - } - fetchPatientName(); - }, [dispatchAction, patientId]); - - useEffect(() => { - async function fetchHasPreviousLog() { + (async () => { if (consultationId && !id) { const res = await dispatchAction( getDailyReport({ limit: 1, offset: 0 }, { consultationId }) @@ -187,8 +191,7 @@ export const DailyRounds = (props: any) => { }, }); } - } - fetchHasPreviousLog(); + })(); }, [dispatchAction, consultationId, id]); const validateForm = () => { @@ -275,10 +278,8 @@ export const DailyRounds = (props: any) => { other_details: state.form.other_details, consultation: consultationId, recommend_discharge: JSON.parse(state.form.recommend_discharge), - action: state.form.action, - review_interval: Number( - state.form.review_interval || prevReviewInterval - ), + action: prevAction, + review_interval: Number(prevReviewInterval), }; if (state.form.rounds_type === "NORMAL") { data = { @@ -648,11 +649,11 @@ export const DailyRounds = (props: any) => { setPreviousAction(e.target.value)} />
@@ -664,12 +665,14 @@ export const DailyRounds = (props: any) => { + setPreviousReviewInterval(Number(e.target.value)) + } errors={state.errors.review_interval} className="mt-1" /> From 7d4b845921c3d7b7060326bd9e2a0dd8d5cf01c9 Mon Sep 17 00:00:00 2001 From: ARYAN PATEL Date: Thu, 4 May 2023 09:24:57 +0530 Subject: [PATCH 21/38] added camera feature in fileupload components (#5043) * added camera feature for file upload * added camera icon * added camera icon * minor refactor * fixed the downloading bug --- src/Components/Patient/FileUpload.tsx | 204 +++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 3 deletions(-) diff --git a/src/Components/Patient/FileUpload.tsx b/src/Components/Patient/FileUpload.tsx index 66f27019d5e..2188f2f2015 100644 --- a/src/Components/Patient/FileUpload.tsx +++ b/src/Components/Patient/FileUpload.tsx @@ -1,7 +1,7 @@ import axios from "axios"; import { CircularProgress, InputLabel } from "@material-ui/core"; import loadable from "@loadable/component"; -import React, { useCallback, useState, useEffect } from "react"; +import React, { useCallback, useState, useEffect, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; import { statusType, useAbortableEffect } from "../../Common/utils"; import { @@ -31,6 +31,8 @@ import CareIcon from "../../CAREUI/icons/CareIcon"; import TextFormField from "../Form/FormFields/TextFormField"; import TextAreaFormField from "../Form/FormFields/TextAreaFormField"; import RecordMeta from "../../CAREUI/display/RecordMeta"; +import Webcam from "react-webcam"; +import useWindowDimensions from "../../Common/hooks/useWindowDimensions"; import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; const Loading = loadable(() => import("../Common/Loading")); @@ -153,6 +155,26 @@ export const FileUpload = (props: FileUploadProps) => { const [audioFileError, setAudioFileError] = useState(""); const [contentType, setcontentType] = useState(""); const [downloadURL, setDownloadURL] = useState(); + const FACING_MODE_USER = "user"; + const FACING_MODE_ENVIRONMENT = { exact: "environment" }; + const webRef = useRef(null); + const [previewImage, setPreviewImage] = useState(null); + const [facingMode, setFacingMode] = useState(FACING_MODE_USER); + const videoConstraints = { + width: 1280, + height: 720, + facingMode: "user", + }; + const { width } = useWindowDimensions(); + const LaptopScreenBreakpoint = 640; + const isLaptopScreen = width >= LaptopScreenBreakpoint ? true : false; + const handleSwitchCamera = useCallback(() => { + setFacingMode((prevState: any) => + prevState === FACING_MODE_USER + ? FACING_MODE_ENVIRONMENT + : FACING_MODE_USER + ); + }, []); const initialState = { open: false, isImage: false, @@ -171,6 +193,7 @@ export const FileUpload = (props: FileUploadProps) => { const [facilityName, setFacilityName] = useState(""); const [patientName, setPatientName] = useState(""); const [modalOpenForEdit, setModalOpenForEdit] = useState(false); + const [modalOpenForCamera, setModalOpenForCamera] = useState(false); const [modalOpenForArchive, setModalOpenForArchive] = useState(false); const [modalOpenForMoreDetails, setModalOpenForMoreDetails] = useState(false); const [archiveReason, setArchiveReason] = useState(""); @@ -207,6 +230,18 @@ export const FileUpload = (props: FileUploadProps) => { fetchPatientName(); }, [dispatch, patientId]); + const captureImage = () => { + setPreviewImage(webRef.current.getScreenshot()); + fetch(webRef.current.getScreenshot()) + .then((res) => res.blob()) + .then((blob) => { + const myFile = new File([blob], "image.png", { + type: blob.type, + }); + setFile(myFile); + }); + }; + const handlePagination = (page: number, limit: number) => { const offset = (page - 1) * limit; setCurrentPage(page); @@ -1113,7 +1148,7 @@ export const FileUpload = (props: FileUploadProps) => { {downloadURL && downloadURL.length > 0 && (
@@ -1156,6 +1191,159 @@ export const FileUpload = (props: FileUploadProps) => {
)} + +
+ +
+
+

Camera

+
+
+ } + className="max-w-2xl" + onClose={() => setModalOpenForCamera(false)} + > +
+ {!previewImage ? ( +
+ +
+ ) : ( +
+ +
+ )} +
+ + {/* buttons for mobile screens */} +
+
+ {!previewImage ? ( + + {t("switch")} + + ) : ( + <> + )} +
+
+ {!previewImage ? ( + <> +
+ { + captureImage(); + }} + className="m-2" + > + {t("capture")} + +
+ + ) : ( + <> +
+ { + setPreviewImage(null); + }} + className="m-2" + > + {t("retake")} + + { + setModalOpenForCamera(false); + }} + className="m-2" + > + {t("submit")} + +
+ + )} +
+
+ { + setPreviewImage(null); + setModalOpenForCamera(false); + }} + className="m-2" + > + {t("close")} + +
+
+ {/* buttons for laptop screens */} +