-
Notifications
You must be signed in to change notification settings - Fork 486
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Consultation Specific route for Doctor Notes (#6851)
* 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
1 parent
83c4524
commit 23af9e0
Showing
10 changed files
with
388 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
src/Components/Facility/ConsultationDoctorNotes/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
Oops, something went wrong.