diff --git a/src/components/Common/DiscussionNotesEditor.tsx b/src/components/Common/DiscussionNotesEditor.tsx index 8efd0e84f72..d41c2cd87be 100644 --- a/src/components/Common/DiscussionNotesEditor.tsx +++ b/src/components/Common/DiscussionNotesEditor.tsx @@ -1,5 +1,6 @@ import { t } from "i18next"; import React, { useEffect, useRef, useState } from "react"; +import useKeyboardShortcut from "use-keyboard-shortcut"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -13,7 +14,7 @@ import NotePreview from "@/components/Common/NotePreview"; import useFileUpload from "@/hooks/useFileUpload"; import { getCaretCoordinates, getCaretInfo } from "@/Utils/textEditor"; -import { classNames } from "@/Utils/utils"; +import { classNames, isAppleDevice } from "@/Utils/utils"; interface DiscussionNotesEditorProps { initialNote?: string; @@ -23,6 +24,7 @@ interface DiscussionNotesEditorProps { onRefetch?: () => void; maxRows?: number; className?: string; + parentRef?: React.RefObject; } const DiscussionNotesEditor: React.FC = ({ @@ -33,6 +35,7 @@ const DiscussionNotesEditor: React.FC = ({ onRefetch, maxRows, className, + parentRef, }) => { const editorRef = useRef(null); const [showMentions, setShowMentions] = useState(false); @@ -154,6 +157,20 @@ const DiscussionNotesEditor: React.FC = ({ }); }; + useKeyboardShortcut( + [isAppleDevice ? "Meta" : "Shift", "Enter"], + async () => { + if (editorRef.current && text.trim()) { + await onAddNote(); + setText(""); + onRefetch?.(); + } + }, + { + ignoreInputFields: false, + }, + ); + return (
@@ -287,6 +304,7 @@ const DiscussionNotesEditor: React.FC = ({ position={mentionPosition} filter={mentionFilter} containerRef={editorRef} + parentRef={parentRef} /> )} diff --git a/src/components/Common/MentionDropdown.tsx b/src/components/Common/MentionDropdown.tsx index 11787379d4c..0338f9ee39a 100644 --- a/src/components/Common/MentionDropdown.tsx +++ b/src/components/Common/MentionDropdown.tsx @@ -14,6 +14,7 @@ interface MentionsDropdownProps { position: { top: number; left: number }; filter: string; containerRef: React.RefObject; + parentRef?: React.RefObject; } const KEYS = { @@ -28,6 +29,7 @@ const MentionsDropdown: React.FC = ({ position, filter, containerRef, + parentRef, }) => { const facilityId = useSlug("facility"); const { data, loading } = useQuery(routes.getFacilityUsers, { @@ -38,16 +40,24 @@ const MentionsDropdown: React.FC = ({ const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0 }); const [selectedIndex, setSelectedIndex] = useState(null); - useEffect(() => { if (containerRef.current) { const rect = containerRef.current.getBoundingClientRect(); - setDropdownPosition({ - top: rect.top + position.top, - left: rect.left + position.left, - }); + const parentRect = parentRef?.current?.getBoundingClientRect(); + + if (parentRef?.current && parentRect) { + setDropdownPosition({ + top: rect.top - parentRect.top + position.top, + left: rect.left - parentRect.left + position.left, + }); + } else { + setDropdownPosition({ + top: rect.top + position.top, + left: rect.left + position.left, + }); + } } - }, [position, containerRef]); + }, [position, containerRef, parentRef]); const filteredUsers = useMemo(() => { return users.filter((user) => diff --git a/src/components/Facility/PatientNotesSlideover.tsx b/src/components/Facility/PatientNotesSlideover.tsx index 22fe5b91e9e..fbb49e51ffd 100644 --- a/src/components/Facility/PatientNotesSlideover.tsx +++ b/src/components/Facility/PatientNotesSlideover.tsx @@ -1,5 +1,5 @@ import { Link } from "raviger"; -import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -51,6 +51,8 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { undefined, ); + const slideoverRef = useRef(null); + useEffect(() => { if (notificationSubscriptionState === "unsubscribed") { Notification.Warn({ @@ -215,6 +217,7 @@ export default function PatientNotesSlideover(props: PatientNotesProps) { return (
)} diff --git a/src/components/Files/FileUpload.tsx b/src/components/Files/FileUpload.tsx index 50ab3ffdb01..a1da295978b 100644 --- a/src/components/Files/FileUpload.tsx +++ b/src/components/Files/FileUpload.tsx @@ -150,10 +150,21 @@ export const FileUpload = (props: FileUploadProps) => { silent: true, }); + const discussionNotesQuery = useQuery(routes.viewUpload, { + query: { + file_type: "PATIENT_NOTES", + consultation_id: consultationId, + is_archived: false, + limit: RESULTS_PER_PAGE_LIMIT, + offset: offset, + }, + }); + const queries = { UNARCHIVED: activeFilesQuery, ARCHIVED: archivedFilesQuery, DISCHARGE_SUMMARY: dischargeSummaryQuery, + PATIENT_NOTES: discussionNotesQuery, }; const refetchAll = async () => @@ -173,6 +184,14 @@ export const FileUpload = (props: FileUploadProps) => { }, ] : []), + ...(discussionNotesQuery.data?.results?.length + ? [ + { + text: "Patient Notes", + value: "PATIENT_NOTES", + }, + ] + : []), ]; const fileUpload = useFileUpload({ @@ -225,6 +244,12 @@ export const FileUpload = (props: FileUploadProps) => { onEdit: refetchAll, }); + const patientNotesFileManager = useFileManager({ + type: "PATIENT_NOTES", + onArchive: refetchAll, + onEdit: refetchAll, + }); + const uploadButtons: { name: string; icon: IconName; @@ -258,7 +283,8 @@ export const FileUpload = (props: FileUploadProps) => { {fileUpload.Dialogues} {fileManager.Dialogues} {dischargeSummaryFileManager.Dialogues} - {!hideUpload && ( + {patientNotesFileManager.Dialogues} + {!hideUpload && tab !== "PATIENT_NOTES" && ( {({ isAuthorized }) => isAuthorized ? ( @@ -357,17 +383,20 @@ export const FileUpload = (props: FileUploadProps) => { file={item} key={item.id} fileManager={ - tab !== "DISCHARGE_SUMMARY" - ? fileManager - : dischargeSummaryFileManager + { + DISCHARGE_SUMMARY: dischargeSummaryFileManager, + PATIENT_NOTES: patientNotesFileManager, + }[tab] || fileManager + } + associating_id={ + tab === "PATIENT_NOTES" ? item.associating_id! : associatedId } - associating_id={associatedId} editable={ item?.uploaded_by?.username === authUser.username || authUser.user_type === "DistrictAdmin" || authUser.user_type === "StateAdmin" } - archivable={tab !== "DISCHARGE_SUMMARY"} + archivable={!["PATIENT_NOTES", "DISCHARGE_SUMMARY"].includes(tab)} /> ))} {!(fileQuery?.data?.results || []).length && (