Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reply feature for doctor notes #7805

Merged
merged 7 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 41 additions & 30 deletions src/Components/Facility/ConsultationDoctorNotes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ 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 { PatientNoteStateType, PaitentNotesReplyModel } from "../models.js";
import routes from "../../../Redux/api.js";
import request from "../../../Utils/request/request.js";
import useQuery from "../../../Utils/request/useQuery.js";
Expand All @@ -15,6 +15,7 @@ import { classNames, isAppleDevice } from "../../../Utils/utils.js";
import AutoExpandingTextInputFormField from "../../Form/FormFields/AutoExpandingTextInputFormField.js";
import { PATIENT_NOTES_THREADS } from "../../../Common/constants.js";
import useAuthUser from "../../../Common/hooks/useAuthUser.js";
import DoctorNoteReplyPreviewCard from "../DoctorNoteReplyPreviewCard.js";

interface ConsultationDoctorNotesProps {
patientId: string;
Expand All @@ -38,6 +39,9 @@ const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => {
const [facilityName, setFacilityName] = useState("");
const [patientName, setPatientName] = useState("");
const [focused, setFocused] = useState(false);
const [reply_to, setReplyTo] = useState<PaitentNotesReplyModel | undefined>(
undefined,
);

const initialData: PatientNoteStateType = {
notes: [],
Expand All @@ -64,6 +68,7 @@ const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => {
note: noteField,
thread,
consultation: consultationId,
reply_to: reply_to?.id,
},
});

Expand All @@ -72,6 +77,7 @@ const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => {
setState({ ...state, cPage: 1 });
setNoteField("");
setReload(true);
setReplyTo(undefined);
}
};

Expand Down Expand Up @@ -148,36 +154,41 @@ const ConsultationDoctorNotes = (props: ConsultationDoctorNotesProps) => {
reload={reload}
setReload={setReload}
thread={thread}
setReplyTo={setReplyTo}
/>

<div className="relative mx-4 flex items-center">
<AutoExpandingTextInputFormField
id="doctor_consultation_notes"
maxHeight={160}
rows={1}
name="note"
value={noteField}
onChange={(e) => setNoteField(e.value)}
className="w-full grow"
innerClassName="pr-10"
errorClassName="hidden"
placeholder="Type your Note"
disabled={!patientActive}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
/>
<ButtonV2
onClick={onAddNote}
border={false}
className="absolute right-2"
ghost
size="small"
disabled={!patientActive}
authorizeFor={NonReadOnlyUsers}
>
<CareIcon icon="l-message" className="text-lg" />
</ButtonV2>
</div>
<DoctorNoteReplyPreviewCard
parentNote={reply_to}
cancelReply={() => setReplyTo(undefined)}
>
<div className="relative mx-4 flex items-center">
<AutoExpandingTextInputFormField
id="doctor_consultation_notes"
maxHeight={160}
rows={1}
name="note"
value={noteField}
onChange={(e) => setNoteField(e.value)}
className="w-full grow"
innerClassName="pr-10"
errorClassName="hidden"
placeholder="Type your Note"
disabled={!patientActive}
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
/>
<ButtonV2
onClick={onAddNote}
border={false}
className="absolute right-2"
ghost
size="small"
disabled={!patientActive}
authorizeFor={NonReadOnlyUsers}
>
<CareIcon icon="l-message" className="text-lg" />
</ButtonV2>
</div>
</DoctorNoteReplyPreviewCard>
</div>
</Page>
);
Expand Down
21 changes: 14 additions & 7 deletions src/Components/Facility/DoctorNote.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import InfiniteScroll from "react-infinite-scroll-component";
import CircularProgress from "../Common/components/CircularProgress";
import PatientNoteCard from "./PatientNoteCard";
import { PatientNoteStateType } from "./models";
import { PatientNoteStateType, PatientNotesModel } from "./models";
import DoctorNoteReplyPreviewCard from "./DoctorNoteReplyPreviewCard";

interface DoctorNoteProps {
state: PatientNoteStateType;
setReload: any;
handleNext: () => void;
disableEdit?: boolean;
setReplyTo?: (reply_to: PatientNotesModel | undefined) => void;
}

