From f804e6d3d01341054a822d673fbbb65be6adee4d Mon Sep 17 00:00:00 2001 From: Bhavik Agarwal <73033511+Bhavik-ag@users.noreply.github.com> Date: Thu, 23 Nov 2023 08:35:27 +0530 Subject: [PATCH] Redesign Doctor Notes (Review, QA, Testing) (#6224) * feat: add patient notes pop-up on consultation page * Migrate form elements to CAREUI * made patient notes popup responsive * feat: updated ui of patient notes dedicated page * resolved merge conflicts * fix merge develop * added doctor location * used Page component in PatientNotes page * Apply suggestions from code review * added close button * Apply suggestions from code review * enchance doctor notes ux * Merge branch 'develop' into doctor-notes-redesign * replace usages of moment with dayjs * Added user role in brackets * added message listener for patient notes * added border for notes by remote specialist * added notification on patient note creation * Update src/Components/Facility/PatientNoteCard.tsx Co-authored-by: Rithvik Nishad * added types for notes object * use existing types of patient notes model * link system notification to notes page * Fixes for real time webpush messages * Fixes for notes popover * Update service-worker.ts * lint --------- Co-authored-by: Rithvik Nishad Co-authored-by: Rithvik Nishad Co-authored-by: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> --- package-lock.json | 20 ++ package.json | 1 + src/CAREUI/icons/UniconPaths.json | 12 +- src/Common/constants.tsx | 22 ++ .../Facility/ConsultationDetails/index.tsx | 15 +- src/Components/Facility/PatientNoteCard.tsx | 37 +++ src/Components/Facility/PatientNotesList.tsx | 127 ++++++++++ .../Facility/PatientNotesSlideover.tsx | 157 ++++++++++++ src/Components/Facility/models.tsx | 41 +++ .../Notifications/NotificationsList.tsx | 2 + .../Notifications/ShowPushNotification.tsx | 2 + src/Components/Patient/PatientNotes.tsx | 238 ++++++------------ src/Locale/en/Consultation.json | 2 +- src/service-worker.ts | 6 +- 14 files changed, 505 insertions(+), 177 deletions(-) create mode 100644 src/Components/Facility/PatientNoteCard.tsx create mode 100644 src/Components/Facility/PatientNotesList.tsx create mode 100644 src/Components/Facility/PatientNotesSlideover.tsx diff --git a/package-lock.json b/package-lock.json index d65f617ec05..ebb35bc465c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "react-dom": "18.2.0", "react-google-recaptcha": "^3.1.0", "react-i18next": "^13.0.1", + "react-infinite-scroll-component": "^6.1.0", "react-markdown": "^8.0.7", "react-player": "^2.13.0", "react-qr-reader": "^2.2.1", @@ -19399,6 +19400,17 @@ } } }, + "node_modules/react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "dependencies": { + "throttle-debounce": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, "node_modules/react-inspector": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", @@ -21527,6 +21539,14 @@ "node": ">=0.8" } }, + "node_modules/throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", diff --git a/package.json b/package.json index ca3f6920a12..cbe2267c40d 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "react-dom": "18.2.0", "react-google-recaptcha": "^3.1.0", "react-i18next": "^13.0.1", + "react-infinite-scroll-component": "^6.1.0", "react-markdown": "^8.0.7", "react-player": "^2.13.0", "react-qr-reader": "^2.2.1", diff --git a/src/CAREUI/icons/UniconPaths.json b/src/CAREUI/icons/UniconPaths.json index 9a2673695aa..c2ed7ecf467 100644 --- a/src/CAREUI/icons/UniconPaths.json +++ b/src/CAREUI/icons/UniconPaths.json @@ -3107,10 +3107,7 @@ 24, "M19,2H5A3,3,0,0,0,2,5V19a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V5A3,3,0,0,0,19,2Zm1,17a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V5A1,1,0,0,1,5,4H19a1,1,0,0,1,1,1Zm-4-8H8a1,1,0,0,0,0,2h8a1,1,0,0,0,0-2Z" ], - "l-minus": [ - 24, - "M19,11H5a1,1,0,0,0,0,2H19a1,1,0,0,0,0-2Z" - ], + "l-minus": [24, "M19,11H5a1,1,0,0,0,0,2H19a1,1,0,0,0,0-2Z"], "l-missed-call": [ 24, "M6,7.49a1,1,0,0,0,1-1V5.9L9.88,8.78a3,3,0,0,0,4.24,0l4.59-4.59a1,1,0,0,0,0-1.41,1,1,0,0,0-1.42,0L12.71,7.36a1,1,0,0,1-1.42,0L8.41,4.49H9a1,1,0,0,0,0-2H6a1,1,0,0,0-.92.61A1.09,1.09,0,0,0,5,3.49v3A1,1,0,0,0,6,7.49Zm15.94,7.36a16.27,16.27,0,0,0-19.88,0,2.69,2.69,0,0,0-1,2,2.66,2.66,0,0,0,.78,2.07L3.6,20.72A2.68,2.68,0,0,0,7.06,21l.47-.32a8.13,8.13,0,0,1,1-.55,1.85,1.85,0,0,0,1-2.3l-.09-.24a10.49,10.49,0,0,1,5.22,0l-.09.24a1.85,1.85,0,0,0,1,2.3,8.13,8.13,0,0,1,1,.55l.47.32a2.58,2.58,0,0,0,1.54.5,2.72,2.72,0,0,0,1.92-.79l1.81-1.82A2.66,2.66,0,0,0,23,16.83,2.69,2.69,0,0,0,21.94,14.85ZM20.8,17.49,19,19.3a.68.68,0,0,1-.86.1c-.19-.14-.38-.27-.59-.4a11.65,11.65,0,0,0-1.09-.61l.4-1.09a1,1,0,0,0-.6-1.28,12.42,12.42,0,0,0-8.5,0,1,1,0,0,0-.6,1.28l.4,1.1a9.8,9.8,0,0,0-1.1.6l-.58.4A.66.66,0,0,1,5,19.3L3.2,17.49A.67.67,0,0,1,3,17a.76.76,0,0,1,.28-.53,14.29,14.29,0,0,1,17.44,0A.76.76,0,0,1,21,17,.67.67,0,0,1,20.8,17.49Z" @@ -4295,10 +4292,7 @@ 24, "M15,13H9a1,1,0,0,0,0,2h2v2a1,1,0,0,0,2,0V15h2a1,1,0,0,0,0-2Zm2-7H7A1,1,0,0,0,7,8h4v2a1,1,0,0,0,2,0V8h4a1,1,0,0,0,0-2Z" ], - "l-text": [ - 24, - "M17,6H7A1,1,0,0,0,7,8h4v9a1,1,0,0,0,2,0V8h4a1,1,0,0,0,0-2Z" - ], + "l-text": [24, "M17,6H7A1,1,0,0,0,7,8h4v9a1,1,0,0,0,2,0V8h4a1,1,0,0,0,0-2Z"], "l-th-large": [ 24, "M20,3H4A1,1,0,0,0,3,4V20a1,1,0,0,0,1,1H20a1,1,0,0,0,1-1V4A1,1,0,0,0,20,3ZM11,19H5V13h6Zm0-8H5V5h6Zm8,8H13V13h6Zm0-8H13V5h6Z" @@ -4841,4 +4835,4 @@ 256, "M204.73 51.85A108.07 108.07 0 0 0 20 128v56a28 28 0 0 0 28 28h16a28 28 0 0 0 28-28v-40a28 28 0 0 0-28-28H44.84A84.05 84.05 0 0 1 128 44h.64a83.7 83.7 0 0 1 82.52 72H192a28 28 0 0 0-28 28v40a28 28 0 0 0 28 28h19.6a20 20 0 0 1-19.6 16h-56a12 12 0 0 0 0 24h56a44.05 44.05 0 0 0 44-44v-80a107.34 107.34 0 0 0-31.27-76.15ZM64 140a4 4 0 0 1 4 4v40a4 4 0 0 1-4 4H48a4 4 0 0 1-4-4v-44Zm124 44v-40a4 4 0 0 1 4-4h20v48h-20a4 4 0 0 1-4-4Z" ] -} \ No newline at end of file +} diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index 21dbd6763b8..065e7ccd759 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -602,6 +602,11 @@ export const NOTIFICATION_EVENTS = [ text: "Shifting Updated", icon: "fa-solid fa-truck-medical", }, + { + id: "PATIENT_NOTE_ADDED", + text: "Patient Note Added", + icon: "fa-solid fa-message", + }, ]; export const BREATHLESSNESS_LEVEL = [ @@ -1015,6 +1020,23 @@ export const XLSXAssetImportSchema = { }, }; +export const USER_TYPES_MAP = { + Pharmacist: "Pharmacist", + Volunteer: "Volunteer", + StaffReadOnly: "Staff", + Staff: "Staff", + Doctor: "Doctor", + WardAdmin: "Ward Admin", + LocalBodyAdmin: "Local Body Admin", + DistrictLabAdmin: "District Lab Admin", + DistrictReadOnlyAdmin: "District Admin", + DistrictAdmin: "District Admin", + StateLabAdmin: "State Lab Admin", + StateReadOnlyAdmin: "State Admin", + StateAdmin: "State Admin", + RemoteSpecialist: "Remote Specialist", +}; + export const AREACODES: Record = { CA: [ "403", diff --git a/src/Components/Facility/ConsultationDetails/index.tsx b/src/Components/Facility/ConsultationDetails/index.tsx index 991dbd69539..7e7664707eb 100644 --- a/src/Components/Facility/ConsultationDetails/index.tsx +++ b/src/Components/Facility/ConsultationDetails/index.tsx @@ -23,9 +23,8 @@ import PatientInfoCard from "../../Patient/PatientInfoCard"; import { PatientModel } from "../../Patient/models"; import { formatDateTime, relativeTime } from "../../../Utils/utils"; -import { navigate } from "raviger"; +import { navigate, useQueryParams } from "raviger"; import { useDispatch } from "react-redux"; -import { useQueryParams } from "raviger"; import { useTranslation } from "react-i18next"; import { triggerGoal } from "../../../Integrations/Plausible"; import useAuthUser from "../../../Common/hooks/useAuthUser"; @@ -42,6 +41,7 @@ import { ConsultationPressureSoreTab } from "./ConsultationPressureSoreTab"; import { ConsultationDialysisTab } from "./ConsultationDialysisTab"; import { ConsultationNeurologicalMonitoringTab } from "./ConsultationNeurologicalMonitoringTab"; import { ConsultationNutritionTab } from "./ConsultationNutritionTab"; +import PatientNotesSlideover from "../PatientNotesSlideover"; import LegacyDiagnosesList from "../../Diagnosis/LegacyDiagnosesList"; const Loading = lazy(() => import("../../Common/Loading")); @@ -105,6 +105,7 @@ export const ConsultationDetails = (props: any) => { return "None"; } }; + const [showPatientNotesPopup, setShowPatientNotesPopup] = useState(false); const authUser = useAuthUser(); @@ -370,7 +371,7 @@ export const ConsultationDetails = (props: any) => { setShowPatientNotesPopup(true)} className="btn btn-primary m-1 w-full hover:text-white" > Doctor's Notes @@ -540,6 +541,14 @@ export const ConsultationDetails = (props: any) => { show={showDoctors} setShow={setShowDoctors} /> + + {showPatientNotesPopup && ( + + )} ); }; diff --git a/src/Components/Facility/PatientNoteCard.tsx b/src/Components/Facility/PatientNoteCard.tsx new file mode 100644 index 00000000000..2f07702504a --- /dev/null +++ b/src/Components/Facility/PatientNoteCard.tsx @@ -0,0 +1,37 @@ +import { relativeDate, formatDateTime, classNames } from "../../Utils/utils"; +import { USER_TYPES_MAP } from "../../Common/constants"; +import { PatientNotesModel } from "./models"; + +const PatientNoteCard = ({ note }: { note: PatientNotesModel }) => { + return ( +
+
+ + {note.created_by_object?.first_name || "Unknown"}{" "} + {note.created_by_object?.last_name} + + {note.user_type && ( + + {`(${USER_TYPES_MAP[note.user_type]})`} + + )} +
+ {note.note} +
+
+ + {formatDateTime(note.created_date)} + + {relativeDate(note.created_date)} +
+
+
+ ); +}; + +export default PatientNoteCard; diff --git a/src/Components/Facility/PatientNotesList.tsx b/src/Components/Facility/PatientNotesList.tsx new file mode 100644 index 00000000000..330bca4b06d --- /dev/null +++ b/src/Components/Facility/PatientNotesList.tsx @@ -0,0 +1,127 @@ +import { useCallback, useState, useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { statusType, useAbortableEffect } from "../../Common/utils"; +import { getPatientNotes } from "../../Redux/actions"; +import { RESULTS_PER_PAGE_LIMIT } from "../../Common/constants"; +import CircularProgress from "../Common/components/CircularProgress"; +import PatientNoteCard from "./PatientNoteCard"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { NoteType } from "./PatientNoteCard"; + +interface PatientNotesProps { + patientId: any; + facilityId: any; + reload?: boolean; + setReload?: any; +} + +interface StateType { + notes: NoteType[]; + cPage: number; + totalPages: number; +} + +const pageSize = RESULTS_PER_PAGE_LIMIT; + +const PatientNotesList = (props: PatientNotesProps) => { + const { reload, setReload } = props; + + const dispatch: any = useDispatch(); + const initialData: StateType = { notes: [], cPage: 1, totalPages: 1 }; + const [state, setState] = useState(initialData); + const [isLoading, setIsLoading] = useState(true); + + const fetchData = useCallback( + async (page = 1, status: statusType = { aborted: false }) => { + setIsLoading(true); + const res = await dispatch( + getPatientNotes(props.patientId, pageSize, (page - 1) * pageSize) + ); + if (!status.aborted) { + if (res && res.data) { + if (page === 1) { + setState({ + notes: res.data?.results, + cPage: page, + totalPages: Math.ceil(res.data.count / pageSize), + }); + } else { + setState((prevState: any) => ({ + ...prevState, + notes: [...prevState.notes, ...res.data.results], + cPage: page, + totalPages: Math.ceil(res.data.count / pageSize), + })); + } + } + setIsLoading(false); + } + }, + [props.patientId, dispatch] + ); + + useEffect(() => { + if (reload) { + fetchData(1); + setReload(false); + } + }, [reload]); + + useAbortableEffect( + (status: statusType) => { + fetchData(1, status); + }, + [fetchData] + ); + + const handleNext = () => { + if (state.cPage < state.totalPages) { + fetchData(state.cPage + 1); + setState((prevState: any) => ({ + ...prevState, + cPage: prevState.cPage + 1, + })); + } + }; + + if (isLoading && !state.notes.length) { + return ( +
+ +
+ ); + } + + return ( +
+ {state.notes.length ? ( + + +
+ } + className="flex h-full flex-col-reverse p-2" + inverse={true} + dataLength={state.notes.length} + scrollableTarget="patient-notes-list" + > + {state.notes.map((note: any) => ( + + ))} + + ) : ( +
+ No Notes Found +
+ )} + + ); +}; + +export default PatientNotesList; diff --git a/src/Components/Facility/PatientNotesSlideover.tsx b/src/Components/Facility/PatientNotesSlideover.tsx new file mode 100644 index 00000000000..a04fac93526 --- /dev/null +++ b/src/Components/Facility/PatientNotesSlideover.tsx @@ -0,0 +1,157 @@ +import { useState, useEffect, Dispatch, SetStateAction } from "react"; +import { getPatient, addPatientNote } from "../../Redux/actions"; +import * as Notification from "../../Utils/Notifications.js"; +import { useDispatch } from "react-redux"; +import PatientNotesList from "./PatientNotesList"; +import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import { classNames } from "../../Utils/utils"; +import TextFormField from "../Form/FormFields/TextFormField"; +import ButtonV2 from "../Common/components/ButtonV2"; +import { make as Link } from "../Common/components/Link.bs"; +import { useMessageListener } from "../../Common/hooks/useMessageListener"; + +interface PatientNotesProps { + patientId: string; + facilityId: string; + setShowPatientNotesPopup: Dispatch>; +} + +export default function PatientNotesSlideover(props: PatientNotesProps) { + const [show, setShow] = useState(false); + const [patientActive, setPatientActive] = useState(true); + const [noteField, setNoteField] = useState(""); + const [reload, setReload] = useState(false); + + const dispatch = useDispatch(); + + const { facilityId, patientId, setShowPatientNotesPopup } = props; + + const onAddNote = () => { + const payload = { + note: noteField, + }; + if (!/\S+/.test(noteField)) { + Notification.Error({ + msg: "Note Should Contain At Least 1 Character", + }); + return; + } + dispatch(addPatientNote(patientId, payload)).then(() => { + Notification.Success({ msg: "Note added successfully" }); + setNoteField(""); + setReload(!reload); + }); + }; + + 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); + } + }); + + useEffect(() => { + async function fetchPatientName() { + if (patientId) { + const res = await dispatch(getPatient({ id: patientId })); + if (res.data) { + setPatientActive(res.data.is_active); + } + } + } + fetchPatientName(); + }, [dispatch, patientId]); + + const notesActionIcons = ( +
+ {show && ( + + + + )} +
setShow(!show)} + > + +
+
setShowPatientNotesPopup(false)} + > + +
+
+ ); + + return ( +
+ {!show ? ( +
setShow(!show)} + > + {"Doctor's Notes"} + {notesActionIcons} +
+ ) : ( +
+ {/* Doctor Notes Header */} +
+ {"Doctor's Notes"} + {notesActionIcons} +
+ {/* Doctor Notes Body */} + +
+ setNoteField(e.value)} + className="grow" + type="text" + errorClassName="hidden" + placeholder="Type your Note" + disabled={!patientActive} + /> + + + +
+
+ )} +
+ ); +} diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index 1ed1cee813c..8dcc5f71e0d 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -447,3 +447,44 @@ export type ICD11DiagnosisModel = { id: string; label: string; }; + +// Patient Notes Model +export interface BaseFacilityModel { + id: string; + name: string; + local_body: number; + district: number; + state: number; + ward_object: WardModel; + local_body_object?: LocalBodyModel; + district_object?: DistrictModel; + state_object?: StateModel; + facility_type: FacilityType; + read_cover_image_url: any; + features: any[]; + patient_count: number; + bed_count: number; +} + +export interface FacilityType { + id: number; + name: string; +} + +export interface BaseUserModel { + id: number; + first_name: string; + username: string; + email: string; + last_name: string; + user_type: string; + last_login: string; +} + +export interface PatientNotesModel { + note: string; + facility: BaseFacilityModel; + created_by_object: BaseUserModel; + user_type?: string; + created_date: string; +} diff --git a/src/Components/Notifications/NotificationsList.tsx b/src/Components/Notifications/NotificationsList.tsx index 864208a432f..ae3e3f94ac6 100644 --- a/src/Components/Notifications/NotificationsList.tsx +++ b/src/Components/Notifications/NotificationsList.tsx @@ -62,6 +62,8 @@ const NotificationTile = ({ return `/facility/${data.facility}/patient/${data.patient}/consultation/${data.consultation}/daily-rounds/${data.daily_round}`; case "INVESTIGATION_SESSION_CREATED": return `/facility/${data.facility}/patient/${data.patient}/consultation/${data.consultation}/investigation/${data.session}`; + case "PATIENT_NOTE_ADDED": + return `/facility/${data.facility}/patient/${data.patient}/notes`; case "MESSAGE": return "/notice_board/"; default: diff --git a/src/Components/Notifications/ShowPushNotification.tsx b/src/Components/Notifications/ShowPushNotification.tsx index 35e9ecd7e70..2d2faa5ff5f 100644 --- a/src/Components/Notifications/ShowPushNotification.tsx +++ b/src/Components/Notifications/ShowPushNotification.tsx @@ -29,6 +29,8 @@ export default function ShowPushNotification({ id }: DetailRoute) { return `/facility/${caused_objects?.facility}/patient/${caused_objects?.patient}/consultation/${caused_objects?.consultation}/daily-rounds/${caused_objects?.daily_round}`; case "INVESTIGATION_SESSION_CREATED": return `/facility/${caused_objects?.facility}/patient/${caused_objects?.patient}/consultation/${caused_objects?.consultation}/investigation/${caused_objects?.session}`; + case "PATIENT_NOTE_ADDED": + return `/facility/${caused_objects.facility}/patient/${caused_objects.patient}/notes`; case "MESSAGE": return "/notice_board/"; default: diff --git a/src/Components/Patient/PatientNotes.tsx b/src/Components/Patient/PatientNotes.tsx index c105619678b..333c25eef4a 100644 --- a/src/Components/Patient/PatientNotes.tsx +++ b/src/Components/Patient/PatientNotes.tsx @@ -1,201 +1,117 @@ -import { useCallback, useState, useEffect } from "react"; +import { useState, useEffect } from "react"; import { useDispatch } from "react-redux"; -import { statusType, useAbortableEffect } from "../../Common/utils"; -import { - getPatientNotes, - addPatientNote, - getPatient, -} from "../../Redux/actions"; +import { addPatientNote, getPatient } from "../../Redux/actions"; import * as Notification from "../../Utils/Notifications.js"; -import PageTitle from "../Common/PageTitle"; -import Pagination from "../Common/Pagination"; -import { navigate } from "raviger"; -import { RESULTS_PER_PAGE_LIMIT } from "../../Common/constants"; -import Loading from "../Common/Loading"; -import { formatDateTime } from "../../Utils/utils"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import TextFormField from "../Form/FormFields/TextFormField"; import ButtonV2 from "../Common/components/ButtonV2"; import { NonReadOnlyUsers } from "../../Utils/AuthorizeFor"; +import PatientNotesList from "../Facility/PatientNotesList"; +import Page from "../Common/components/Page"; +import { useMessageListener } from "../../Common/hooks/useMessageListener"; interface PatientNotesProps { patientId: any; facilityId: any; } -const pageSize = RESULTS_PER_PAGE_LIMIT; - const PatientNotes = (props: PatientNotesProps) => { const { patientId, facilityId } = props; - const dispatch: any = useDispatch(); - const initialData: any = { notes: [], cPage: 1, count: 1 }; - const [state, setState] = useState(initialData); + const [patientActive, setPatientActive] = useState(true); const [noteField, setNoteField] = useState(""); - const [isLoading, setIsLoading] = useState(true); + const [reload, setReload] = useState(false); const [facilityName, setFacilityName] = useState(""); const [patientName, setPatientName] = useState(""); - const [patientActive, setPatientActive] = useState(true); - const fetchData = useCallback( - async (page = 1, status: statusType = { aborted: false }) => { - setIsLoading(true); - const res = await dispatch( - getPatientNotes(props.patientId, pageSize, (page - 1) * pageSize) - ); - if (!status.aborted) { - if (res && res.data) { - setState({ - ...state, - count: res.data?.count, - notes: res.data?.results, - cPage: page, - }); - } - setIsLoading(false); - } - }, - [props.patientId, dispatch] - ); + const dispatch = useDispatch(); - useAbortableEffect( - (status: statusType) => { - fetchData(1, status); - }, - [fetchData] - ); + const onAddNote = () => { + const payload = { + note: noteField, + }; + if (!/\S+/.test(noteField)) { + Notification.Error({ + msg: "Note Should Contain At Least 1 Character", + }); + return; + } + dispatch(addPatientNote(patientId, payload)).then(() => { + Notification.Success({ msg: "Note added successfully" }); + setNoteField(""); + setReload(!reload); + }); + }; useEffect(() => { async function fetchPatientName() { if (patientId) { const res = await dispatch(getPatient({ id: patientId })); if (res.data) { + setPatientActive(res.data.is_active); setPatientName(res.data.name); setFacilityName(res.data.facility_object.name); - setPatientActive(res.data.is_active); } - } else { - setPatientName(""); - setFacilityName(""); } } fetchPatientName(); }, [dispatch, patientId]); - function handlePagination(page: number) { - fetchData(page); - } - - const onAddNote = () => { - const payload = { - note: noteField, - }; - if (!/\S+/.test(noteField)) { - Notification.Error({ - msg: "Note Should Contain At Least 1 Character", - }); - return; + 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); } - dispatch(addPatientNote(props.patientId, payload)).then(() => { - Notification.Success({ msg: "Note added successfully" }); - setNoteField(""); - fetchData(); - }); - }; + }); return ( -
- -

Add new notes

-