diff --git a/package-lock.json b/package-lock.json index b0027f9c7be..93346b978e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "echarts-for-react": "^3.0.2", "eslint-mdx": "^3.1.5", "events": "^3.3.0", - "glob": "^10.3.15", + "glob": "^10.4.2", "hi-profiles": "^1.0.6", "i18next": "^23.11.4", "i18next-browser-languagedetector": "^7.2.1", @@ -43,7 +43,7 @@ "react-copy-to-clipboard": "^5.1.0", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dnd-scrolling": "^1.3.7", + "react-dnd-scrolling": "^1.3.8", "react-dom": "18.3.1", "react-google-recaptcha": "^3.1.0", "react-i18next": "^13.0.1", @@ -13772,15 +13772,16 @@ "dev": true }, "node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", + "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -15439,9 +15440,9 @@ } }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -18160,9 +18161,9 @@ } }, "node_modules/minipass": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz", - "integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "engines": { "node": ">=16 || 14 >=14.17" } @@ -18959,6 +18960,11 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, "node_modules/pako": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", @@ -19056,15 +19062,15 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.0.tgz", - "integrity": "sha512-LNHTaVkzaYaLGlO+0u3rQTz7QrHTFOuKyba9JMTQutkmtNew8dw8wOD7mTU/5fCPZzCWpfW0XnQKzY61P0aTaw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -20019,9 +20025,9 @@ } }, "node_modules/react-dnd-scrolling": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/react-dnd-scrolling/-/react-dnd-scrolling-1.3.7.tgz", - "integrity": "sha512-iLMziS6A4fxiCBpheb+B5T3I8SnZtAeAJszADLavkCvCX+gWt0ElL7Z895c1xLZOlFTWvHPfeCMYtP5ELqV8zQ==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/react-dnd-scrolling/-/react-dnd-scrolling-1.3.8.tgz", + "integrity": "sha512-XcvmrTsQrPNry7jkY8RkNAZ2HZIiLiUzOSUltkW6eOhNjkKfivnPEhkj9hZf1JP4C32zxDsjN26xoBy7puZXoA==", "dependencies": { "hoist-non-react-statics": "3.x", "lodash.throttle": "^4.1.1", diff --git a/package.json b/package.json index e23c97fd517..59fd5cd89e8 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "echarts-for-react": "^3.0.2", "eslint-mdx": "^3.1.5", "events": "^3.3.0", - "glob": "^10.3.15", + "glob": "^10.4.2", "hi-profiles": "^1.0.6", "i18next": "^23.11.4", "i18next-browser-languagedetector": "^7.2.1", @@ -83,7 +83,7 @@ "react-copy-to-clipboard": "^5.1.0", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dnd-scrolling": "^1.3.7", + "react-dnd-scrolling": "^1.3.8", "react-dom": "18.3.1", "react-google-recaptcha": "^3.1.0", "react-i18next": "^13.0.1", diff --git a/src/CAREUI/display/NetworkSignal.tsx b/src/CAREUI/display/NetworkSignal.tsx index 1d5f2d49623..91ce6b58b4c 100644 --- a/src/CAREUI/display/NetworkSignal.tsx +++ b/src/CAREUI/display/NetworkSignal.tsx @@ -26,7 +26,7 @@ export default function NetworkSignal({ strength, children }: Props) { strength === 3 && "text-primary-500", )} > -
+
{strength === undefined ? ( )}
diff --git a/src/Common/hooks/useFullscreen.ts b/src/Common/hooks/useFullscreen.ts index 106e657cf16..a826ff5f0ad 100644 --- a/src/Common/hooks/useFullscreen.ts +++ b/src/Common/hooks/useFullscreen.ts @@ -5,10 +5,7 @@ interface HTMLElementWithFullscreen extends HTMLElement { webkitExitFullscreen?: () => void; } -export default function useFullscreen(): [ - boolean, - (value: boolean, element?: HTMLElement) => void, -] { +export default function useFullscreen() { const [isFullscreen, _setIsFullscreen] = useState( !!document.fullscreenElement, ); @@ -39,12 +36,22 @@ export default function useFullscreen(): [ else document.exitFullscreen(); } - const setFullscreen = (value: boolean, element?: HTMLElement) => { + const setFullscreen = ( + value: boolean, + element?: HTMLElement, + enterLandscape?: boolean, + ) => { const fullscreenElement = element ?? document.documentElement; - if (value) openFullscreen(fullscreenElement); - else exitFullscreen(fullscreenElement); + if (value) { + openFullscreen(fullscreenElement); + if (enterLandscape) { + (screen.orientation as any)?.lock?.("landscape"); + } + } else { + exitFullscreen(fullscreenElement); + } }; - return [isFullscreen, setFullscreen]; + return [isFullscreen, setFullscreen] as const; } diff --git a/src/Components/ABDM/ABHAProfileModal.tsx b/src/Components/ABDM/ABHAProfileModal.tsx index be991bb8f55..7815165db7d 100644 --- a/src/Components/ABDM/ABHAProfileModal.tsx +++ b/src/Components/ABDM/ABHAProfileModal.tsx @@ -67,64 +67,17 @@ const ABHAProfileModal = ({ patientId, show, onClose, abha }: IProps) => { } show={show} onClose={onClose} + className="max-w-[500px]" + fixedWidth={false} >
- <> -
-
- {abha?.name ? ( - {abha?.name} - ) : ( - <> - {abha?.first_name} - {abha?.middle_name} - {abha?.last_name} - - )} -
- {abha?.abha_number} - {abha?.health_id && ( -
- {abha.health_id.split("@")[0]} - {/* @ - {abha.health_id.split("@")[1] || "care"} */} -
- )} -
- {abha?.gender && ( -

- Gender: - - {abha?.gender} - -

- )} - {abha?.date_of_birth && ( -

- DOB: - - {abha?.date_of_birth} - -

- )} - {abha?.email && ( -

- Email: - - {abha?.email} - -

- )} -
-
- - <> +
{ "dist name": abha?.district, })} /> - +
+
+ {[ + { + label: "Name", + value: + abha?.name || + `${abha?.first_name} ${abha?.middle_name} ${abha?.last_name}`, + }, + { label: "DOB", value: abha?.date_of_birth }, + { label: "Gender", value: abha?.gender }, + { label: "ABHA Number", value: abha?.abha_number }, + { label: "ABHA ID", value: abha?.health_id?.split("@")[0] }, + { label: "Email", value: abha?.email }, + ].map((item, index) => + item.value ? ( +
+
{item.label}
+
{item.value}
+
+ ) : null, + )} +
-
+
{abha?.created_date && (
Created On: diff --git a/src/Components/CameraFeed/AssetBedSelect.tsx b/src/Components/CameraFeed/AssetBedSelect.tsx index f970a920abc..3d7b7ab0951 100644 --- a/src/Components/CameraFeed/AssetBedSelect.tsx +++ b/src/Components/CameraFeed/AssetBedSelect.tsx @@ -67,10 +67,10 @@ export const CameraPresetDropdown = (
diff --git a/src/Components/CameraFeed/CameraFeed.tsx b/src/Components/CameraFeed/CameraFeed.tsx index 1c6781ee51b..64b37587cb9 100644 --- a/src/Components/CameraFeed/CameraFeed.tsx +++ b/src/Components/CameraFeed/CameraFeed.tsx @@ -9,10 +9,9 @@ import FeedAlert, { FeedAlertState } from "./FeedAlert"; import FeedNetworkSignal from "./FeedNetworkSignal"; import NoFeedAvailable from "./NoFeedAvailable"; import FeedControls from "./FeedControls"; -import Fullscreen from "../../CAREUI/misc/Fullscreen"; import FeedWatermark from "./FeedWatermark"; import CareIcon from "../../CAREUI/icons/CareIcon"; -import { Error } from "../../Utils/Notifications"; +import useFullscreen from "../../Common/hooks/useFullscreen"; interface Props { children?: React.ReactNode; @@ -33,12 +32,13 @@ interface Props { export default function CameraFeed(props: Props) { const playerRef = useRef(null); + const playerWrapperRef = useRef(null); const streamUrl = getStreamUrl(props.asset); const player = usePlayer(streamUrl, playerRef); const operate = useOperateCamera(props.asset.id, props.silent); - const [isFullscreen, setFullscreen] = useState(false); + const [isFullscreen, setFullscreen] = useFullscreen(); const [state, setState] = useState(); useEffect(() => setState(player.status), [player.status, setState]); @@ -91,32 +91,20 @@ export default function CameraFeed(props: Props) { props.onReset?.(); initializeStream(); }; + return ( - { - setFullscreen(false); - - if (reason === "DEVICE_UNSUPPORTED") { - // iOS webkit allows only video/iframe elements to call full-screen - // APIs. But we need to show controls too, not just the video element. - Error({ - msg: "This device does not support viewing this content in full-screen.", - }); - } - }} - > +
-
+
{props.children} -
- +
+ { + if (!value) { + setFullscreen(false); + return; + } + + if (isIOS) { + const element = document.querySelector("video"); + if (!element) { + return; + } + setFullscreen(true, element, true); + return; + } + + if (!playerRef.current) { + return; + } + + setFullscreen( + true, + playerWrapperRef.current || + (playerRef.current as HTMLElement), + true, + ); + }} onReset={resetStream} onMove={async (data) => { props.onMove?.(); @@ -223,6 +236,6 @@ export default function CameraFeed(props: Props) { )}
- +
); } diff --git a/src/Components/CameraFeed/FeedNetworkSignal.tsx b/src/Components/CameraFeed/FeedNetworkSignal.tsx index 502c61843e8..68df86bb4d5 100644 --- a/src/Components/CameraFeed/FeedNetworkSignal.tsx +++ b/src/Components/CameraFeed/FeedNetworkSignal.tsx @@ -34,7 +34,7 @@ export default function FeedNetworkSignal(props: Props) { return ( - + {videoDelay ? ( `${(videoDelay * 1e3) | 1} ms` ) : ( diff --git a/src/Components/CameraFeed/FeedWatermark.tsx b/src/Components/CameraFeed/FeedWatermark.tsx index 90ca2d15863..90b9f7cc408 100644 --- a/src/Components/CameraFeed/FeedWatermark.tsx +++ b/src/Components/CameraFeed/FeedWatermark.tsx @@ -47,7 +47,7 @@ const Watermark = (props: { children: string; className: string }) => { return ( {props.children} diff --git a/src/Components/Common/FacilitySelect.tsx b/src/Components/Common/FacilitySelect.tsx index 2b820b40d6a..526bf6d68ac 100644 --- a/src/Components/Common/FacilitySelect.tsx +++ b/src/Components/Common/FacilitySelect.tsx @@ -17,7 +17,7 @@ interface FacilitySelectProps { district?: string; state?: string; showAll?: boolean; - showNOptions?: number; + showNOptions?: number | undefined; freeText?: boolean; selected?: FacilityModel | FacilityModel[] | null; setSelected: (selected: FacilityModel | FacilityModel[] | null) => void; @@ -34,7 +34,7 @@ export const FacilitySelect = (props: FacilitySelectProps) => { searchAll, disabled = false, showAll = true, - showNOptions = 10, + showNOptions, className = "", facilityType, district, @@ -65,6 +65,7 @@ export const FacilitySelect = (props: FacilitySelectProps) => { data?.results?.push({ name: text, }); + return data?.results; }, [searchAll, showAll, facilityType, district, exclude_user, freeText], diff --git a/src/Components/CriticalCareRecording/Recording/CriticalCare__Recording.res b/src/Components/CriticalCareRecording/Recording/CriticalCare__Recording.res index d919215071e..5ff736f5664 100644 --- a/src/Components/CriticalCareRecording/Recording/CriticalCare__Recording.res +++ b/src/Components/CriticalCareRecording/Recording/CriticalCare__Recording.res @@ -36,10 +36,11 @@ let basicEditor = (~facilityId, ~patientId, ~consultationId, ~id) => { href={`/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/daily-rounds/${id}/update`}>
-
{str("Basic Editor")}
-
+
+ +
} let editorNameToString = editor => { @@ -94,7 +95,7 @@ let reducer = (state, action) => { | ShowEditor(editor) => {...state, visibleEditor: Some(editor)} | CloseEditor => {...state, visibleEditor: None} | UpdateDailyRound(dailyRound, editor) => { - dailyRound: dailyRound, + dailyRound, visibleEditor: None, updatedEditors: Js.Array.concat([editor], state.updatedEditors), } @@ -103,7 +104,7 @@ let reducer = (state, action) => { let initialState = dailyRound => { visibleEditor: None, - dailyRound: dailyRound, + dailyRound, updatedEditors: [], } @@ -115,6 +116,21 @@ let updateDailyRound = (send, editor, dailyRound) => { let make = (~id, ~facilityId, ~patientId, ~consultationId, ~dailyRound) => { let (state, send) = React.useReducer(reducer, initialState(dailyRound)) + let sections = + dailyRound.roundsType == VentilatorRound + ? [ + HemodynamicParametersEditor, + NeurologicalMonitoringEditor, + VentilatorParametersEditor, + ArterialBloodGasAnalysisEditor, + BloodSugarEditor, + IOBalanceEditor, + DialysisEditor, + PressureSoreEditor, + NursingCareEditor, + ] + : [NeurologicalMonitoringEditor, VentilatorParametersEditor] +
{ReactUtils.nullUnless(
@@ -222,25 +238,15 @@ let make = (~id, ~facilityId, ~patientId, ~consultationId, ~dailyRound) => { className="bg-white px-2 md:px-6 py-5 border-b border-gray-200 sm:px-6 max-w-5xl mx-auto border mt-4 shadow rounded-lg">

{str("Record Updates")}

- {basicEditor(~facilityId, ~patientId, ~consultationId, ~id)} {Js.Array.map(editor => { + {basicEditor(~facilityId, ~patientId, ~consultationId, ~id)} + {Js.Array.map(editor => { editorToggle(editor, state, send) - }, [ - HemodynamicParametersEditor, - NeurologicalMonitoringEditor, - VentilatorParametersEditor, - ArterialBloodGasAnalysisEditor, - BloodSugarEditor, - IOBalanceEditor, - DialysisEditor, - PressureSoreEditor, - NursingCareEditor, - ])->React.array} + }, sections)->React.array}
diff --git a/src/Components/CriticalCareRecording/VentilatorParametersEditor/CriticalCare__VentilatorParametersEditor.res b/src/Components/CriticalCareRecording/VentilatorParametersEditor/CriticalCare__VentilatorParametersEditor.res index 0933f46bf1a..cd3010b1c1d 100644 --- a/src/Components/CriticalCareRecording/VentilatorParametersEditor/CriticalCare__VentilatorParametersEditor.res +++ b/src/Components/CriticalCareRecording/VentilatorParametersEditor/CriticalCare__VentilatorParametersEditor.res @@ -115,7 +115,7 @@ let makePayload = (state: VentilatorParameters.state) => { DictUtils.setOptionalNumber("ventilator_tidal_volume", state.ventilator_tidal_volume, payload) DictUtils.setOptionalNumber( "ventilator_oxygen_modality_oxygen_rate", - state.ventilator_interface === UNKNOWN && + state.ventilator_interface === OXYGEN_SUPPORT && state.ventilator_oxygen_modality !== HIGH_FLOW_NASAL_CANNULA ? state.ventilator_oxygen_modality_oxygen_rate : None, diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index a728ffc805a..436f8f19e04 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -1230,16 +1230,9 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { required={["A", "DC", "OP"].includes( state.form.suggestion, )} - label={ - { - A: "Date & Time of Admission to the Facility", - DC: "Date & Time of Domiciliary Care commencement", - OP: "Date & Time of Out-patient visit", - DD: "Date & Time of Consultation", - HI: "Date & Time of Consultation", - R: "Date & Time of Consultation", - }[state.form.suggestion] - } + label={t( + `encounter_date_field_label__${state.form.suggestion}`, + )} type="datetime-local" value={dayjs(state.form.encounter_date).format( "YYYY-MM-DDTHH:mm", @@ -1251,6 +1244,21 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { : undefined } /> + {dayjs().diff(state.form.encounter_date, "day") > 30 && ( +
+ + + {t("caution")}:{" "} + {t("back_dated_encounter_date_caution")}{" "} + + {dayjs(state.form.encounter_date).fromNow()}. + + +
+ )}
{state.form.route_to_facility === 30 && ( diff --git a/src/Components/Facility/Consultations/LiveFeed.tsx b/src/Components/Facility/Consultations/LiveFeed.tsx index 621a0baf0aa..a2d4eb9ee99 100644 --- a/src/Components/Facility/Consultations/LiveFeed.tsx +++ b/src/Components/Facility/Consultations/LiveFeed.tsx @@ -25,6 +25,7 @@ import { FieldLabel } from "../../Form/FormFields/FormField"; import useFullscreen from "../../../Common/hooks/useFullscreen"; import ReactPlayer from "react-player"; import { isIOS } from "../../../Utils/utils"; +import TextFormField from "../../Form/FormFields/TextFormField"; const LiveFeed = (props: any) => { const middlewareHostname = props.middlewareHostname; @@ -39,7 +40,7 @@ const LiveFeed = (props: any) => { ); const [videoStartTime, setVideoStartTime] = useState(null); const [bed, setBed] = useState({}); - const [preset, setNewPreset] = useState(""); + const [presetName, setPresetName] = useState(""); const [loading, setLoading] = useState(); const dispatch: any = useDispatch(); const [page, setPage] = useState({ @@ -145,7 +146,7 @@ const LiveFeed = (props: any) => { const updatePreset = async (currentPreset: any) => { const data = { bed_id: bed.id, - preset_name: preset, + preset_name: presetName, }; const response = await dispatch( partialUpdateAssetBed( @@ -187,7 +188,7 @@ const LiveFeed = (props: any) => { }, []); useEffect(() => { - setNewPreset(toUpdate?.meta?.preset_name); + setPresetName(toUpdate?.meta?.preset_name); setBed(toUpdate?.bed_object); }, [toUpdate]); @@ -334,23 +335,30 @@ const LiveFeed = (props: any) => { setToUpdate(null)} onConfirm={() => updatePreset(toUpdate)} > -
- Bed - setBed(selected as BedModel)} - selected={bed} - error="" - multiple={false} - location={cameraAsset.location_id} - facility={cameraAsset.facility_id} +
+ setPresetName(value)} /> +
+ Bed + setBed(selected as BedModel)} + selected={bed} + error="" + multiple={false} + location={cameraAsset.location_id} + facility={cameraAsset.facility_id} + /> +
)} diff --git a/src/Components/Facility/DischargeModal.tsx b/src/Components/Facility/DischargeModal.tsx index 0be7b4eabd8..0ed17210bf8 100644 --- a/src/Components/Facility/DischargeModal.tsx +++ b/src/Components/Facility/DischargeModal.tsx @@ -25,6 +25,7 @@ import { FacilitySelect } from "../Common/FacilitySelect"; import { FacilityModel } from "./models"; import dayjs from "../../Utils/dayjs"; import { FieldError } from "../Form/FieldValidators"; +import { useTranslation } from "react-i18next"; interface PreDischargeFormInterface { new_discharge_reason: number | null; @@ -57,6 +58,7 @@ const DischargeModal = ({ discharge_date = dayjs().format("YYYY-MM-DDTHH:mm"), death_datetime = dayjs().format("YYYY-MM-DDTHH:mm"), }: IProps) => { + const { t } = useTranslation(); const { enable_hcx } = useConfig(); const dispatch: any = useDispatch(); const [preDischargeForm, setPreDischargeForm] = @@ -80,18 +82,15 @@ const DischargeModal = ({ useEffect(() => { setPreDischargeForm((prev) => ({ ...prev, - new_discharge_reason, discharge_notes: referred_to ? "Patient Shifted to another facility." : "", - discharge_date, - death_datetime, referred_to_external: !referred_to?.id ? referred_to?.name : null, referred_to: referred_to?.id ? referred_to.id : null, })); setFacility(referred_to); - }, [referred_to, new_discharge_reason, discharge_date, death_datetime]); + }, [referred_to]); const discharge_reason = new_discharge_reason ?? preDischargeForm.new_discharge_reason; @@ -205,6 +204,19 @@ const DischargeModal = ({ })); }; + const encounterDuration = dayjs + .duration( + dayjs( + preDischargeForm[ + discharge_reason === + DISCHARGE_REASONS.find((i) => i.text == "Expired")?.id + ? "death_datetime" + : "discharge_date" + ], + ).diff(consultationData.encounter_date), + ) + .humanize(); + return ( - {discharge_reason === DISCHARGE_REASONS.find((i) => i.text == "Recovered")?.id && ( <> @@ -374,7 +385,13 @@ const DischargeModal = ({
)} -
+
+ + {t("encounter_duration_confirmation")}{" "} + {encounterDuration}. + +
+
{isSendingDischargeApi ? ( diff --git a/src/Components/Facility/LocationManagement.tsx b/src/Components/Facility/LocationManagement.tsx index 18f3af60eb5..6eecdb28afe 100644 --- a/src/Components/Facility/LocationManagement.tsx +++ b/src/Components/Facility/LocationManagement.tsx @@ -228,7 +228,7 @@ const Location = ({
-
+

{name}

diff --git a/src/Components/Form/AutoCompleteAsync.tsx b/src/Components/Form/AutoCompleteAsync.tsx index b66cf16b800..b9caa512137 100644 --- a/src/Components/Form/AutoCompleteAsync.tsx +++ b/src/Components/Form/AutoCompleteAsync.tsx @@ -18,7 +18,7 @@ interface Props { onChange: (selected: any) => void; optionLabel?: (option: any) => string; optionLabelChip?: (option: any) => string; - showNOptions?: number; + showNOptions?: number | undefined; multiple?: boolean; compareBy?: string; debounceTime?: number; @@ -40,7 +40,7 @@ const AutoCompleteAsync = (props: Props) => { onChange, optionLabel = (option: any) => option.label, optionLabelChip = (option: any) => option.label, - showNOptions = 10, + showNOptions, multiple = false, compareBy, debounceTime = 300, @@ -62,8 +62,13 @@ const AutoCompleteAsync = (props: Props) => { () => debounce(async (query: string) => { setLoading(true); - const data = await fetchData(query); - setData(data?.slice(0, showNOptions) || []); + const data = (await fetchData(query)) || []; + + if (showNOptions !== undefined) { + setData(data.slice(0, showNOptions)); + } else { + setData(data); + } setLoading(false); }, debounceTime), [fetchData, showNOptions, debounceTime], @@ -102,7 +107,6 @@ const AutoCompleteAsync = (props: Props) => { onChange={({ target }) => setQuery(target.value)} onFocus={props.onFocus} onBlur={() => { - setQuery(""); props.onBlur?.(); }} autoComplete="off" diff --git a/src/Components/Form/FormFields/PhoneNumberFormField.tsx b/src/Components/Form/FormFields/PhoneNumberFormField.tsx index b2034507475..c580a15e409 100644 --- a/src/Components/Form/FormFields/PhoneNumberFormField.tsx +++ b/src/Components/Form/FormFields/PhoneNumberFormField.tsx @@ -7,6 +7,7 @@ import { formatPhoneNumber as formatPhoneNumberUtil, getCountryCode, CountryData, + humanizeStrings, } from "../../../Utils/utils"; import phoneCodesJson from "../../../Common/static/countryPhoneAndFlags.json"; import { @@ -14,8 +15,9 @@ import { PhoneNumberValidator, PhoneNumberType, } from "../FieldValidators"; -import CareIcon, { IconName } from "../../../CAREUI/icons/CareIcon"; +import CareIcon from "../../../CAREUI/icons/CareIcon"; import { Popover } from "@headlessui/react"; +import { useTranslation } from "react-i18next"; const phoneCodes: Record = phoneCodesJson; @@ -154,29 +156,22 @@ export default function PhoneNumberFormField(props: Props) { ); } -const phoneNumberTypeIcons: Record = { - international_mobile: "l-globe", - indian_mobile: "l-mobile-android", - mobile: "l-mobile-android", - landline: "l-phone", - support: "l-headset", -}; +const PhoneNumberTypesHelp = (props: { types: PhoneNumberType[] }) => { + const { t } = useTranslation(); -const PhoneNumberTypesHelp = ({ types }: { types: PhoneNumberType[] }) => ( -
- {types.map((type) => ( - - - - {type.replace("_", " ")} - - - ))} -
-); + return ( +
+ +
+ Supports only{" "} + + {humanizeStrings(props.types.map((item) => t(item)))} + {" "} + numbers. +
+
+ ); +}; const conditionPhoneCode = (code: string) => { code = code.split(" ")[0]; diff --git a/src/Components/Medicine/CreatePrescriptionForm.tsx b/src/Components/Medicine/CreatePrescriptionForm.tsx index 173f5163427..a75cd868318 100644 --- a/src/Components/Medicine/CreatePrescriptionForm.tsx +++ b/src/Components/Medicine/CreatePrescriptionForm.tsx @@ -190,7 +190,9 @@ export const PRESCRIPTION_ROUTES = [ "INTRATHECAL", "TRANSDERMAL", "RECTAL", + "SUBLINGUAL", ] as const; + export const PRESCRIPTION_FREQUENCIES = { STAT: { slots: 1, diff --git a/src/Components/Medicine/models.ts b/src/Components/Medicine/models.ts index 53fd39d90f8..bb596e88b3e 100644 --- a/src/Components/Medicine/models.ts +++ b/src/Components/Medicine/models.ts @@ -8,6 +8,8 @@ export const DOSAGE_UNITS = [ "drop(s)", "ampule(s)", "tsp", + "mcg", + "unit(s)", ] as const; export type DosageValue = `${number} ${(typeof DOSAGE_UNITS)[number]}`; diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx index 2bb544327be..97ee038362b 100644 --- a/src/Components/Patient/DailyRounds.tsx +++ b/src/Components/Patient/DailyRounds.tsx @@ -343,11 +343,7 @@ export const DailyRounds = (props: any) => { Notification.Success({ msg: `${t(obj.rounds_type as string)} log updated successfully`, }); - if ( - ["NORMAL", "TELEMEDICINE", "DOCTORS_LOG"].includes( - state.form.rounds_type, - ) - ) { + if (["NORMAL", "TELEMEDICINE"].includes(state.form.rounds_type)) { navigate( `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}`, ); @@ -369,11 +365,7 @@ export const DailyRounds = (props: any) => { msg: `${t(state.form.rounds_type)} log created successfully`, }); - if ( - ["NORMAL", "TELEMEDICINE", "DOCTORS_LOG"].includes( - state.form.rounds_type, - ) - ) { + if (["NORMAL", "TELEMEDICINE"].includes(state.form.rounds_type)) { navigate( `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}`, ); diff --git a/src/Components/Patient/ManagePatients.tsx b/src/Components/Patient/ManagePatients.tsx index eaa1ff7af20..9ddcb4b379c 100644 --- a/src/Components/Patient/ManagePatients.tsx +++ b/src/Components/Patient/ManagePatients.tsx @@ -517,11 +517,11 @@ export const PatientManager = () => {
{patient.name} - + {formatPatientAge(patient, true)}
@@ -610,7 +610,7 @@ export const PatientManager = () => { size="small" variant="primary" startIcon="l-clock-three" - text={`IP Days: ${dayjs().diff(patient.last_consultation.encounter_date, "day")}`} + text={`IP Day No: ${dayjs().diff(patient.last_consultation.encounter_date, "day") + 1}`} /> )} {patient.gender === 2 && diff --git a/src/Components/Patient/PatientInfoCard.tsx b/src/Components/Patient/PatientInfoCard.tsx index a43d49a26ac..d3ad76bf661 100644 --- a/src/Components/Patient/PatientInfoCard.tsx +++ b/src/Components/Patient/PatientInfoCard.tsx @@ -559,12 +559,12 @@ export default function PatientInfoCard(props: { {dayjs(consultation.discharge_date || undefined).diff( consultation.encounter_date, "day", - )} + ) + 1}
- IP Days + IP Day No
)} diff --git a/src/Components/Scribe/Scribe.tsx b/src/Components/Scribe/Scribe.tsx index b5149267e24..e29b825124f 100644 --- a/src/Components/Scribe/Scribe.tsx +++ b/src/Components/Scribe/Scribe.tsx @@ -490,7 +490,7 @@ export const Scribe: React.FC = ({ fields, onFormUpdate }) => { ​ -
+

Voice AutoFill diff --git a/src/Components/Users/UserAdd.tsx b/src/Components/Users/UserAdd.tsx index f7e6b978fb9..bb8b1ea158d 100644 --- a/src/Components/Users/UserAdd.tsx +++ b/src/Components/Users/UserAdd.tsx @@ -608,7 +608,8 @@ export const UserAdd = (props: UserProps) => { className="inline-block rounded border border-gray-600 bg-gray-50 px-4 py-2 text-gray-600 transition hover:bg-gray-100" target="_blank" > -  Need Help? +  Need + Help? } backUrl="/users" diff --git a/src/Locale/en/Common.json b/src/Locale/en/Common.json index 3b6cb163e4d..6c4b2ceb9e7 100644 --- a/src/Locale/en/Common.json +++ b/src/Locale/en/Common.json @@ -48,6 +48,11 @@ "filter": "Filter", "ordering": "Ordering", "phone_number": "Phone Number", + "international_mobile": "International Mobile", + "indian_mobile": "Indian Mobile", + "mobile": "Mobile", + "landline": "Indian landline", + "support": "Support", "emergency_contact_number": "Emergency Contact Number", "last_modified": "Last Modified", "patient_address": "Patient Address", @@ -167,6 +172,7 @@ "ration_card__NO_CARD": "Non-card holder", "ration_card__BPL": "BPL", "ration_card__APL": "APL", + "caution": "Caution", "complete_vaccination_details": "Complete Vaccination Details", "vaccination_details": "Vaccination Details" } \ No newline at end of file diff --git a/src/Locale/en/Consultation.json b/src/Locale/en/Consultation.json index 4df1a4de9a3..d811680d0fd 100644 --- a/src/Locale/en/Consultation.json +++ b/src/Locale/en/Consultation.json @@ -36,5 +36,13 @@ "prev_sessions": "Prev Sessions", "next_sessions": "Next Sessions", "no_changes": "No changes", - "encounter_suggestion_edit_disallowed": "Not allowed to switch to this option in edit consultation" + "encounter_suggestion_edit_disallowed": "Not allowed to switch to this option in edit consultation", + "encounter_date_field_label__A": "Date & Time of Admission to the Facility", + "encounter_date_field_label__DC": "Date & Time of Domiciliary Care commencement", + "encounter_date_field_label__OP": "Date & Time of Out-patient visit", + "encounter_date_field_label__DD": "Date & Time of Consultation", + "encounter_date_field_label__HI": "Date & Time of Consultation", + "encounter_date_field_label__R": "Date & Time of Consultation", + "back_dated_encounter_date_caution": "You are creating an encounter for", + "encounter_duration_confirmation": "The duration of this encounter would be" } \ No newline at end of file diff --git a/src/Locale/en/Medicine.json b/src/Locale/en/Medicine.json index 4a5a5785047..c21f5fa236f 100644 --- a/src/Locale/en/Medicine.json +++ b/src/Locale/en/Medicine.json @@ -51,6 +51,7 @@ "PRESCRIPTION_ROUTE_INTRATHECAL": "intrathecal injection", "PRESCRIPTION_ROUTE_TRANSDERMAL": "Transdermal", "PRESCRIPTION_ROUTE_RECTAL": "Rectal", + "PRESCRIPTION_ROUTE_SUBLINGUAL": "Sublingual", "PRESCRIPTION_FREQUENCY_STAT": "Imediately", "PRESCRIPTION_FREQUENCY_OD": "Once daily", "PRESCRIPTION_FREQUENCY_HS": "Night only", diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index d599a494b1c..60c49da0dc9 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -454,3 +454,22 @@ export const isPostPartum = (data_of_delivery?: string) => { export const isAntenatal = (menstruation_start_date?: string) => { return dayjs().diff(menstruation_start_date, "month") <= 9; }; + +/** + * A utility method to format an array of string to human readable format. + * + * @param values Array of strings to be made human readable. + * @returns Human readable version of the list of strings + */ +export const humanizeStrings = (strings: readonly string[], empty = "") => { + if (strings.length === 0) { + return empty; + } + + if (strings.length === 1) { + return strings[0]; + } + + const [last, ...items] = [...strings].reverse(); + return `${items.reverse().join(", ")} and ${last}`; +};