const DoctorNote = (props: DoctorNoteProps) => {
const { state, handleNext, setReload, disableEdit } = props;
const { state, handleNext, setReload, disableEdit, setReplyTo } = props;

return (
<div
Expand All @@ -33,12 +35,17 @@ const DoctorNote = (props: DoctorNoteProps) => {
scrollableTarget="patient-notes-list"
>
{state.notes.map((note) => (
<PatientNoteCard
note={note}
<DoctorNoteReplyPreviewCard
key={note.id}
setReload={setReload}
disableEdit={disableEdit}
/>
parentNote={note.reply_to}
>
<PatientNoteCard
note={note}
setReload={setReload}
disableEdit={disableEdit}
setReplyTo={setReplyTo}
/>
</DoctorNoteReplyPreviewCard>
))}
</InfiniteScroll>
) : (
Expand Down
64 changes: 64 additions & 0 deletions src/Components/Facility/DoctorNoteReplyPreviewCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from "react";
import { PaitentNotesReplyModel } from "./models";
import { USER_TYPES_MAP } from "../../Common/constants";
import { formatDateTime, relativeDate } from "../../Utils/utils";

interface Props {
parentNote: PaitentNotesReplyModel | undefined;
children: React.ReactNode;
cancelReply?: () => void;
}

const DoctorNoteReplyPreviewCard = ({
parentNote,
children,
cancelReply,
}: Props) => {
return (
<div className="">
{parentNote ? (
<div className="mt-4 flex w-full flex-col rounded-lg border border-gray-300 bg-gray-200 p-2 text-gray-800">
<div className="flex flex-col px-2">
<div className="flex justify-between">
<div>
<div>
<span className="text-sm font-semibold text-gray-700">
{parentNote.created_by_object?.first_name || "Unknown"}{" "}
{parentNote.created_by_object?.last_name}
</span>
{parentNote.user_type && (
<span className="pl-2 text-sm text-gray-700">
{`(${USER_TYPES_MAP[parentNote.user_type]})`}
</span>
)}
</div>
<div className="text-xs text-gray-600">
<div className="tooltip inline">
<span className="tooltip-text tooltip-bottom">
{formatDateTime(parentNote.created_date)}
</span>
Created {relativeDate(parentNote.created_date, true)}
</div>
</div>
</div>
{cancelReply && (
<div
className="cursor-pointer text-xs text-gray-600"
onClick={cancelReply}
>
Cancel
</div>
)}
</div>
<div className="pb-2 text-sm text-gray-700">{parentNote.note}</div>
</div>
<div>{children}</div>
</div>
) : (
<div>{children}</div>
)}
</div>
);
};

export default DoctorNoteReplyPreviewCard;
12 changes: 11 additions & 1 deletion src/Components/Facility/PatientConsultationNotesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,21 @@ interface PatientNotesProps {
setReload?: (value: boolean) => void;
disableEdit?: boolean;
thread: PatientNotesModel["thread"];
setReplyTo?: (value: PatientNotesModel | undefined) => void;
}

const pageSize = RESULTS_PER_PAGE_LIMIT;

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

const [isLoading, setIsLoading] = useState(true);
Expand Down Expand Up @@ -94,6 +103,7 @@ const PatientConsultationNotesList = (props: PatientNotesProps) => {
handleNext={handleNext}
setReload={setReload}
disableEdit={disableEdit}
setReplyTo={setReplyTo}
/>
);
};
Expand Down
37 changes: 24 additions & 13 deletions src/Components/Facility/PatientNoteCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ const PatientNoteCard = ({
note,
setReload,
disableEdit,
setReplyTo,
}: {
note: PatientNotesModel;
setReload: any;
disableEdit?: boolean;
setReplyTo?: (reply_to: PatientNotesModel | undefined) => void;
}) => {
const patientId = useSlug("patient");
const [isEditing, setIsEditing] = useState(false);
Expand Down Expand Up @@ -124,19 +126,28 @@ const PatientNoteCard = ({
)
}
</div>

{!disableEdit &&
note.created_by_object.id === authUser.id &&
!isEditing && (
<ButtonV2
ghost
onClick={() => {
setIsEditing(true);
}}
>
<CareIcon icon="l-pen" className="h-5 w-5" />
</ButtonV2>
)}
<div className="flex gap-2">
{!disableEdit &&
note.created_by_object.id === authUser.id &&
!isEditing && (
<ButtonV2
ghost
onClick={() => {
setIsEditing(true);
}}
>
<CareIcon icon="l-pen" className="h-5 w-5" />
</ButtonV2>
)}
<ButtonV2
ghost
onClick={() => {
setReplyTo && setReplyTo(note);
}}
>
<CareIcon icon="l-corner-up-left-alt" className="h-5 w-5" />
</ButtonV2>
</div>
</div>
{
<div className="mt-2">
Expand Down
10 changes: 8 additions & 2 deletions src/Components/Facility/PatientNotesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ interface PatientNotesProps {
reload?: boolean;
setReload?: any;
thread: PatientNotesModel["thread"];
setReplyTo?: (reply_to: PatientNotesModel | undefined) => void;
}

const pageSize = RESULTS_PER_PAGE_LIMIT;

const PatientNotesList = (props: PatientNotesProps) => {
const { state, setState, reload, setReload, thread } = props;
const { state, setState, reload, setReload, thread, setReplyTo } = props;

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

Expand Down Expand Up @@ -83,7 +84,12 @@ const PatientNotesList = (props: PatientNotesProps) => {
}

return (
<DoctorNote state={state} handleNext={handleNext} setReload={setReload} />
<DoctorNote
state={state}
handleNext={handleNext}
setReload={setReload}
setReplyTo={setReplyTo}
/>
);
};

Expand Down
Loading
Loading