Skip to content

Commit

Permalink
code suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
UdaySagar-Git committed Dec 5, 2024
1 parent 4702d32 commit d0186b6
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 108 deletions.
7 changes: 7 additions & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@
"assigned_to": "Assigned to",
"assigned_volunteer": "Assigned Volunteer",
"async_operation_warning": "This operation may take some time. Please check back later.",
"attach_file": "Attach File",
"atypical_presentation_details": "Atypical presentation details",
"audio__allow_permission": "Please allow microphone permission in site settings",
"audio__allow_permission_button": "Click here to know how to allow",
Expand Down Expand Up @@ -913,6 +914,7 @@
"medicines_administered": "Medicine(s) administered",
"medicines_administered_error": "Error administering medicine(s)",
"member_id_required": "Member Id is required",
"mention": "Mention",
"middleware_hostname": "Middleware Hostname",
"middleware_hostname_example": "e.g. example.ohc.network",
"middleware_hostname_sourced_from": "Middleware hostname sourced from {{ source }}",
Expand Down Expand Up @@ -965,6 +967,7 @@
"no_linked_facilities": "No Linked Facilities",
"no_log_update_delta": "No changes since previous log update",
"no_log_updates": "No log updates found",
"no_matching_users": "No matching users found",
"no_medical_history_available": "No Medical History Available",
"no_notices_for_you": "No notices for you.",
"no_patients_found": "No Patients Found",
Expand All @@ -985,6 +988,7 @@
"normal": "Normal",
"not_eligible": "Not Eligible",
"not_specified": "Not Specified",
"note": "Note",
"notes": "Notes",
"notes_placeholder": "Type your Notes",
"notice_board": "Notice Board",
Expand Down Expand Up @@ -1161,6 +1165,7 @@
"reload": "Reload",
"remove": "Remove",
"rename": "Rename",
"replies": "Replies",
"reply": "Reply",
"report": "Report",
"req_atleast_one_digit": "Require at least one digit",
Expand Down Expand Up @@ -1347,6 +1352,7 @@
"type_d_cylinders": "D Type Cylinders",
"type_to_search": "Type to search",
"type_your_comment": "Type your comment",
"type_your_message": "Type your message here...",
"type_your_reason_here": "Type your reason here",
"unable_to_get_current_position": "Unable to get current position.",
"unconfirmed": "Unconfirmed",
Expand Down Expand Up @@ -1391,6 +1397,7 @@
"use_existing_abha_address": "Use Existing ABHA Address",
"user_deleted_successfuly": "User Deleted Successfuly",
"user_management": "User Management",
"user_mentions": "User Mentions",
"username": "Username",
"users": "Users",
"vacant": "Vacant",
Expand Down
120 changes: 50 additions & 70 deletions src/components/Common/DiscussionNotesEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React, { useCallback, useEffect, useRef, useState } from "react";
import { t } from "i18next";
import React, { useEffect, useRef, useState } from "react";

import CareIcon from "@/CAREUI/icons/CareIcon";

import { Submit } from "@/components/Common/ButtonV2";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";

import { FilePreviewCard } from "@/components/Common/FilePreviewCard";
import MentionsDropdown from "@/components/Common/MentionDropdown";
import NotePreview from "@/components/Common/NotePreview";
Expand Down Expand Up @@ -65,7 +68,6 @@ const DiscussionNotesEditor: React.FC<DiscussionNotesEditorProps> = ({
"xls",
"xlsx",
"ods",
"pdf",
],
});

