From 430d8ec20c8da4c44c46f512c79bce0554e560b0 Mon Sep 17 00:00:00 2001 From: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> Date: Tue, 26 Dec 2023 14:47:33 +0530 Subject: [PATCH 1/6] Add edit option for doctor notes --- .../ConsultationDoctorNotes/index.tsx | 4 +- src/Components/Facility/DoctorNote.tsx | 10 +- .../Facility/PatientConsultationNotesList.tsx | 8 +- src/Components/Facility/PatientNoteCard.tsx | 218 +++++++++++++++--- src/Components/Facility/PatientNotesList.tsx | 4 +- .../Facility/PatientNotesSlideover.tsx | 9 +- src/Components/Facility/models.tsx | 11 + .../Form/FormFields/TextFormField.tsx | 2 + src/Redux/api.tsx | 5 + src/Utils/utils.ts | 4 +- 10 files changed, 236 insertions(+), 39 deletions(-) diff --git a/src/Components/Facility/ConsultationDoctorNotes/index.tsx b/src/Components/Facility/ConsultationDoctorNotes/index.tsx index dd96ef9af1e..3853dc5decc 100644 --- a/src/Components/Facility/ConsultationDoctorNotes/index.tsx +++ b/src/Components/Facility/ConsultationDoctorNotes/index.tsx @@ -31,6 +31,8 @@ const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => { notes: [], cPage: 1, totalPages: 1, + facilityId: facilityId, + patientId: patientId, }; const [state, setState] = useState(initialData); @@ -98,8 +100,6 @@ const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => { diff --git a/src/Components/Facility/DoctorNote.tsx b/src/Components/Facility/DoctorNote.tsx index 85703a1e3d8..5777f9e3fb1 100644 --- a/src/Components/Facility/DoctorNote.tsx +++ b/src/Components/Facility/DoctorNote.tsx @@ -5,11 +5,12 @@ import { PatientNoteStateType } from "./models"; interface DoctorNoteProps { state: PatientNoteStateType; + setReload: any; handleNext: () => void; } const DoctorNote = (props: DoctorNoteProps) => { - const { state, handleNext } = props; + const { state, handleNext, setReload } = props; return (
{ scrollableTarget="patient-notes-list" > {state.notes.map((note: any) => ( - + ))} ) : ( diff --git a/src/Components/Facility/PatientConsultationNotesList.tsx b/src/Components/Facility/PatientConsultationNotesList.tsx index f38de51110b..86aa99abc3d 100644 --- a/src/Components/Facility/PatientConsultationNotesList.tsx +++ b/src/Components/Facility/PatientConsultationNotesList.tsx @@ -10,8 +10,6 @@ import request from "../../Utils/request/request"; interface PatientNotesProps { state: PatientNoteStateType; setState: any; - patientId: string; - facilityId: string; reload?: boolean; setReload?: any; } @@ -28,7 +26,7 @@ const PatientConsultationNotesList = (props: PatientNotesProps) => { setIsLoading(true); const { data }: any = await request(routes.getPatientNotes, { pathParams: { - patientId: props.patientId, + patientId: props.state.patientId, }, query: { consultation: consultationId, @@ -81,7 +79,9 @@ const PatientConsultationNotesList = (props: PatientNotesProps) => { ); } - return ; + return ( + + ); }; export default PatientConsultationNotesList; diff --git a/src/Components/Facility/PatientNoteCard.tsx b/src/Components/Facility/PatientNoteCard.tsx index 2f07702504a..88c64914321 100644 --- a/src/Components/Facility/PatientNoteCard.tsx +++ b/src/Components/Facility/PatientNoteCard.tsx @@ -1,36 +1,202 @@ import { relativeDate, formatDateTime, classNames } from "../../Utils/utils"; import { USER_TYPES_MAP } from "../../Common/constants"; -import { PatientNotesModel } from "./models"; +import { PatientNoteStateType, PatientNotesModel } from "./models"; +import ButtonV2 from "../Common/components/ButtonV2"; +import CareIcon from "../../CAREUI/icons/CareIcon"; +import { useState } from "react"; +import { Error, Success } from "../../Utils/Notifications"; +import request from "../../Utils/request/request"; +import routes from "../../Redux/api"; +import DialogModal from "../Common/Dialog"; +import { t } from "i18next"; + +const PatientNoteCard = ({ + state, + note, + setReload, +}: { + state: PatientNoteStateType; + note: PatientNotesModel; + setReload: any; +}) => { + const [isEditing, setIsEditing] = useState(false); + const [noteField, setNoteField] = useState(note.note); + const [showEditHistory, setShowEditHistory] = useState(false); + + const onUpdateNote = async () => { + if (noteField === note.note) { + setIsEditing(false); + return; + } + const payload = { + note: noteField, + }; + if (!/\S+/.test(noteField)) { + Error({ + msg: "Note Should Contain At Least 1 Character", + }); + return; + } + + const { res } = await request(routes.updatePatientNote, { + pathParams: { patientId: state.patientId, noteId: note.id }, + body: payload, + }); + if (res?.status === 200) { + Success({ msg: "Note updated successfully" }); + setIsEditing(false); + setReload(true); + } + }; -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)} + > +
+
+
+ + {note.created_by_object?.first_name || "Unknown"}{" "} + {note.created_by_object?.last_name} + + {note.user_type && ( + + {`(${USER_TYPES_MAP[note.user_type]})`} + + )} +
+
+
+ + {formatDateTime(note.created_date)} + + Created {relativeDate(note.created_date, true)} +
+
+ {note.edits.length > 1 && ( +
+
{ + setShowEditHistory(true); + }} + > +
+ + {formatDateTime(note.edits[0].edited_on)} + + Edited {relativeDate(note.edits[0].edited_on, true)} +
+ +
+
+ )} +
+ + { + if (!isEditing) setIsEditing(true); + }} + > + {isEditing ? ( + + ) : ( + + )} +
+ { +
+ {isEditing ? ( + + ) : ( +
{noteField}
+ )} +
+ }
-
+ {showEditHistory && ( + setShowEditHistory(false)} + title={t("edit_history")} + > +
+
+

+ Edit History for note + {note.id} +

+
+
+ {note.edits.map((edit, index) => { + const isLast = index === note.edits.length - 1; + return ( +
+
+
+

+ {isLast ? "Created" : "Edited"} On +

+

+ {formatDateTime(edit.edited_on)} +

+
+
+

+ {isLast ? "Created" : "Edited"} By +

+

+ {edit.edited_by.username} +

+
+
+
+

Note

+

{edit.note}

+
+
+ ); + })} +
+
+ { + setShowEditHistory(false); + }} + > + {t("close")} + +
+
+
+ )} + ); }; diff --git a/src/Components/Facility/PatientNotesList.tsx b/src/Components/Facility/PatientNotesList.tsx index 96f9dcad871..a36762072b9 100644 --- a/src/Components/Facility/PatientNotesList.tsx +++ b/src/Components/Facility/PatientNotesList.tsx @@ -74,7 +74,9 @@ const PatientNotesList = (props: PatientNotesProps) => { ); } - return ; + return ( + + ); }; export default PatientNotesList; diff --git a/src/Components/Facility/PatientNotesSlideover.tsx b/src/Components/Facility/PatientNotesSlideover.tsx index 8b08d9767db..9b2674ec84a 100644 --- a/src/Components/Facility/PatientNotesSlideover.tsx +++ b/src/Components/Facility/PatientNotesSlideover.tsx @@ -29,6 +29,8 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { notes: [], cPage: 1, totalPages: 1, + patientId: props.patientId, + facilityId: props.facilityId, }; const [state, setState] = useState(initialData); @@ -141,8 +143,6 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { @@ -157,6 +157,11 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { errorClassName="hidden" placeholder="Type your Note" disabled={!patientActive} + onKeyDown={(e) => { + if (e.key === "Enter") { + onAddNote(); + } + }} /> & { leadingPadding?: string | undefined; min?: string | number; max?: string | number; + onKeyDown?: (event: React.KeyboardEvent) => void; onFocus?: (event: React.FocusEvent) => void; onBlur?: (event: React.FocusEvent) => void; }; @@ -62,6 +63,7 @@ const TextFormField = forwardRef((props: TextFormFieldProps, ref) => { onFocus={props.onFocus} onBlur={props.onBlur} onChange={(e) => field.handleChange(e.target.value)} + onKeyDown={props.onKeyDown} /> ); diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index 9634036e6c4..09c682261e5 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -624,6 +624,11 @@ const routes = { method: "POST", TRes: Type(), }, + updatePatientNote: { + path: "/api/v1/patient/{patientId}/notes/{noteId}/", + method: "PUT", + TRes: Type(), + }, sampleTestList: { path: "/api/v1/patient/{patientId}/test_sample/", }, diff --git a/src/Utils/utils.ts b/src/Utils/utils.ts index df6bd46d131..23f07fae5a0 100644 --- a/src/Utils/utils.ts +++ b/src/Utils/utils.ts @@ -99,9 +99,9 @@ export const formatDate = (date: DateLike, format = DATE_FORMAT) => export const formatTime = (date: DateLike, format = TIME_FORMAT) => formatDateTime(date, format); -export const relativeDate = (date: DateLike) => { +export const relativeDate = (date: DateLike, withoutSuffix = false) => { const obj = dayjs(date); - return `${obj.fromNow()} at ${obj.format(TIME_FORMAT)}`; + return `${obj.fromNow(withoutSuffix)} at ${obj.format(TIME_FORMAT)}`; }; export const formatName = (user: { first_name: string; last_name: string }) => { From 1220789bcd261b5445863fafdbfe19a8f9245e24 Mon Sep 17 00:00:00 2001 From: Ashesh <3626859+Ashesh3@users.noreply.github.com> Date: Wed, 27 Dec 2023 14:17:43 +0530 Subject: [PATCH 2/6] use edited_date --- src/Components/Facility/PatientNoteCard.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Facility/PatientNoteCard.tsx b/src/Components/Facility/PatientNoteCard.tsx index 88c64914321..02a1d7df845 100644 --- a/src/Components/Facility/PatientNoteCard.tsx +++ b/src/Components/Facility/PatientNoteCard.tsx @@ -89,9 +89,9 @@ const PatientNoteCard = ({ >
- {formatDateTime(note.edits[0].edited_on)} + {formatDateTime(note.edits[0].edited_date)} - Edited {relativeDate(note.edits[0].edited_on, true)} + Edited {relativeDate(note.edits[0].edited_date, true)}

- {formatDateTime(edit.edited_on)} + {formatDateTime(edit.edited_date)}

From d80144a2c255ff252e5561c7aeba4cd512db856e Mon Sep 17 00:00:00 2001 From: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> Date: Thu, 18 Jan 2024 13:16:45 +0530 Subject: [PATCH 3/6] Update PatientNoteCard component and models --- src/Components/Facility/PatientNoteCard.tsx | 118 ++++++++++++-------- src/Components/Facility/models.tsx | 5 +- src/Redux/api.tsx | 6 + 3 files changed, 80 insertions(+), 49 deletions(-) diff --git a/src/Components/Facility/PatientNoteCard.tsx b/src/Components/Facility/PatientNoteCard.tsx index 02a1d7df845..8c53a5701d4 100644 --- a/src/Components/Facility/PatientNoteCard.tsx +++ b/src/Components/Facility/PatientNoteCard.tsx @@ -1,6 +1,10 @@ import { relativeDate, formatDateTime, classNames } from "../../Utils/utils"; import { USER_TYPES_MAP } from "../../Common/constants"; -import { PatientNoteStateType, PatientNotesModel } from "./models"; +import { + PatientNoteStateType, + PatientNotesEditModel, + PatientNotesModel, +} from "./models"; import ButtonV2 from "../Common/components/ButtonV2"; import CareIcon from "../../CAREUI/icons/CareIcon"; import { useState } from "react"; @@ -9,6 +13,9 @@ import request from "../../Utils/request/request"; import routes from "../../Redux/api"; import DialogModal from "../Common/Dialog"; import { t } from "i18next"; +import dayjs from "dayjs"; +import Spinner from "../Common/Spinner"; +import useAuthUser from "../../Common/hooks/useAuthUser"; const PatientNoteCard = ({ state, @@ -22,6 +29,17 @@ const PatientNoteCard = ({ const [isEditing, setIsEditing] = useState(false); const [noteField, setNoteField] = useState(note.note); const [showEditHistory, setShowEditHistory] = useState(false); + const [editHistory, setEditHistory] = useState([]); + const authUser = useAuthUser(); + + const fetchEditHistory = async () => { + const { res, data } = await request(routes.getPatientNoteEditHistory, { + pathParams: { patientId: state.patientId, noteId: note.id }, + }); + if (res?.status === 200) { + setEditHistory(data?.results ?? []); + } + }; const onUpdateNote = async () => { if (noteField === note.note) { @@ -79,46 +97,55 @@ const PatientNoteCard = ({ Created {relativeDate(note.created_date, true)}
- {note.edits.length > 1 && ( -
-
{ - setShowEditHistory(true); - }} - > -
- - {formatDateTime(note.edits[0].edited_date)} - - Edited {relativeDate(note.edits[0].edited_date, true)} + { + // If last edited date is same as created date, then it is not edited + !dayjs(note.last_edited_date).isSame( + note.created_date, + "second" + ) && ( +
+
{ + fetchEditHistory(); + setShowEditHistory(true); + }} + > +
+ + {formatDateTime(note.last_edited_date)} + + Edited {relativeDate(note.last_edited_date, true)} +
+
-
-
- )} + ) + }
- { - if (!isEditing) setIsEditing(true); - }} - > - {isEditing ? ( - - ) : ( - - )} - + {note.created_by_object.id === authUser.id && ( + { + if (!isEditing) setIsEditing(true); + }} + > + {isEditing ? ( + + ) : ( + + )} + + )}
{
@@ -149,8 +176,13 @@ const PatientNoteCard = ({

- {note.edits.map((edit, index) => { - const isLast = index === note.edits.length - 1; + {editHistory.length === 0 && ( +
+ +
+ )} + {editHistory?.map((edit, index) => { + const isLast = index === editHistory.length - 1; return (
-
-

- {isLast ? "Created" : "Edited"} By -

-

- {edit.edited_by.username} -

-

Note

diff --git a/src/Components/Facility/models.tsx b/src/Components/Facility/models.tsx index b774d13f525..ea33a36fa00 100644 --- a/src/Components/Facility/models.tsx +++ b/src/Components/Facility/models.tsx @@ -490,7 +490,7 @@ export interface BaseUserModel { export interface PatientNotesEditModel { id: string; edited_by: BaseUserModel; - edited_on: string; + edited_date: string; note: string; } @@ -501,7 +501,8 @@ export interface PatientNotesModel { created_by_object: BaseUserModel; user_type?: string; created_date: string; - edits: PatientNotesEditModel[]; + last_edited_by?: BaseUserModel; + last_edited_date?: string; } export interface PatientNoteStateType { diff --git a/src/Redux/api.tsx b/src/Redux/api.tsx index 09c682261e5..f9a31cc4f21 100644 --- a/src/Redux/api.tsx +++ b/src/Redux/api.tsx @@ -46,6 +46,7 @@ import { LocationModel, StateModel, PatientNotesModel, + PatientNotesEditModel, } from "../Components/Facility/models"; import { IDeleteExternalResult, @@ -629,6 +630,11 @@ const routes = { method: "PUT", TRes: Type(), }, + getPatientNoteEditHistory: { + path: "/api/v1/patient/{patientId}/notes/{noteId}/edits/", + method: "GET", + TRes: Type>(), + }, sampleTestList: { path: "/api/v1/patient/{patientId}/test_sample/", }, From c378683c134928138f19671c8aee5cbdfbca74a7 Mon Sep 17 00:00:00 2001 From: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> Date: Thu, 18 Jan 2024 13:35:53 +0530 Subject: [PATCH 4/6] disableEdit for inactive patient --- src/Components/Facility/DoctorNote.tsx | 4 +++- .../Facility/PatientConsultationNotesList.tsx | 10 ++++++++-- src/Components/Facility/PatientNoteCard.tsx | 4 +++- src/Components/Facility/PatientNotesSlideover.tsx | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Components/Facility/DoctorNote.tsx b/src/Components/Facility/DoctorNote.tsx index 5777f9e3fb1..1fe28ba38d0 100644 --- a/src/Components/Facility/DoctorNote.tsx +++ b/src/Components/Facility/DoctorNote.tsx @@ -7,10 +7,11 @@ interface DoctorNoteProps { state: PatientNoteStateType; setReload: any; handleNext: () => void; + disableEdit?: boolean; } const DoctorNote = (props: DoctorNoteProps) => { - const { state, handleNext, setReload } = props; + const { state, handleNext, setReload, disableEdit } = props; return (
{ note={note} key={note.id} setReload={setReload} + disableEdit={disableEdit} /> ))} diff --git a/src/Components/Facility/PatientConsultationNotesList.tsx b/src/Components/Facility/PatientConsultationNotesList.tsx index 86aa99abc3d..2b9df8c3902 100644 --- a/src/Components/Facility/PatientConsultationNotesList.tsx +++ b/src/Components/Facility/PatientConsultationNotesList.tsx @@ -12,12 +12,13 @@ interface PatientNotesProps { setState: any; reload?: boolean; setReload?: any; + disableEdit?: boolean; } const pageSize = RESULTS_PER_PAGE_LIMIT; const PatientConsultationNotesList = (props: PatientNotesProps) => { - const { state, setState, reload, setReload } = props; + const { state, setState, reload, setReload, disableEdit } = props; const consultationId = useSlug("consultation") ?? ""; const [isLoading, setIsLoading] = useState(true); @@ -80,7 +81,12 @@ const PatientConsultationNotesList = (props: PatientNotesProps) => { } return ( - + ); }; diff --git a/src/Components/Facility/PatientNoteCard.tsx b/src/Components/Facility/PatientNoteCard.tsx index 8c53a5701d4..8f98e621573 100644 --- a/src/Components/Facility/PatientNoteCard.tsx +++ b/src/Components/Facility/PatientNoteCard.tsx @@ -21,10 +21,12 @@ const PatientNoteCard = ({ state, note, setReload, + disableEdit, }: { state: PatientNoteStateType; note: PatientNotesModel; setReload: any; + disableEdit?: boolean; }) => { const [isEditing, setIsEditing] = useState(false); const [noteField, setNoteField] = useState(note.note); @@ -127,7 +129,7 @@ const PatientNoteCard = ({ }
- {note.created_by_object.id === authUser.id && ( + {!disableEdit && note.created_by_object.id === authUser.id && (
Date: Tue, 13 Feb 2024 15:20:09 +0530 Subject: [PATCH 5/6] Make editing more intuitive --- src/Components/Facility/PatientNoteCard.tsx | 65 +++++++++++++-------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/src/Components/Facility/PatientNoteCard.tsx b/src/Components/Facility/PatientNoteCard.tsx index 8f98e621573..c97527f5070 100644 --- a/src/Components/Facility/PatientNoteCard.tsx +++ b/src/Components/Facility/PatientNoteCard.tsx @@ -129,35 +129,52 @@ const PatientNoteCard = ({ }
- {!disableEdit && note.created_by_object.id === authUser.id && ( - { - if (!isEditing) setIsEditing(true); - }} - > - {isEditing ? ( - - ) : ( + {!disableEdit && + note.created_by_object.id === authUser.id && + !isEditing && ( + { + setIsEditing(true); + }} + > - )} - - )} + + )}
{
{isEditing ? ( - +
+ +
+ + + Update Note + + { + setIsEditing(false); + setNoteField(note.note); + }} + id="cancel-update-note-button" + > + + +
+
) : (
{noteField}
)} From 8650c240bab2bb1c6d00bc7c2ffc0a7fb1bc2c9a Mon Sep 17 00:00:00 2001 From: Ashesh3 <3626859+Ashesh3@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:10:46 +0530 Subject: [PATCH 6/6] Refactor PatientNoteCard component buttons --- src/Components/Facility/PatientNoteCard.tsx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Components/Facility/PatientNoteCard.tsx b/src/Components/Facility/PatientNoteCard.tsx index c97527f5070..671c1744acf 100644 --- a/src/Components/Facility/PatientNoteCard.tsx +++ b/src/Components/Facility/PatientNoteCard.tsx @@ -152,17 +152,9 @@ const PatientNoteCard = ({ value={noteField} onChange={(e) => setNoteField(e.target.value)} > -
+
- - Update Note - - { @@ -172,6 +164,15 @@ const PatientNoteCard = ({ id="cancel-update-note-button" > + Cancel + + + + Update Note