From 905cddf29a3b24bc2de7e4619ed2584e84b031eb Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Sat, 19 Apr 2025 16:00:58 +0200 Subject: [PATCH] Add theme to all chat pages --- .../Chat/AnnouncementDiscussion.tsx | 66 ++-- src/components/Chat/AnnouncementItem.tsx | 329 ++++++++++-------- src/components/Chat/AnnouncementList.tsx | 25 +- src/components/Chat/ChatGroup.tsx | 101 +++--- src/components/Chat/CreateCommonSecret.tsx | 296 +++++++++------- src/components/Chat/GroupAnnouncements.tsx | 127 ++++--- src/components/Chat/GroupForum.tsx | 63 ++-- src/components/Chat/MentionList.tsx | 135 ++++--- src/components/Chat/ResizableImage.tsx | 19 +- 9 files changed, 620 insertions(+), 541 deletions(-) diff --git a/src/components/Chat/AnnouncementDiscussion.tsx b/src/components/Chat/AnnouncementDiscussion.tsx index ed06a49..e3c3976 100644 --- a/src/components/Chat/AnnouncementDiscussion.tsx +++ b/src/components/Chat/AnnouncementDiscussion.tsx @@ -4,7 +4,7 @@ import { AuthenticatedContainerInnerTop, CustomButton, } from '../../styles/App-styles'; -import { Box, CircularProgress } from '@mui/material'; +import { Box, CircularProgress, useTheme } from '@mui/material'; import { objectToBase64 } from '../../qdn/encryption/group-encryption'; import ShortUniqueId from 'short-unique-id'; import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar'; @@ -39,6 +39,7 @@ export const AnnouncementDiscussion = ({ myName, isPrivate, }) => { + const theme = useTheme(); const [isSending, setIsSending] = useState(false); const [isLoading, setIsLoading] = useState(false); const [isFocusedParent, setIsFocusedParent] = useState(false); @@ -212,6 +213,7 @@ export const AnnouncementDiscussion = ({ getData({ name: data.name, identifier: data.identifier }, isPrivate); } } catch (error) { + console.log(error); } finally { setIsLoading(false); @@ -274,19 +276,19 @@ export const AnnouncementDiscussion = ({ return (
+
@@ -353,11 +353,11 @@ export const AnnouncementDiscussion = ({ {isFocusedParent && ( @@ -369,13 +369,13 @@ export const AnnouncementDiscussion = ({ // Unfocus the editor }} style={{ - marginTop: 'auto', alignSelf: 'center', + background: 'red', cursor: isSending ? 'default' : 'pointer', flexShrink: 0, - padding: isMobile && '5px', - fontSize: isMobile && '14px', - background: 'red', + fontSize: '14px', + marginTop: 'auto', + padding: '5px', }} > {` Close`} @@ -387,25 +387,25 @@ export const AnnouncementDiscussion = ({ publishComment(); }} style={{ - marginTop: 'auto', alignSelf: 'center', + background: theme.palette.background.default, cursor: isSending ? 'default' : 'pointer', - background: isSending && 'rgba(0, 0, 0, 0.8)', flexShrink: 0, - padding: isMobile && '5px', - fontSize: isMobile && '14px', + fontSize: '14px', + marginTop: 'auto', + padding: '5px', }} > {isSending && ( )} diff --git a/src/components/Chat/AnnouncementItem.tsx b/src/components/Chat/AnnouncementItem.tsx index 758a451..73faf24 100644 --- a/src/components/Chat/AnnouncementItem.tsx +++ b/src/components/Chat/AnnouncementItem.tsx @@ -1,173 +1,206 @@ -import { Message } from "@chatscope/chat-ui-kit-react"; -import React, { useEffect, useState } from "react"; -import { useInView } from "react-intersection-observer"; -import { MessageDisplay } from "./MessageDisplay"; -import { Avatar, Box, Typography } from "@mui/material"; -import { formatTimestamp } from "../../utils/time"; +import React, { useEffect, useState } from 'react'; +import { MessageDisplay } from './MessageDisplay'; +import { Avatar, Box, Typography, useTheme } from '@mui/material'; +import { formatTimestamp } from '../../utils/time'; import ChatBubbleIcon from '@mui/icons-material/ChatBubble'; import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos'; -import { getBaseApi } from "../../background"; -import { requestQueueCommentCount } from "./GroupAnnouncements"; -import { CustomLoader } from "../../common/CustomLoader"; -import { getArbitraryEndpointReact, getBaseApiReact } from "../../App"; -import { WrapperUserAction } from "../WrapperUserAction"; -export const AnnouncementItem = ({ message, messageData, setSelectedAnnouncement, disableComment, myName }) => { +import { getBaseApi } from '../../background'; +import { requestQueueCommentCount } from './GroupAnnouncements'; +import { CustomLoader } from '../../common/CustomLoader'; +import { getArbitraryEndpointReact, getBaseApiReact } from '../../App'; +import { WrapperUserAction } from '../WrapperUserAction'; - const [commentLength, setCommentLength] = useState(0) - const getNumberOfComments = React.useCallback( - async () => { - try { - const offset = 0; +export const AnnouncementItem = ({ + message, + messageData, + setSelectedAnnouncement, + disableComment, + myName, +}) => { + const theme = useTheme(); + const [commentLength, setCommentLength] = useState(0); + const getNumberOfComments = React.useCallback(async () => { + try { + const offset = 0; - // dispatch(setIsLoadingGlobal(true)) - const identifier = `cm-${message.identifier}`; - const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=0&includemetadata=false&offset=${offset}&reverse=true&prefix=true`; - - const response = await requestQueueCommentCount.enqueue(() => { - return fetch(url, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); - }) - const responseData = await response.json(); + // dispatch(setIsLoadingGlobal(true)) + const identifier = `cm-${message.identifier}`; + const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=0&includemetadata=false&offset=${offset}&reverse=true&prefix=true`; + + const response = await requestQueueCommentCount.enqueue(() => { + return fetch(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + }); + const responseData = await response.json(); + + setCommentLength(responseData?.length); + } catch (error) { + console.log(error); + } + }, []); + + useEffect(() => { + if (disableComment) return; + getNumberOfComments(); + }, []); - setCommentLength(responseData?.length); - - } catch (error) { - } finally { - // dispatch(setIsLoadingGlobal(false)) - } - }, - [] - ); - useEffect(()=> { - if(disableComment) return - getNumberOfComments() - }, []) return (
- - - - {message?.name?.charAt(0)} - - - - + + {message?.name?.charAt(0)} + + + - {message?.name} - - - {!messageData?.decryptedData && ( - - - - )} - {messageData?.decryptedData?.message && ( - <> - {messageData?.type === "notification" ? ( - - ) : ( - - )} - - )} + + + {message?.name} + + + {!messageData?.decryptedData && ( + + + + )} + {messageData?.decryptedData?.message && ( + <> + {messageData?.type === 'notification' ? ( + + ) : ( + + )} + + )} - - - {formatTimestamp(message.created)} + + + {formatTimestamp(message.created)} + + - - {!disableComment && ( - setSelectedAnnouncement(message)}> - - - - {commentLength ? ( - {`${commentLength > 1 ? `${commentLength} comments` : `${commentLength} comment`}`} - ) : ( - Leave comment - )} - + {!disableComment && ( + setSelectedAnnouncement(message)} + > + + + {commentLength ? ( + {`${commentLength > 1 ? `${commentLength} comments` : `${commentLength} comment`}`} + ) : ( + + Leave comment + + )} + + - - - )} - + )}
); }; diff --git a/src/components/Chat/AnnouncementList.tsx b/src/components/Chat/AnnouncementList.tsx index efaf1fa..9c32cc1 100644 --- a/src/components/Chat/AnnouncementList.tsx +++ b/src/components/Chat/AnnouncementList.tsx @@ -1,10 +1,5 @@ -import React, { useCallback, useState, useEffect, useRef } from 'react'; -import { - List, - AutoSizer, - CellMeasurerCache, - CellMeasurer, -} from 'react-virtualized'; +import { useState, useEffect, useRef } from 'react'; +import { CellMeasurerCache } from 'react-virtualized'; import { AnnouncementItem } from './AnnouncementItem'; import { Box } from '@mui/material'; import { CustomButton } from '../../styles/App-styles'; @@ -37,12 +32,12 @@ export const AnnouncementList = ({ return (
@@ -57,11 +52,11 @@ export const AnnouncementList = ({
*/} {showLoadMore && ( diff --git a/src/components/Chat/ChatGroup.tsx b/src/components/Chat/ChatGroup.tsx index 9b16f69..97c0551 100644 --- a/src/components/Chat/ChatGroup.tsx +++ b/src/components/Chat/ChatGroup.tsx @@ -7,15 +7,10 @@ import React, { useRef, useState, } from 'react'; -import { CreateCommonSecret } from './CreateCommonSecret'; -import { reusableGet } from '../../qdn/publish/pubish'; -import { uint8ArrayToObject } from '../../backgroundFunctions/encryption'; import { - base64ToUint8Array, decodeBase64ForUIChatMessages, objectToBase64, } from '../../qdn/encryption/group-encryption'; -import { ChatContainerComp } from './ChatContainer'; import { ChatList } from './ChatList'; import '@chatscope/chat-ui-kit-styles/dist/default/styles.min.css'; import Tiptap from './TipTap'; @@ -38,7 +33,7 @@ import { subscribeToEvent, unsubscribeFromEvent, } from '../../utils/events'; -import { Box, ButtonBase, Divider, Typography } from '@mui/material'; +import { Box, ButtonBase, Divider, Typography, useTheme } from '@mui/material'; import ShortUniqueId from 'short-unique-id'; import { ReplyPreview } from './MessageItem'; import { ExitIcon } from '../../assets/Icons/ExitIcon'; @@ -1001,16 +996,18 @@ export const ChatGroup = ({ setIsOpenQManager(true); }, []); + const theme = useTheme(); + return (
{replyMessage && ( @@ -1088,9 +1083,9 @@ export const ChatGroup = ({ {onEditMessage && ( @@ -1123,9 +1118,9 @@ export const ChatGroup = ({ {isSending && ( )} @@ -1185,25 +1182,24 @@ export const ChatGroup = ({ {isOpenQManager !== null && ( Q-Manager @@ -1251,12 +1246,14 @@ export const ChatGroup = ({ )} {/* */} + + { +export const CreateCommonSecret = ({ + groupId, + secretKey, + isOwner, + myAddress, + secretKeyDetails, + userInfo, + noSecretKey, + setHideCommonKeyPopup, + setIsForceShowCreationKeyPopup, + isForceShowCreationKeyPopup, +}) => { const { show, setTxList } = useContext(MyContext); const [openSnack, setOpenSnack] = React.useState(false); const [infoSnack, setInfoSnack] = React.useState(null); - const [isLoading, setIsLoading] = React.useState(false) + const [isLoading, setIsLoading] = React.useState(false); + + const theme = useTheme(); const getPublishesFromAdmins = async (admins: string[]) => { // const validApi = await findUsableApi(); - const queryString = admins.map((name) => `name=${name}`).join("&"); + const queryString = admins.map((name) => `name=${name}`).join('&'); const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT_PRIVATE&identifier=symmetric-qchat-group-${ groupId }&exactmatchnames=true&limit=0&reverse=true&${queryString}&prefix=true`; const response = await fetch(url); - if(!response.ok){ - throw new Error('network error') + if (!response.ok) { + throw new Error('network error'); } const adminData = await response.json(); - + const filterId = adminData.filter( - (data: any) => - data.identifier === `symmetric-qchat-group-${groupId}` + (data: any) => data.identifier === `symmetric-qchat-group-${groupId}` ); if (filterId?.length === 0) { return false; @@ -38,149 +59,182 @@ export const CreateCommonSecret = ({groupId, secretKey, isOwner, myAddress, sec // Get the most recent date for both a and b const dateA = a.updated ? new Date(a.updated) : new Date(a.created); const dateB = b.updated ? new Date(b.updated) : new Date(b.created); - + // Sort by most recent return dateB.getTime() - dateA.getTime(); }); - + return sortedData[0]; }; - const getSecretKey = async (loadingGroupParam?: boolean, secretKeyToPublish?: boolean) => { + + const getSecretKey = async ( + loadingGroupParam?: boolean, + secretKeyToPublish?: boolean + ) => { try { - pauseAllQueues() - - - - const {names} = await getGroupAdmins(groupId); - if(!names.length){ - throw new Error('Network error') + pauseAllQueues(); + + const { names } = await getGroupAdmins(groupId); + if (!names.length) { + throw new Error('Network error'); } const publish = await getPublishesFromAdmins(names); - - + if (publish === false) { - return false; } - + const res = await fetch( `${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ publish.identifier }?encoding=base64&rebuild=true` ); const data = await res.text(); - + const decryptedKey: any = await decryptResource(data); - + const dataint8Array = base64ToUint8Array(decryptedKey.data); const decryptedKeyToObject = uint8ArrayToObject(dataint8Array); - + if (!validateSecretKey(decryptedKeyToObject)) - throw new Error("SecretKey is not valid"); - + throw new Error('SecretKey is not valid'); + if (decryptedKeyToObject) { - return decryptedKeyToObject; - } else { } - } catch (error) { - - - } finally { + console.log(error); } }; - const createCommonSecret = async ()=> { - try { - const fee = await getFee('ARBITRARY') - await show({ - message: "Would you like to perform an ARBITRARY transaction?" , - publishFee: fee.fee + ' QORT' - }) - setIsLoading(true) + const createCommonSecret = async () => { + try { + const fee = await getFee('ARBITRARY'); + await show({ + message: 'Would you like to perform an ARBITRARY transaction?', + publishFee: fee.fee + ' QORT', + }); + setIsLoading(true); - const secretKey2 = await getSecretKey() - if((!secretKey2 && secretKey2 !== false)) throw new Error('invalid secret key') - if (secretKey2 && !validateSecretKey(secretKey2)) throw new Error('invalid secret key') + const secretKey2 = await getSecretKey(); + if (!secretKey2 && secretKey2 !== false) + throw new Error('invalid secret key'); + if (secretKey2 && !validateSecretKey(secretKey2)) + throw new Error('invalid secret key'); - const secretKeyToSend = !secretKey2 ? null : secretKey2 - - - window.sendMessage("encryptAndPublishSymmetricKeyGroupChat", { - groupId: groupId, - previousData: secretKeyToSend, - }) - .then((response) => { - if (!response?.error) { - setInfoSnack({ - type: "success", - message: "Successfully re-encrypted secret key. It may take a couple of minutes for the changes to propagate. Refresh the group in 5 mins.", - }); - setOpenSnack(true); - setTxList((prev) => [ - { - ...response, - type: 'created-common-secret', - label: `Published secret key for group ${groupId}: awaiting confirmation`, - labelDone: `Published secret key for group ${groupId}: success!`, - done: false, - groupId, - }, - ...prev, - ]); - } - setIsLoading(false); - setTimeout(() => { - setIsForceShowCreationKeyPopup(false) - }, 1000); - }) - .catch((error) => { - console.error("Failed to encrypt and publish symmetric key for group chat:", error.message || "An error occurred"); - setIsLoading(false); + const secretKeyToSend = !secretKey2 ? null : secretKey2; + + window + .sendMessage('encryptAndPublishSymmetricKeyGroupChat', { + groupId: groupId, + previousData: secretKeyToSend, + }) + .then((response) => { + if (!response?.error) { + setInfoSnack({ + type: 'success', + message: + 'Successfully re-encrypted secret key. It may take a couple of minutes for the changes to propagate. Refresh the group in 5 mins.', }); - - } catch (error) { - - } + setOpenSnack(true); + setTxList((prev) => [ + { + ...response, + type: 'created-common-secret', + label: `Published secret key for group ${groupId}: awaiting confirmation`, + labelDone: `Published secret key for group ${groupId}: success!`, + done: false, + groupId, + }, + ...prev, + ]); + } + setIsLoading(false); + setTimeout(() => { + setIsForceShowCreationKeyPopup(false); + }, 1000); + }) + .catch((error) => { + console.error( + 'Failed to encrypt and publish symmetric key for group chat:', + error.message || 'An error occurred' + ); + setIsLoading(false); + }); + } catch (error) { + console.log(error); } - + }; return ( - - Re-encrypt key - {noSecretKey ? ( - - There is no group secret key. Be the first admin to publish one! - - ) : isOwner && secretKeyDetails && userInfo?.name && userInfo.name !== secretKeyDetails?.name ? ( - - The latest group secret key was published by a non-owner. As the owner of the group please re-encrypt the key as a safeguard - - ): isForceShowCreationKeyPopup ? null : ( - - The group member list has changed. Please re-encrypt the secret key. - - )} - - + flexDirection: 'column', + gap: '25px', + maxWidth: '350px', + padding: '25px', + }} + > + + Re-encrypt key + + + {noSecretKey ? ( + + + There is no group secret key. Be the first admin to publish one! + + + ) : isOwner && + secretKeyDetails && + userInfo?.name && + userInfo.name !== secretKeyDetails?.name ? ( + + + The latest group secret key was published by a non-owner. As the + owner of the group please re-encrypt the key as a safeguard + + + ) : isForceShowCreationKeyPopup ? null : ( + + + The group member list has changed. Please re-encrypt the secret key. + + + )} + + + - + + - - ) -} + ); +}; diff --git a/src/components/Chat/GroupAnnouncements.tsx b/src/components/Chat/GroupAnnouncements.tsx index 87f7658..4221af7 100644 --- a/src/components/Chat/GroupAnnouncements.tsx +++ b/src/components/Chat/GroupAnnouncements.tsx @@ -5,31 +5,22 @@ import React, { useRef, useState, } from 'react'; -import { CreateCommonSecret } from './CreateCommonSecret'; -import { reusableGet } from '../../qdn/publish/pubish'; import { uint8ArrayToObject } from '../../backgroundFunctions/encryption'; import { base64ToUint8Array, objectToBase64, } from '../../qdn/encryption/group-encryption'; -import { ChatContainerComp } from './ChatContainer'; -import { ChatList } from './ChatList'; import '@chatscope/chat-ui-kit-styles/dist/default/styles.min.css'; import Tiptap from './TipTap'; -import { - AuthenticatedContainerInnerTop, - CustomButton, -} from '../../styles/App-styles'; +import { CustomButton } from '../../styles/App-styles'; import CircularProgress from '@mui/material/CircularProgress'; -import { getBaseApi, getFee } from '../../background'; +import { getFee } from '../../background'; import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar'; -import { Box, Typography } from '@mui/material'; +import { Box, Typography, useTheme } from '@mui/material'; import { Spacer } from '../../common/Spacer'; import ShortUniqueId from 'short-unique-id'; import { AnnouncementList } from './AnnouncementList'; -const uid = new ShortUniqueId({ length: 8 }); import CampaignIcon from '@mui/icons-material/Campaign'; -import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import { AnnouncementDiscussion } from './AnnouncementDiscussion'; import { MyContext, @@ -42,9 +33,11 @@ import { import { RequestQueueWithPromise } from '../../utils/queue/queue'; import { CustomizedSnackbars } from '../Snackbar/Snackbar'; import { addDataPublishesFunc, getDataPublishesFunc } from '../Group/Group'; -import { getRootHeight } from '../../utils/mobile/mobileUtils'; + +const uid = new ShortUniqueId({ length: 8 }); export const requestQueueCommentCount = new RequestQueueWithPromise(3); + export const requestQueuePublishedAccouncements = new RequestQueueWithPromise( 3 ); @@ -125,6 +118,7 @@ export const handleUnencryptedPublishes = (publishes) => { }); return publishesData; }; + export const GroupAnnouncements = ({ selectedGroup, secretKey, @@ -264,6 +258,7 @@ export const GroupAnnouncements = ({ }); }); }; + const clearEditorContent = () => { if (editorRef.current) { editorRef.current.chain().focus().clearContent().run(); @@ -301,10 +296,12 @@ export const GroupAnnouncements = ({ try { pauseAllQueues(); const fee = await getFee('ARBITRARY'); + await show({ message: 'Would you like to perform a ARBITRARY transaction?', publishFee: fee.fee + ' QORT', }); + if (isSending) return; if (editorRef.current) { const htmlContent = editorRef.current.getHTML(); @@ -387,8 +384,7 @@ export const GroupAnnouncements = ({ ); } } catch (error) { - } finally { - // dispatch(setIsLoadingGlobal(false)) + console.log(error); } }, [secretKey] @@ -437,6 +433,8 @@ export const GroupAnnouncements = ({ const interval = useRef(null); + const theme = useTheme(); + const checkNewMessages = React.useCallback(async () => { try { const identifier = `grp-${selectedGroup}-anc-`; @@ -485,7 +483,7 @@ export const GroupAnnouncements = ({ } setAnnouncements((prev) => [...newArray, ...prev]); } catch (error) { - } finally { + console.log(error); } }, [announcements, secretKey, selectedGroup]); @@ -537,10 +535,10 @@ export const GroupAnnouncements = ({ : 'calc(100vh - 70px)', display: 'flex', flexDirection: 'column', - width: '100%', - visibility: hide && 'hidden', - position: hide && 'fixed', left: hide && '-1000px', + position: hide && 'fixed', + visibility: hide && 'hidden', + width: '100%', }} >
{!isMobile && ( Group Announcements )} - +
+ {!isLoading && combinedListTempAndReal?.length === 0 && (
+ {isFocusedParent && ( @@ -692,43 +688,46 @@ export const GroupAnnouncements = ({ // Unfocus the editor }} style={{ - marginTop: 'auto', alignSelf: 'center', - cursor: isSending ? 'default' : 'pointer', background: 'var(--danger)', + cursor: isSending ? 'default' : 'pointer', flexShrink: 0, - padding: isMobile && '5px', - fontSize: isMobile && '14px', + fontSize: '14px', + marginTop: 'auto', + padding: '5px', }} > {` Close`}
)} + { if (isSending) return; publishAnnouncement(); }} style={{ - marginTop: 'auto', alignSelf: 'center', + background: isSending + ? theme.palette.background.default + : theme.palette.background.paper, cursor: isSending ? 'default' : 'pointer', - background: isSending && 'rgba(0, 0, 0, 0.8)', flexShrink: 0, - padding: isMobile && '5px', - fontSize: isMobile && '14px', + fontSize: '14px', + marginTop: 'auto', + padding: '5px', }} > {isSending && ( )} diff --git a/src/components/Chat/GroupForum.tsx b/src/components/Chat/GroupForum.tsx index d8dd7e5..b97b11c 100644 --- a/src/components/Chat/GroupForum.tsx +++ b/src/components/Chat/GroupForum.tsx @@ -1,19 +1,6 @@ -import React, { - useCallback, - useContext, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { GroupMail } from "../Group/Forum/GroupMail"; -import { MyContext, isMobile } from "../../App"; -import { getRootHeight } from "../../utils/mobile/mobileUtils"; - - - - - +import { useContext, useEffect, useState } from 'react'; +import { GroupMail } from '../Group/Forum/GroupMail'; +import { MyContext, isMobile } from '../../App'; export const GroupForum = ({ selectedGroup, @@ -23,12 +10,13 @@ export const GroupForum = ({ isAdmin, myAddress, hide, - defaultThread, + defaultThread, setDefaultThread, - isPrivate + isPrivate, }) => { - const { rootHeight } = useContext(MyContext); + const { rootHeight } = useContext(MyContext); const [isMoved, setIsMoved] = useState(false); + useEffect(() => { if (hide) { setTimeout(() => setIsMoved(true), 300); // Wait for the fade-out to complete before moving @@ -39,20 +27,27 @@ export const GroupForum = ({ return (
- - -
+ style={{ + display: 'flex', + flexDirection: 'column', + height: 'calc(100vh - 70px)', + left: hide && '-1000px', + opacity: hide ? 0 : 1, + position: hide ? 'fixed' : 'relative', + visibility: hide && 'hidden', + width: '100%', + }} + > + +
); }; diff --git a/src/components/Chat/MentionList.tsx b/src/components/Chat/MentionList.tsx index 85f6890..06cea5c 100644 --- a/src/components/Chat/MentionList.tsx +++ b/src/components/Chat/MentionList.tsx @@ -1,69 +1,68 @@ -import React, { - forwardRef, useEffect, useImperativeHandle, - useState, - } from 'react' - - export default forwardRef((props, ref) => { - const [selectedIndex, setSelectedIndex] = useState(0) - - const selectItem = index => { - const item = props.items[index] - - if (item) { - props.command(item) +import { forwardRef, useEffect, useImperativeHandle, useState } from 'react'; + +export default forwardRef((props, ref) => { + const [selectedIndex, setSelectedIndex] = useState(0); + + const selectItem = (index) => { + const item = props.items[index]; + + if (item) { + props.command(item); + } + }; + + const upHandler = () => { + setSelectedIndex( + (selectedIndex + props.items.length - 1) % props.items.length + ); + }; + + const downHandler = () => { + setSelectedIndex((selectedIndex + 1) % props.items.length); + }; + + const enterHandler = () => { + selectItem(selectedIndex); + }; + + useEffect(() => setSelectedIndex(0), [props.items]); + + useImperativeHandle(ref, () => ({ + onKeyDown: ({ event }) => { + if (event.key === 'ArrowUp') { + upHandler(); + return true; } - } - - const upHandler = () => { - setSelectedIndex((selectedIndex + props.items.length - 1) % props.items.length) - } - - const downHandler = () => { - setSelectedIndex((selectedIndex + 1) % props.items.length) - } - - const enterHandler = () => { - selectItem(selectedIndex) - } - - useEffect(() => setSelectedIndex(0), [props.items]) - - useImperativeHandle(ref, () => ({ - onKeyDown: ({ event }) => { - if (event.key === 'ArrowUp') { - upHandler() - return true - } - - if (event.key === 'ArrowDown') { - downHandler() - return true - } - - if (event.key === 'Enter') { - enterHandler() - return true - } - - return false - }, - })) - - return ( -
- {props.items.length - ? props.items.map((item, index) => ( - - )) - :
No result
- } -
- ) - }) - \ No newline at end of file + + if (event.key === 'ArrowDown') { + downHandler(); + return true; + } + + if (event.key === 'Enter') { + enterHandler(); + return true; + } + + return false; + }, + })); + + return ( +
+ {props.items.length ? ( + props.items.map((item, index) => ( + + )) + ) : ( +
No result
+ )} +
+ ); +}); diff --git a/src/components/Chat/ResizableImage.tsx b/src/components/Chat/ResizableImage.tsx index 8c29292..881c1d7 100644 --- a/src/components/Chat/ResizableImage.tsx +++ b/src/components/Chat/ResizableImage.tsx @@ -1,8 +1,10 @@ -import React, { useRef } from 'react'; +import { useRef } from 'react'; import { NodeViewWrapper } from '@tiptap/react'; +import { useTheme } from '@mui/material'; const ResizableImage = ({ node, updateAttributes, selected }) => { const imgRef = useRef(null); + const theme = useTheme(); const startResizing = (e) => { e.preventDefault(); @@ -40,18 +42,23 @@ const ResizableImage = ({ node, updateAttributes, selected }) => { src={node.attrs.src} alt={node.attrs.alt || ''} title={node.attrs.title || ''} - style={{ width: node.attrs.width || 'auto', display: 'block', margin: '0 auto' }} + style={{ + width: node.attrs.width || 'auto', + display: 'block', + margin: '0 auto', + }} draggable={false} // Prevent image dragging /> +