From c577b91dfe0764b1274000871f1b05ef823e2094 Mon Sep 17 00:00:00 2001 From: PhilReact Date: Fri, 27 Sep 2024 02:03:44 +0300 Subject: [PATCH] fixes --- src/components/Chat/TipTap.tsx | 398 +++++++++++------------ src/components/Group/Forum/GroupMail.tsx | 12 +- src/components/Group/Forum/NewThread.tsx | 16 +- src/components/ReactionPicker.tsx | 20 +- 4 files changed, 228 insertions(+), 218 deletions(-) diff --git a/src/components/Chat/TipTap.tsx b/src/components/Chat/TipTap.tsx index c7e3e7f..7c9ce5c 100644 --- a/src/components/Chat/TipTap.tsx +++ b/src/components/Chat/TipTap.tsx @@ -1,34 +1,35 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { EditorProvider, useCurrentEditor } from '@tiptap/react'; -import StarterKit from '@tiptap/starter-kit'; -import { Color } from '@tiptap/extension-color'; -import ListItem from '@tiptap/extension-list-item'; -import TextStyle from '@tiptap/extension-text-style'; -import Placeholder from '@tiptap/extension-placeholder' -import Image from '@tiptap/extension-image'; -import IconButton from '@mui/material/IconButton'; -import FormatBoldIcon from '@mui/icons-material/FormatBold'; -import FormatItalicIcon from '@mui/icons-material/FormatItalic'; -import StrikethroughSIcon from '@mui/icons-material/StrikethroughS'; -import FormatClearIcon from '@mui/icons-material/FormatClear'; -import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted'; -import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered'; -import CodeIcon from '@mui/icons-material/Code'; -import ImageIcon from '@mui/icons-material/Image'; // Import Image icon -import FormatQuoteIcon from '@mui/icons-material/FormatQuote'; -import HorizontalRuleIcon from '@mui/icons-material/HorizontalRule'; -import UndoIcon from '@mui/icons-material/Undo'; -import RedoIcon from '@mui/icons-material/Redo'; -import FormatHeadingIcon from '@mui/icons-material/FormatSize'; -import DeveloperModeIcon from '@mui/icons-material/DeveloperMode'; -import CustomImage from './CustomImage'; -import Compressor from 'compressorjs' +import React, { useEffect, useRef, useState } from "react"; +import { EditorProvider, useCurrentEditor } from "@tiptap/react"; +import StarterKit from "@tiptap/starter-kit"; +import { Color } from "@tiptap/extension-color"; +import ListItem from "@tiptap/extension-list-item"; +import TextStyle from "@tiptap/extension-text-style"; +import Placeholder from "@tiptap/extension-placeholder"; +import Image from "@tiptap/extension-image"; +import IconButton from "@mui/material/IconButton"; +import FormatBoldIcon from "@mui/icons-material/FormatBold"; +import FormatItalicIcon from "@mui/icons-material/FormatItalic"; +import StrikethroughSIcon from "@mui/icons-material/StrikethroughS"; +import FormatClearIcon from "@mui/icons-material/FormatClear"; +import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted"; +import FormatListNumberedIcon from "@mui/icons-material/FormatListNumbered"; +import CodeIcon from "@mui/icons-material/Code"; +import ImageIcon from "@mui/icons-material/Image"; // Import Image icon +import FormatQuoteIcon from "@mui/icons-material/FormatQuote"; +import HorizontalRuleIcon from "@mui/icons-material/HorizontalRule"; +import UndoIcon from "@mui/icons-material/Undo"; +import RedoIcon from "@mui/icons-material/Redo"; +import FormatHeadingIcon from "@mui/icons-material/FormatSize"; +import DeveloperModeIcon from "@mui/icons-material/DeveloperMode"; +import Compressor from "compressorjs"; + +import ImageResize from "tiptap-extension-resize-image"; // Import the ResizeImage extension +import { isMobile } from "../../App"; -import ImageResize from 'tiptap-extension-resize-image'; // Import the ResizeImage extension -import { isMobile } from '../../App'; const MenuBar = ({ setEditorRef, isChat }) => { const { editor } = useCurrentEditor(); - const fileInputRef = useRef(null); + const fileInputRef = useRef(null); + if (!editor) { return null; } @@ -39,33 +40,35 @@ const MenuBar = ({ setEditorRef, isChat }) => { } }, [editor, setEditorRef]); - const handleImageUpload = async (event) => { - - const file = event.target.files[0]; - - let compressedFile + const handleImageUpload = async (file) => { + let compressedFile; await new Promise((resolve) => { new Compressor(file, { quality: 0.6, maxWidth: 1200, - mimeType: 'image/webp', + mimeType: "image/webp", success(result) { - const file = new File([result], 'name', { - type: 'image/webp' - }) - compressedFile = file - resolve() + compressedFile = new File([result], "image.webp", { + type: "image/webp", + }); + resolve(); }, - error(err) {} - }) - }) - + error(err) { + console.error("Image compression error:", err); + }, + }); + }); + if (compressedFile) { const reader = new FileReader(); reader.onload = () => { const url = reader.result; - editor.chain().focus().setImage({ src: url , style: "width: auto"}).run(); - fileInputRef.current.value = ''; + editor + .chain() + .focus() + .setImage({ src: url, style: "width: auto" }) + .run(); + fileInputRef.current.value = ""; }; reader.readAsDataURL(compressedFile); } @@ -75,200 +78,171 @@ const MenuBar = ({ setEditorRef, isChat }) => { fileInputRef.current.click(); // Trigger the file input click }; + const handlePaste = (event) => { + const items = event.clipboardData.items; + for (const item of items) { + if (item.type.startsWith("image/")) { + const file = item.getAsFile(); + if (file) { + event.preventDefault(); // Prevent the default paste behavior + handleImageUpload(file); // Call the image upload function + } + } + } + }; + + useEffect(() => { + if (editor) { + editor.view.dom.addEventListener("paste", handlePaste); + return () => { + editor.view.dom.removeEventListener("paste", handlePaste); + }; + } + }, [editor]); + return (
editor.chain().focus().toggleBold().run()} - disabled={ - !editor.can() - .chain() - .focus() - .toggleBold() - .run() - } - // color={editor.isActive('bold') ? 'white' : 'gray'} + disabled={!editor.can().chain().focus().toggleBold().run()} sx={{ - color: editor.isActive('bold') ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("bold") ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > - + editor.chain().focus().toggleItalic().run()} - disabled={ - !editor.can() - .chain() - .focus() - .toggleItalic() - .run() - } - // color={editor.isActive('italic') ? 'white' : 'gray'} + disabled={!editor.can().chain().focus().toggleItalic().run()} sx={{ - color: editor.isActive('italic') ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("italic") ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > editor.chain().focus().toggleStrike().run()} - disabled={ - !editor.can() - .chain() - .focus() - .toggleStrike() - .run() - } - // color={editor.isActive('strike') ? 'white' : 'gray'} + disabled={!editor.can().chain().focus().toggleStrike().run()} sx={{ - color: editor.isActive('strike') ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("strike") ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > editor.chain().focus().toggleCode().run()} - disabled={ - !editor.can() - .chain() - .focus() - .toggleCode() - .run() - } - // color={editor.isActive('code') ? 'white' : 'gray'} + disabled={!editor.can().chain().focus().toggleCode().run()} sx={{ - color: editor.isActive('code') ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("code") ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > editor.chain().focus().unsetAllMarks().run()} - sx={{ - color: editor.isActive('bold') || editor.isActive('italic') || editor.isActive('strike') || editor.isActive('code') - ? 'white' - : 'gray', - padding: isMobile ? '5px' : 'revert', - }} -> - - + onClick={() => editor.chain().focus().unsetAllMarks().run()} + sx={{ + color: + editor.isActive("bold") || + editor.isActive("italic") || + editor.isActive("strike") || + editor.isActive("code") + ? "white" + : "gray", + padding: isMobile ? "5px" : "revert", + }} + > + + editor.chain().focus().toggleBulletList().run()} - // color={editor.isActive('bulletList') ? 'white' : 'gray'} sx={{ - color: editor.isActive('bulletList') ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("bulletList") ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > editor.chain().focus().toggleOrderedList().run()} - // color={editor.isActive('orderedList') ? 'white' : 'gray'} sx={{ - color: editor.isActive('orderedList') ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("orderedList") ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > editor.chain().focus().toggleCodeBlock().run()} - // color={editor.isActive('codeBlock') ? 'white' : 'gray'} sx={{ - color: editor.isActive('codeBlock') ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("codeBlock") ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > editor.chain().focus().toggleBlockquote().run()} - // color={editor.isActive('blockquote') ? 'white' : 'gray'} sx={{ - color: editor.isActive('blockquote') ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("blockquote") ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > editor.chain().focus().setHorizontalRule().run()} - disabled={!editor.can().chain().focus().setHorizontalRule().run()} - sx={{ - color: 'gray', - padding: isMobile ? '5px' : 'revert', - }} -> - - + onClick={() => editor.chain().focus().setHorizontalRule().run()} + disabled={!editor.can().chain().focus().setHorizontalRule().run()} + sx={{ color: "gray", padding: isMobile ? "5px" : "revert" }} + > + + editor.chain().focus().toggleHeading({ level: 1 }).run()} - // color={editor.isActive('heading', { level: 1 }) ? 'white' : 'gray'} + onClick={() => + editor.chain().focus().toggleHeading({ level: 1 }).run() + } sx={{ - color: editor.isActive('heading', { level: 1 }) ? 'white' : 'gray', - padding: isMobile ? '5px' : 'revert' + color: editor.isActive("heading", { level: 1 }) ? "white" : "gray", + padding: isMobile ? "5px" : "revert", }} > editor.chain().focus().undo().run()} - disabled={ - !editor.can() - .chain() - .focus() - .undo() - .run() - } - sx={{ - color: 'gray', - padding: isMobile ? '5px' : 'revert' - }} + disabled={!editor.can().chain().focus().undo().run()} + sx={{ color: "gray", padding: isMobile ? "5px" : "revert" }} > editor.chain().focus().redo().run()} - disabled={ - !editor.can() - .chain() - .focus() - .redo() - .run() - } + disabled={!editor.can().chain().focus().redo().run()} + sx={{ color: "gray" }} > {!isChat && ( <> - - - - + + + + handleImageUpload(event.target.files[0])} + accept="image/*" + /> )} -
); @@ -288,73 +262,91 @@ const extensions = [ }, }), Placeholder.configure({ - placeholder: 'Start typing here...', // Add your placeholder text here + placeholder: "Start typing here...", }), ImageResize, ]; const content = ``; -export default ({ setEditorRef, onEnter, disableEnter, isChat, maxHeightOffset, setIsFocusedParent, isFocusedParent, overrideMobile, customEditorHeight }) => { +export default ({ + setEditorRef, + onEnter, + disableEnter, + isChat, + maxHeightOffset, + setIsFocusedParent, + isFocusedParent, + overrideMobile, + customEditorHeight, +}) => { const [isFocused, setIsFocused] = useState(false); - const extensionsFiltered = isChat ? extensions.filter((item)=> item?.name !== 'image') : extensions + const extensionsFiltered = isChat + ? extensions.filter((item) => item?.name !== "image") + : extensions; const editorRef = useRef(null); const setEditorRefFunc = (editorInstance) => { editorRef.current = editorInstance; - setEditorRef(editorInstance) + setEditorRef(editorInstance); }; + const handleFocus = () => { - if(!isMobile) return - // setIsFocused(true); - setIsFocusedParent(true) + if (!isMobile) return; + setIsFocusedParent(true); }; const handleBlur = () => { const htmlContent = editorRef.current.getHTML(); - - if (!htmlContent?.trim() || htmlContent?.trim() === "

"){ - // setIsFocused(false); - // setIsFocusedParent(false) - }; - + if (!htmlContent?.trim() || htmlContent?.trim() === "

") { + // Set focus state based on content + } }; - // useEffect(()=> { - // setIsFocused(isFocusedParent) - // },[isFocusedParent]) return ( } - extensions={extensionsFiltered} - content={content} - onCreate={({ editor }) => { - editor.on('focus', handleFocus); // Listen for focus event - editor.on('blur', handleBlur); // Listen for blur event - }} - onUpdate={({ editor }) => { + slotBefore={ + (isFocusedParent || !isMobile || overrideMobile) && ( + + ) + } + extensions={extensionsFiltered} + content={content} + onCreate={({ editor }) => { + editor.on("focus", handleFocus); // Listen for focus event + editor.on("blur", handleBlur); // Listen for blur event + }} + onUpdate={({ editor }) => { editor.on('focus', handleFocus); // Ensure focus is updated editor.on('blur', handleBlur); // Ensure blur is updated }} - editorProps={{ - attributes: { - class: 'tiptap-prosemirror', - style: isMobile && `overflow: auto; min-height: ${customEditorHeight ? '200px' : '0px'}; 200px; max-height:calc(100svh - ${ customEditorHeight ? customEditorHeight : '140px'})`, - }, - handleKeyDown(view, event) { - if (!disableEnter && event.key === 'Enter') { - if (event.shiftKey) { - view.dispatch(view.state.tr.replaceSelectionWith(view.state.schema.nodes.hardBreak.create())); - return true; - } else { - if (typeof onEnter === 'function') { - onEnter(); + editorProps={{ + attributes: { + class: "tiptap-prosemirror", + style: + isMobile && + `overflow: auto; min-height: ${ + customEditorHeight ? "200px" : "0px" + }; max-height:calc(100svh - ${customEditorHeight || "140px"})`, + }, + handleKeyDown(view, event) { + if (!disableEnter && event.key === "Enter") { + if (event.shiftKey) { + view.dispatch( + view.state.tr.replaceSelectionWith( + view.state.schema.nodes.hardBreak.create() + ) + ); + return true; + } else { + if (typeof onEnter === "function") { + onEnter(); + } + return true; } - return true; } - } - return false; - }, - }} - /> - ) + return false; + }, + }} + /> + ); }; diff --git a/src/components/Group/Forum/GroupMail.tsx b/src/components/Group/Forum/GroupMail.tsx index 6d26848..05a1b3e 100644 --- a/src/components/Group/Forum/GroupMail.tsx +++ b/src/components/Group/Forum/GroupMail.tsx @@ -53,7 +53,7 @@ import ArrowDownSVG from "../../../assets/svgs/ArrowDown.svg"; import { LoadingSnackbar } from "../../Snackbar/LoadingSnackbar"; import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../../utils/events"; import RefreshIcon from '@mui/icons-material/Refresh'; -import { getArbitraryEndpointReact, getBaseApiReact } from "../../../App"; +import { getArbitraryEndpointReact, getBaseApiReact, isMobile } from "../../../App"; import { WrapperUserAction } from "../../WrapperUserAction"; import { addDataPublishesFunc, getDataPublishesFunc } from "../Group"; const filterOptions = ["Recently active", "Newest", "Oldest"]; @@ -105,12 +105,15 @@ export const GroupMail = ({ const setTempData = async ()=> { try { const getTempAnnouncements = await getTempPublish() - + if(getTempAnnouncements?.thread){ let tempData = [] Object.keys(getTempAnnouncements?.thread || {}).map((key)=> { const value = getTempAnnouncements?.thread[key] - tempData.push(value.data) + if(value?.data?.groupId === groupIdRef?.current){ + tempData.push(value.data) + } + }) setTempPublishedList(tempData) } @@ -720,15 +723,18 @@ export const GroupMail = ({ display: "flex", flexDirection: "column", justifyContent: "center", + width: '100%' }} > {thread?.threadData?.title} + {filterMode === "Recently active" && (
{ setIsOpen(false); setValue(""); - setPostReply(null) + if(setPostReply){ + setPostReply(null) + } + }; async function publishQDNResource() { @@ -288,6 +291,7 @@ export const NewThread = ({ service: 'DOCUMENT', tempData: threadObject, created: Date.now(), + groupId: groupInfo.groupId } const dataToSaveToStoragePost = { name: myName, @@ -313,15 +317,7 @@ export const NewThread = ({ // ); if (publishCallback) { publishCallback() - // threadCallback({ - // threadData: threadObject, - // threadOwner: name, - // name, - // threadId: identifierThread, - // created: Date.now(), - // service: 'MAIL_PRIVATE', - // identifier: identifier - // }) + } closeModal(); } else { diff --git a/src/components/ReactionPicker.tsx b/src/components/ReactionPicker.tsx index eb33021..849e05d 100644 --- a/src/components/ReactionPicker.tsx +++ b/src/components/ReactionPicker.tsx @@ -44,13 +44,28 @@ export const ReactionPicker = ({ onReaction }) => { {/* Emoji CTA */} setShowPicker(!showPicker)}> + }} + // onTouchStart={(e) => { + // e.preventDefault(); // Prevent mobile keyboard + // e.stopPropagation(); + // if(!isMobile) return + // setShowPicker(!showPicker); + // }} + onClick={(e) => { + e.preventDefault(); // Prevents any focus issues + e.stopPropagation(); + // if(isMobile) return + + setShowPicker(!showPicker); + }} + + > 😃 {/* Emoji Picker with dark theme */} {showPicker && ( -
+
e.preventDefault()}> { onReactionClick={handleReaction} onEmojiClick={handlePicker} allowExpandReactions={true} + autoFocusSearch={false} theme={Theme.DARK} />