Expand Down Expand Up @@ -167,17 +169,34 @@ const DiscussionNotesEditor: React.FC<DiscussionNotesEditorProps> = ({
<NotePreview initialNote={text} />
</div>
) : (
<AutoExpandingTextarea
<Textarea
id="discussion_notes_textarea"
ref={editorRef}
placeholder="Type your message here..."
placeholder={t("type_your_message")}
className={classNames(
"w-full resize-none border-none p-3 align-middle text-sm outline-none focus:outline-none focus:ring-0",
"w-full resize-none border-0 p-3 text-sm",
maxRows ? "overflow-y-auto" : "overflow-hidden",
)}
value={text}
onInput={handleInput}
maxRows={maxRows}
onChange={handleInput}
onInput={(e) => {
// auto expand textarea
const textarea = e.currentTarget;
textarea.style.height = "auto";
textarea.style.height = `${textarea.scrollHeight}px`;
if (maxRows) {
const lineHeight = parseInt(
window.getComputedStyle(textarea).lineHeight,
);
const maxHeight = lineHeight * maxRows;
if (textarea.scrollHeight > maxHeight) {
textarea.style.height = `${maxHeight}px`;
textarea.style.overflowY = "auto";
} else {
textarea.style.overflowY = "hidden";
}
}
}}
/>
)}
{fileUpload.files.length > 0 && (
Expand All @@ -196,46 +215,52 @@ const DiscussionNotesEditor: React.FC<DiscussionNotesEditorProps> = ({

{/* toolbar*/}
<div className="flex items-center space-x-1 rounded-b-md border border-secondary-300 bg-secondary-100 pl-2 sm:space-x-2">
<label className="tooltip cursor-pointer rounded bg-secondary-200/50 p-1 text-secondary-700">
<label className="tooltip cursor-pointer rounded bg-secondary-200/50 px-1 text-secondary-800">
<CareIcon icon="l-paperclip" className="text-lg" />
<span className="tooltip-text tooltip-top -translate-x-4">
Attach File
{t("attach_file")}
</span>
<fileUpload.Input multiple />
</label>
<div className="mx-2 h-6 border-l border-secondary-400"></div>
<button
<Button
variant="ghost"
size="icon"
onClick={() => fileUpload.handleCameraCapture()}
className="tooltip rounded bg-secondary-200/50 p-1"
className="tooltip rounded bg-secondary-200/50 px-1"
>
<CareIcon icon="l-camera" className="text-lg" />
<span className="tooltip-text tooltip-top -translate-x-1/2">
Camera
{t("camera")}
</span>
</button>
<button
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => fileUpload.handleAudioCapture()}
className="tooltip rounded bg-secondary-200/50 p-1"
className="tooltip rounded bg-secondary-200/50 px-1"
>
<CareIcon icon="l-microphone" className="text-lg" />
<span className="tooltip-text tooltip-top -translate-x-1/2">
Audio
{t("audio__record")}
</span>
</button>
</Button>
<div className="mx-2 h-6 border-l border-secondary-400"></div>
<button
<Button
variant="ghost"
size="icon"
onClick={handleMentionButtonClick}
className="tooltip rounded bg-secondary-200/50 p-1"
className="tooltip rounded bg-secondary-200/50 px-1"
>
<CareIcon icon="l-at" className="text-lg" />
<span className="tooltip-text tooltip-top -translate-x-1/2">
Mention
{t("mention")}
</span>
</button>
</Button>

<div className="grow"></div>

<Submit
<Button
id="add_doctor_note_button"
onClick={async () => {
if (!editorRef.current) return;
Expand All @@ -249,17 +274,17 @@ const DiscussionNotesEditor: React.FC<DiscussionNotesEditorProps> = ({
}}
className="max-w-12"
disabled={!isAuthorized || isPreviewMode}
variant="primary"
>
<CareIcon icon="l-message" className="text-lg" />
</Submit>
</Button>
</div>
</div>

{showMentions && (
<MentionsDropdown
onSelect={insertMention}
position={mentionPosition}
editorRef={editorRef}
filter={mentionFilter}
containerRef={editorRef}
/>
Expand All @@ -270,49 +295,4 @@ const DiscussionNotesEditor: React.FC<DiscussionNotesEditorProps> = ({
);
};

interface AutoExpandingTextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
maxRows?: number;
}

const AutoExpandingTextarea = React.forwardRef<
HTMLTextAreaElement,
AutoExpandingTextareaProps
>(({ maxRows, ...props }, ref) => {
const adjustHeight = useCallback(
(textarea: HTMLTextAreaElement) => {
textarea.style.height = "auto";

const style = window.getComputedStyle(textarea);
const borderHeight =
parseInt(style.borderTopWidth) + parseInt(style.borderBottomWidth);
const paddingHeight =
parseInt(style.paddingTop) + parseInt(style.paddingBottom);

const lineHeight = parseInt(style.lineHeight);
const maxHeight = maxRows
? lineHeight * maxRows + borderHeight + paddingHeight
: Infinity;

const newHeight = Math.min(
textarea.scrollHeight + borderHeight,
maxHeight,
);
textarea.style.height = `${newHeight}px`;
},
[maxRows],
);

useEffect(() => {
const textarea = (ref as React.RefObject<HTMLTextAreaElement>).current;
if (textarea) {
adjustHeight(textarea);
}
}, [props.value, adjustHeight]);

return <textarea ref={ref} {...props} />;
});

AutoExpandingTextarea.displayName = "AutoExpandingTextarea";

export default DiscussionNotesEditor;
4 changes: 4 additions & 0 deletions src/components/Common/FilePreviewCard.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { t } from "i18next";

import CareIcon, { IconName } from "@/CAREUI/icons/CareIcon";

import { FileUploadModel } from "@/components/Patient/models";
Expand Down Expand Up @@ -54,6 +56,8 @@ export function FilePreviewCard({
onClick && "cursor-pointer",
)}
onClick={onClick}
role="button"
aria-label={t("file_preview")}
>
{!readonly && onRemove && typeof index === "number" && (
<button
Expand Down
24 changes: 11 additions & 13 deletions src/components/Common/MentionDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { t } from "i18next";
import React, { useCallback, useEffect, useMemo, useState } from "react";

import { Avatar } from "@/components/Common/Avatar";
Expand All @@ -11,7 +12,6 @@ import { formatDisplayName } from "@/Utils/utils";
interface MentionsDropdownProps {
onSelect: (user: { id: string; username: string }) => void;
position: { top: number; left: number };
editorRef: React.RefObject<HTMLTextAreaElement>;
filter: string;
containerRef: React.RefObject<HTMLTextAreaElement>;
}
Expand All @@ -26,7 +26,6 @@ const KEYS = {
const MentionsDropdown: React.FC<MentionsDropdownProps> = ({
onSelect,
position,
editorRef,
filter,
containerRef,
}) => {
Expand Down Expand Up @@ -58,10 +57,6 @@ const MentionsDropdown: React.FC<MentionsDropdownProps> = ({

const handleKeyDown = useCallback(
(event: KeyboardEvent) => {
if (document.activeElement !== editorRef.current) {
return;
}

if (event.key === KEYS.ENTER && filteredUsers.length > 0) {
const selectedUser =
selectedIndex !== null
Expand All @@ -86,15 +81,18 @@ const MentionsDropdown: React.FC<MentionsDropdownProps> = ({
});
}
},
[filteredUsers, selectedIndex, onSelect, editorRef],
[filteredUsers, selectedIndex, onSelect],
);

useEffect(() => {
document.addEventListener("keydown", handleKeyDown);
const container = containerRef.current;
if (!container) return;

container.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener("keydown", handleKeyDown);
container.removeEventListener("keydown", handleKeyDown);
};
}, [handleKeyDown]);
}, [handleKeyDown, containerRef]);

return (
<div
Expand All @@ -104,15 +102,15 @@ const MentionsDropdown: React.FC<MentionsDropdownProps> = ({
left: `${dropdownPosition.left}px`,
}}
role="listbox"
aria-label="User mentions"
aria-label={t("user_mentions")}
>
{loading ? (
<div
className="p-2 text-secondary-500"
role="status"
aria-live="polite"
>
<span className="inline-block animate-spin"></span> Loading users...
<span className="inline-block animate-spin"></span> {t("loading")}
</div>
) : filteredUsers.length > 0 ? (
filteredUsers.map((user, index) => (
Expand Down Expand Up @@ -148,7 +146,7 @@ const MentionsDropdown: React.FC<MentionsDropdownProps> = ({
role="status"
aria-live="polite"
>
{filter ? "No matching users found" : "Type to search users"}
{filter ? t("no_matching_users") : t("type_to_search")}
</div>
)}
</div>
Expand Down
10 changes: 7 additions & 3 deletions src/components/Common/NotePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ const NotePreview = ({
position: { x: number; y: number };
} | null>(null);

const SANITIZE_CONFIG = {
ALLOWED_TAGS: ["span", "br"],
ALLOWED_ATTR: ["class", "data-username"],
ALLOW_DATA_ATTR: false,
};

const processText = (content: string) => {
const withLineBreaks = content.replace(/\n/g, "<br />");
// valid usernames : devdoctor, dev-doctor and dev_doctor
Expand All @@ -52,9 +58,7 @@ const NotePreview = ({
return `<span class="cursor-pointer font-medium text-primary hover:underline" data-username="${username}">@${username}</span>`;
});

return DOMPurify.sanitize(withMentions, {
ADD_ATTR: ["data-username"],
});
return DOMPurify.sanitize(withMentions, SANITIZE_CONFIG);
};

useEffect(() => {
Expand Down
Loading

0 comments on commit d0186b6

Please sign in to comment.