diff --git a/.github/workflows/combine.yml b/.github/workflows/combine.yml new file mode 100644 index 00000000000..d44461ff5a7 --- /dev/null +++ b/.github/workflows/combine.yml @@ -0,0 +1,23 @@ +name: Combine Dependencies + +on: workflow_dispatch + +# The minimum permissions required to run this Action +permissions: + contents: write + pull-requests: write + checks: read + +jobs: + combine-prs: + runs-on: ubuntu-latest + + steps: + - name: Combine dependencies + id: combine-dependencies + uses: github/combine-prs@v5.0.0 + with: + pr_title: Combined dependencies # The title of the pull request to create + select_label: dependencies # The label which marks PRs that should be combined. + labels: combined-dependencies # Add a label to the combined PR + ci_required: "false" # Whether or not CI should be passing to combine the PR diff --git a/src/Components/ABDM/LinkABHANumberModal.tsx b/src/Components/ABDM/LinkABHANumberModal.tsx index fe789e6c909..d7dfc9f60c1 100644 --- a/src/Components/ABDM/LinkABHANumberModal.tsx +++ b/src/Components/ABDM/LinkABHANumberModal.tsx @@ -194,12 +194,12 @@ const ScanABHAQRSection = ({ body: { patientId, hidn: abha?.hidn, - phr: abha?.hid, + phr: (abha?.phr ?? abha?.hid) as string, name: abha?.name, gender: abha?.gender, dob: abha?.dob.replace(/\//g, "-"), address: abha?.address, - "dist name": abha?.district_name, + "dist name": abha?.["dist name"] ?? abha?.district_name, "state name": abha?.["state name"], }, }); diff --git a/src/Components/ABDM/models.ts b/src/Components/ABDM/models.ts index 957dc9c2d17..9dc362f5cac 100644 --- a/src/Components/ABDM/models.ts +++ b/src/Components/ABDM/models.ts @@ -123,10 +123,12 @@ export interface ILinkViaQRBody { export interface ABHAQRContent { address: string; distlgd: string; - district_name: string; + district_name?: string; dob: string; - gender: "M"; - hid: string; + gender: "M" | "F" | "O"; + hid?: string; + phr?: string; + "dist name"?: string; hidn: string; mobile: string; name: string; diff --git a/src/Components/Facility/FacilityCreate.tsx b/src/Components/Facility/FacilityCreate.tsx index 8aec0861d62..3138f374e4b 100644 --- a/src/Components/Facility/FacilityCreate.tsx +++ b/src/Components/Facility/FacilityCreate.tsx @@ -18,7 +18,7 @@ import { SelectFormField, } from "../Form/FormFields/SelectFormField"; import { Popover, Transition } from "@headlessui/react"; -import { Fragment, lazy, useState } from "react"; +import { Fragment, lazy, useEffect, useState } from "react"; import Steps, { Step } from "../Common/Steps"; import { getPincodeDetails, @@ -57,6 +57,7 @@ import request from "../../Utils/request/request.js"; import routes from "../../Redux/api.js"; import useQuery from "../../Utils/request/useQuery.js"; import { RequestResult } from "../../Utils/request/types.js"; +import useAuthUser from "../../Common/hooks/useAuthUser"; const Loading = lazy(() => import("../Common/Loading")); @@ -159,6 +160,21 @@ export const FacilityCreate = (props: FacilityProps) => { const headerText = !facilityId ? "Create Facility" : "Update Facility"; const buttonText = !facilityId ? "Save Facility" : "Update Facility"; + const authUser = useAuthUser(); + useEffect(() => { + if ( + authUser && + authUser.user_type !== "StateAdmin" && + authUser.user_type !== "DistrictAdmin" && + authUser.user_type !== "DistrictLabAdmin" + ) { + navigate("/facility"); + Notification.Error({ + msg: "You don't have permission to perform this action. Contact the admin", + }); + } + }, [authUser]); + const { data: districtData, refetch: districtFetch, diff --git a/src/Components/Facility/TreatmentSummary.tsx b/src/Components/Facility/TreatmentSummary.tsx index d0d1658cd61..a83cb64ec66 100644 --- a/src/Components/Facility/TreatmentSummary.tsx +++ b/src/Components/Facility/TreatmentSummary.tsx @@ -78,9 +78,13 @@ const TreatmentSummary = (props: any) => {
- Date of admission : + {consultationData?.suggestion === "DC" ? ( + Date of domiciliary care commenced : + ) : ( + Date of admission : + )} - {consultationData?.admitted + {consultationData?.encounter_date ? formatDateTime(consultationData.encounter_date) : " --/--/----"} diff --git a/src/Components/Form/FormFields/TextFormField.tsx b/src/Components/Form/FormFields/TextFormField.tsx index 8f1ee341e34..b2a84e51595 100644 --- a/src/Components/Form/FormFields/TextFormField.tsx +++ b/src/Components/Form/FormFields/TextFormField.tsx @@ -100,7 +100,7 @@ const TextFormField = forwardRef((props: TextFormFieldProps, ref) => { ); const _trailing = trailing === trailingFocused ? ( -
+
{trailing}
) : ( diff --git a/src/Components/Notifications/NotificationsList.tsx b/src/Components/Notifications/NotificationsList.tsx index 02cb1f4fa8b..c9e6720e6ad 100644 --- a/src/Components/Notifications/NotificationsList.tsx +++ b/src/Components/Notifications/NotificationsList.tsx @@ -46,6 +46,16 @@ const NotificationTile = ({ setIsMarkingAsRead(false); }; + const handleMarkAsUnRead = async () => { + setIsMarkingAsRead(true); + await request(routes.markNotificationAsUnRead, { + pathParams: { id: result.id }, + body: { read_at: null }, + }); + setResult({ ...result, read_at: null }); + setIsMarkingAsRead(false); + }; + const resultUrl = (event: string, data: any) => { switch (event) { case "PATIENT_CREATED": @@ -107,24 +117,33 @@ const NotificationTile = ({
{ event.stopPropagation(); - handleMarkAsRead(); + if (result.read_at) { + handleMarkAsUnRead(); + } else { + handleMarkAsRead(); + } }} > - {t("mark_as_read")} + + {result.read_at ? t("mark_as_unread") : t("mark_as_read")} + { diagnoses_provisional: qParams.diagnoses_provisional || undefined, diagnoses_unconfirmed: qParams.diagnoses_unconfirmed || undefined, diagnoses_differential: qParams.diagnoses_differential || undefined, + review_missed: qParams.review_missed || undefined, }; useEffect(() => { @@ -944,6 +945,7 @@ export const PatientManager = () => { kasp(), badge("COWIN ID", "covin_id"), badge("Is Antenatal", "is_antenatal"), + badge("Review Missed", "review_missed"), badge( "Is Medico-Legal Case", "last_consultation_medico_legal_case", diff --git a/src/Components/Patient/PatientFilter.tsx b/src/Components/Patient/PatientFilter.tsx index 0c0087e6d66..79a04242170 100644 --- a/src/Components/Patient/PatientFilter.tsx +++ b/src/Components/Patient/PatientFilter.tsx @@ -100,6 +100,7 @@ export default function PatientFilter(props: any) { diagnoses_provisional: filter.diagnoses_provisional || null, diagnoses_unconfirmed: filter.diagnoses_unconfirmed || null, diagnoses_differential: filter.diagnoses_differential || null, + review_missed: filter.review_missed || null, }); useQuery(routes.getAnyFacility, { @@ -203,6 +204,7 @@ export default function PatientFilter(props: any) { diagnoses_provisional, diagnoses_unconfirmed, diagnoses_differential, + review_missed, } = filterState; const data = { district: district || "", @@ -270,6 +272,7 @@ export default function PatientFilter(props: any) { diagnoses_provisional: diagnoses_provisional || "", diagnoses_unconfirmed: diagnoses_unconfirmed || "", diagnoses_differential: diagnoses_differential || "", + review_missed: review_missed || "", }; onChange(data); }; @@ -437,6 +440,18 @@ export default function PatientFilter(props: any) { } />
+
+ Review Missed + (o === "true" ? "Yes" : "No")} + value={filterState.review_missed} + onChange={(v) => + setFilterState({ ...filterState, review_missed: v }) + } + /> +
Is Medico-Legal Case {consultation?.encounter_date && (
- Admission on:{" "} + {consultation.suggestion === "DC" + ? "Commenced on: " + : "Admitted on: "} {formatDateTime(consultation?.encounter_date)}
)} diff --git a/src/Components/Patient/PatientRegister.tsx b/src/Components/Patient/PatientRegister.tsx index 3be6b985dda..dbc5b869e3e 100644 --- a/src/Components/Patient/PatientRegister.tsx +++ b/src/Components/Patient/PatientRegister.tsx @@ -1382,10 +1382,10 @@ export const PatientRegister = (props: PatientRegisterProps) => { {...field("age")} errorClassName="hidden" trailing={ -

-

+

+

{field("age").value !== "" && - "Year_of_Birth:"} + "Year of Birth:"}

{field("age").value !== "" && diff --git a/src/Components/Patient/SampleDetails.tsx b/src/Components/Patient/SampleDetails.tsx index f66805a3ded..a3d3df95c21 100644 --- a/src/Components/Patient/SampleDetails.tsx +++ b/src/Components/Patient/SampleDetails.tsx @@ -265,7 +265,7 @@ export const SampleDetails = ({ id }: DetailRoute) => { ); }; - if (isLoading) { + if (isLoading || !sampleDetails) { return ; } diff --git a/src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx b/src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx index 0d5a137becc..61c62f80c70 100644 --- a/src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx +++ b/src/Components/VitalsMonitor/HL7PatientVitalsMonitor.tsx @@ -151,9 +151,11 @@ export default function HL7PatientVitalsMonitor(props: IVitalsComponentProps) { > - No incoming data from HL7 Monitor + + No incoming data from HL7 Monitor +
(), }, + markNotificationAsUnRead: { + path: "/api/v1/notification/{id}/", + method: "PATCH", + TRes: Type(), + }, getPublicKey: { path: "/api/v1/notification/public_key/", method: "GET", diff --git a/src/Utils/useRecorder.js b/src/Utils/useRecorder.js index 5c9dc324ce1..585e557d787 100644 --- a/src/Utils/useRecorder.js +++ b/src/Utils/useRecorder.js @@ -7,6 +7,12 @@ const useRecorder = (handleMicPermission) => { const [recorder, setRecorder] = useState(null); const [newBlob, setNewBlob] = useState(null); + useEffect(() => { + if (!isRecording && recorder && audioURL) { + setRecorder(null); + } + }, [isRecording, recorder, audioURL]); + useEffect(() => { // Lazily obtain recorder first time we're recording. if (recorder === null) { @@ -32,6 +38,7 @@ const useRecorder = (handleMicPermission) => { if (isRecording) { recorder.start(); } else { + recorder.stream.getTracks().forEach((i) => i.stop()); recorder.stop(); } diff --git a/src/Utils/useSegmentedRecorder.ts b/src/Utils/useSegmentedRecorder.ts index d58ca67bc7c..9434ea8383c 100644 --- a/src/Utils/useSegmentedRecorder.ts +++ b/src/Utils/useSegmentedRecorder.ts @@ -2,7 +2,6 @@ import { useState, useEffect } from "react"; import * as Notify from "./Notifications"; const useSegmentedRecording = () => { - const [audioURL, setAudioURL] = useState(""); const [isRecording, setIsRecording] = useState(false); const [recorder, setRecorder] = useState(null); const [audioBlobs, setAudioBlobs] = useState([]); @@ -11,6 +10,12 @@ const useSegmentedRecording = () => { const bufferInterval = 1 * 1000; const splitSizeLimit = 20 * 1000000; // 20MB + useEffect(() => { + if (!isRecording && recorder && audioBlobs.length > 0) { + setRecorder(null); + } + }, [isRecording, recorder, audioBlobs]); + useEffect(() => { if (recorder === null) { if (isRecording || restart) { @@ -37,6 +42,9 @@ const useSegmentedRecording = () => { } else { if (restart) { setIsRecording(true); + } else { + recorder?.stream?.getTracks()?.forEach((i) => i?.stop()); + recorder.stop(); } recorder.state === "recording" && recorder.stop(); } @@ -96,12 +104,10 @@ const useSegmentedRecording = () => { }; const resetRecording = () => { - setAudioURL(""); setAudioBlobs([]); }; return { - audioURL, isRecording, startRecording, stopRecording,