Skip to content

Commit

Permalink
Add Consultation Specific route for Doctor Notes (#6851)
Browse files Browse the repository at this point in the history
* add new route

* refactor

* show consultation specific notes by passing consultation param in api

* use useQuery

* refactor

* fix offset calls

* refactor props

* use common component

* separate files for notes

* auto fetch on adding new note

* refactor

* remove dispatch

* remove dispatch on patient notes

* use request instead of usequery on consultation notes page

* replace useQuery with request on patient notes

* remove dispatch

* useQuery and change model name
  • Loading branch information
Pranshu1902 authored Dec 20, 2023
1 parent 83c4524 commit 23af9e0
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 113 deletions.
1 change: 1 addition & 0 deletions src/Components/Facility/ConsultationDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ export const ConsultationDetails = (props: any) => {
<PatientNotesSlideover
patientId={patientId}
facilityId={facilityId}
consultationId={consultationId}
setShowPatientNotesPopup={setShowPatientNotesPopup}
/>
)}
Expand Down
135 changes: 135 additions & 0 deletions src/Components/Facility/ConsultationDoctorNotes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { useState } from "react";
import * as Notification from "../../../Utils/Notifications.js";
import Page from "../../Common/components/Page";
import TextFormField from "../../Form/FormFields/TextFormField";
import ButtonV2 from "../../Common/components/ButtonV2";
import CareIcon from "../../../CAREUI/icons/CareIcon";
import { NonReadOnlyUsers } from "../../../Utils/AuthorizeFor";
import { useMessageListener } from "../../../Common/hooks/useMessageListener";
import PatientConsultationNotesList from "../PatientConsultationNotesList.js";
import { PatientNoteStateType } from "../models.js";
import routes from "../../../Redux/api.js";
import request from "../../../Utils/request/request.js";
import useQuery from "../../../Utils/request/useQuery.js";

interface ConsultationDoctorNotesProps {
patientId: string;
facilityId: string;
consultationId: string;
}

const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => {
const { patientId, facilityId, consultationId } = props;

const [patientActive, setPatientActive] = useState(true);
const [noteField, setNoteField] = useState("");
const [reload, setReload] = useState(false);
const [facilityName, setFacilityName] = useState("");
const [patientName, setPatientName] = useState("");

const initialData: PatientNoteStateType = {
notes: [],
cPage: 1,
totalPages: 1,
};
const [state, setState] = useState(initialData);

const onAddNote = async () => {
const payload = {
note: noteField,
consultation: consultationId,
};
if (!/\S+/.test(noteField)) {
Notification.Error({
msg: "Note Should Contain At Least 1 Character",
});
return;
}

const { res } = await request(routes.addPatientNote, {
pathParams: {
patientId: patientId,
},
body: payload,
});

if (res?.status === 201) {
Notification.Success({ msg: "Note added successfully" });
setState({ ...state, cPage: 1 });
setNoteField("");
setReload(true);
}
};

useQuery(routes.getPatient, {
pathParams: { id: patientId },
onResponse: ({ data }) => {
if (data) {
setPatientActive(data.is_active ?? true);
setPatientName(data.name ?? "");
setFacilityName(data.facility_object?.name ?? "");
}
},
});

useMessageListener((data) => {
const message = data?.message;
if (
(message?.from == "patient/doctor_notes/create" ||
message?.from == "patient/doctor_notes/edit") &&
message?.facility_id == facilityId &&
message?.patient_id == patientId
) {
setReload(true);
}
});

return (
<Page
title="Doctor Notes"
className="flex h-screen flex-col"
crumbsReplacements={{
[facilityId]: { name: facilityName },
[patientId]: { name: patientName },
}}
backUrl={`/facility/${facilityId}/patient/${patientId}`}
>
<div className="mx-3 my-2 flex grow flex-col rounded-lg bg-white p-2 sm:mx-10 sm:my-5 sm:p-5">
<PatientConsultationNotesList
state={state}
setState={setState}
patientId={patientId}
facilityId={facilityId}
reload={reload}
setReload={setReload}
/>

<div className="relative mx-4 flex items-center">
<TextFormField
name="note"
value={noteField}
onChange={(e) => setNoteField(e.value)}
className="grow"
type="text"
errorClassName="hidden"
placeholder="Type your Note"
disabled={!patientActive}
/>
<ButtonV2
onClick={onAddNote}
border={false}
className="absolute right-2"
ghost
size="small"
disabled={!patientActive}
authorizeFor={NonReadOnlyUsers}
>
<CareIcon className="care-l-message text-lg" />
</ButtonV2>
</div>
</div>
</Page>
);
};

export default ConsultationDoctorNotes;
45 changes: 45 additions & 0 deletions src/Components/Facility/DoctorNote.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import InfiniteScroll from "react-infinite-scroll-component";
import CircularProgress from "../Common/components/CircularProgress";
import PatientNoteCard from "./PatientNoteCard";
import { PatientNoteStateType } from "./models";

interface DoctorNoteProps {
state: PatientNoteStateType;
handleNext: () => void;
}

const DoctorNote = (props: DoctorNoteProps) => {
const { state, handleNext } = props;
return (
<div
className="m-2 flex h-[390px] grow flex-col-reverse overflow-auto bg-white"
id="patient-notes-list"
>
{state.notes.length ? (
<InfiniteScroll
next={handleNext}
hasMore={state.cPage < state.totalPages}
loader={
<div className="flex items-center justify-center">
<CircularProgress />
</div>
}
className="flex h-full flex-col-reverse p-2"
inverse={true}
dataLength={state.notes.length}
scrollableTarget="patient-notes-list"
>
{state.notes.map((note: any) => (
<PatientNoteCard note={note} key={note.id} />
))}
</InfiniteScroll>
) : (
<div className="mt-2 flex items-center justify-center text-2xl font-bold text-gray-500">
No Notes Found
</div>
)}
</div>
);
};

export default DoctorNote;
87 changes: 87 additions & 0 deletions src/Components/Facility/PatientConsultationNotesList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { useEffect, useState } from "react";
import { RESULTS_PER_PAGE_LIMIT } from "../../Common/constants";
import CircularProgress from "../Common/components/CircularProgress";
import routes from "../../Redux/api";
import { PatientNoteStateType } from "./models";
import useSlug from "../../Common/hooks/useSlug";
import DoctorNote from "./DoctorNote";
import request from "../../Utils/request/request";

interface PatientNotesProps {
state: PatientNoteStateType;
setState: any;
patientId: string;
facilityId: string;
reload?: boolean;
setReload?: any;
}

const pageSize = RESULTS_PER_PAGE_LIMIT;

const PatientConsultationNotesList = (props: PatientNotesProps) => {
const { state, setState, reload, setReload } = props;
const consultationId = useSlug("consultation") ?? "";

const [isLoading, setIsLoading] = useState(true);

const fetchNotes = async () => {
setIsLoading(true);
const { data }: any = await request(routes.getPatientNotes, {
pathParams: {
patientId: props.patientId,
},
query: {
consultation: consultationId,
offset: (state.cPage - 1) * RESULTS_PER_PAGE_LIMIT,
},
});

if (state.cPage === 1) {
setState((prevState: any) => ({
...prevState,
notes: data.results,
totalPages: Math.ceil(data.count / pageSize),
}));
} else {
setState((prevState: any) => ({
...prevState,
notes: [...prevState.notes, ...data.results],
totalPages: Math.ceil(data.count / pageSize),
}));
}
setIsLoading(false);
setReload(false);
};

useEffect(() => {
if (reload) {
fetchNotes();
}
}, [reload]);

useEffect(() => {
setReload(true);
}, []);

const handleNext = () => {
if (state.cPage < state.totalPages) {
setState((prevState: any) => ({
...prevState,
cPage: prevState.cPage + 1,
}));
setReload(true);
}
};

if (isLoading && !state.notes.length) {
return (
<div className=" flex h-[400px] w-full items-center justify-center bg-white">
<CircularProgress />
</div>
);
}

return <DoctorNote state={state} handleNext={handleNext} />;
};

export default PatientConsultationNotesList;
Loading

0 comments on commit 23af9e0

Please sign in to comment.