mirror of
https://github.com/Qortal/qortal-mobile.git
synced 2025-03-26 23:44:35 +00:00
added reply
This commit is contained in:
parent
c8fb4974a7
commit
bcf22ca5e0
@ -129,7 +129,7 @@ const defaultValues: MyContextInterface = {
|
|||||||
message: "",
|
message: "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export let isMobile = false
|
export let isMobile = true
|
||||||
|
|
||||||
const isMobileDevice = () => {
|
const isMobileDevice = () => {
|
||||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
||||||
|
@ -1622,17 +1622,22 @@ async function sendChatDirect({
|
|||||||
...(otherData || {})
|
...(otherData || {})
|
||||||
};
|
};
|
||||||
const messageStringified = JSON.stringify(finalJson);
|
const messageStringified = JSON.stringify(finalJson);
|
||||||
const tx = await createTransaction(18, keyPair, {
|
console.log('chatReferencefinal', chatReference)
|
||||||
|
const txBody = {
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
recipient: recipientAddress,
|
recipient: recipientAddress,
|
||||||
recipientPublicKey: recipientPublicKey,
|
recipientPublicKey: recipientPublicKey,
|
||||||
hasChatReference: 0,
|
hasChatReference: chatReference ? 1 : 0,
|
||||||
message: messageStringified,
|
message: messageStringified,
|
||||||
lastReference: reference,
|
lastReference: reference,
|
||||||
proofOfWorkNonce: 0,
|
proofOfWorkNonce: 0,
|
||||||
isEncrypted: 1,
|
isEncrypted: 1,
|
||||||
isText: 1,
|
isText: 1,
|
||||||
});
|
}
|
||||||
|
if(chatReference){
|
||||||
|
txBody['chatReference'] = chatReference
|
||||||
|
}
|
||||||
|
const tx = await createTransaction(18, keyPair, txBody);
|
||||||
|
|
||||||
// if (!hasEnoughBalance) {
|
// if (!hasEnoughBalance) {
|
||||||
// throw new Error("Must have at least 4 QORT to send a chat message");
|
// throw new Error("Must have at least 4 QORT to send a chat message");
|
||||||
@ -4000,7 +4005,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
address,
|
address,
|
||||||
otherData
|
otherData
|
||||||
} = request.payload;
|
} = request.payload;
|
||||||
|
console.log('chatReferencebg', chatReference)
|
||||||
sendChatDirect({
|
sendChatDirect({
|
||||||
directTo,
|
directTo,
|
||||||
chatReference,
|
chatReference,
|
||||||
|
@ -19,6 +19,7 @@ import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
|||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
import { ReturnIcon } from '../../assets/Icons/ReturnIcon';
|
import { ReturnIcon } from '../../assets/Icons/ReturnIcon';
|
||||||
import { ExitIcon } from '../../assets/Icons/ExitIcon';
|
import { ExitIcon } from '../../assets/Icons/ExitIcon';
|
||||||
|
import { MessageItem, ReplyPreview } from './MessageItem';
|
||||||
|
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
@ -41,12 +42,12 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
|||||||
const socketRef = useRef(null);
|
const socketRef = useRef(null);
|
||||||
const timeoutIdRef = useRef(null);
|
const timeoutIdRef = useRef(null);
|
||||||
const groupSocketTimeoutRef = useRef(null);
|
const groupSocketTimeoutRef = useRef(null);
|
||||||
|
const [replyMessage, setReplyMessage] = useState(null)
|
||||||
const setEditorRef = (editorInstance) => {
|
const setEditorRef = (editorInstance) => {
|
||||||
editorRef.current = editorInstance;
|
editorRef.current = editorInstance;
|
||||||
};
|
};
|
||||||
const publicKeyOfRecipientRef = useRef(null)
|
const publicKeyOfRecipientRef = useRef(null)
|
||||||
|
console.log({messages})
|
||||||
const getPublicKeyFunc = async (address)=> {
|
const getPublicKeyFunc = async (address)=> {
|
||||||
try {
|
try {
|
||||||
const publicKey = await getPublicKey(address)
|
const publicKey = await getPublicKey(address)
|
||||||
@ -219,6 +220,7 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
|||||||
|
|
||||||
const sendChatDirect = async ({ chatReference = undefined, messageText, otherData}: any, address, publicKeyOfRecipient, isNewChatVar)=> {
|
const sendChatDirect = async ({ chatReference = undefined, messageText, otherData}: any, address, publicKeyOfRecipient, isNewChatVar)=> {
|
||||||
try {
|
try {
|
||||||
|
console.log('chatReferencedirect', chatReference)
|
||||||
const directTo = isNewChatVar ? directToValue : address
|
const directTo = isNewChatVar ? directToValue : address
|
||||||
|
|
||||||
if(!directTo) return
|
if(!directTo) return
|
||||||
@ -282,6 +284,8 @@ const clearEditorContent = () => {
|
|||||||
|
|
||||||
const sendMessage = async ()=> {
|
const sendMessage = async ()=> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
||||||
if(+balance < 4) throw new Error('You need at least 4 QORT to send a message')
|
if(+balance < 4) throw new Error('You need at least 4 QORT to send a message')
|
||||||
if(isSending) return
|
if(isSending) return
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
@ -297,12 +301,20 @@ const clearEditorContent = () => {
|
|||||||
await sendChatDirect({ messageText: htmlContent}, null, null, true)
|
await sendChatDirect({ messageText: htmlContent}, null, null, true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let repliedTo = replyMessage?.signature
|
||||||
|
|
||||||
|
if (replyMessage?.chatReference) {
|
||||||
|
repliedTo = replyMessage?.chatReference
|
||||||
|
}
|
||||||
const otherData = {
|
const otherData = {
|
||||||
specialId: uid.rnd()
|
specialId: uid.rnd(),
|
||||||
|
repliedTo
|
||||||
}
|
}
|
||||||
const sendMessageFunc = async () => {
|
const sendMessageFunc = async () => {
|
||||||
await sendChatDirect({ messageText: htmlContent, otherData}, selectedDirect?.address, publicKeyOfRecipient, false)
|
await sendChatDirect({ chatReference: undefined, messageText: htmlContent, otherData}, selectedDirect?.address, publicKeyOfRecipient, false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add the function to the queue
|
// Add the function to the queue
|
||||||
const messageObj = {
|
const messageObj = {
|
||||||
@ -321,6 +333,7 @@ const clearEditorContent = () => {
|
|||||||
executeEvent("sent-new-message-group", {})
|
executeEvent("sent-new-message-group", {})
|
||||||
}, 150);
|
}, 150);
|
||||||
clearEditorContent()
|
clearEditorContent()
|
||||||
|
setReplyMessage(null)
|
||||||
}
|
}
|
||||||
// send chat message
|
// send chat message
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -337,6 +350,9 @@ const clearEditorContent = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onReply = useCallback((message)=> {
|
||||||
|
setReplyMessage(message)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -444,7 +460,7 @@ const clearEditorContent = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ChatList chatId={selectedDirect?.address} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>
|
<ChatList onReply={onReply} chatId={selectedDirect?.address} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>
|
||||||
|
|
||||||
|
|
||||||
<div style={{
|
<div style={{
|
||||||
@ -470,7 +486,24 @@ const clearEditorContent = () => {
|
|||||||
flexGrow: isMobile && 1,
|
flexGrow: isMobile && 1,
|
||||||
overflow: !isMobile && "auto",
|
overflow: !isMobile && "auto",
|
||||||
}}>
|
}}>
|
||||||
|
{replyMessage && (
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: '5px',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
width: '100%'
|
||||||
|
}}>
|
||||||
|
<ReplyPreview message={replyMessage} />
|
||||||
|
|
||||||
|
<ButtonBase
|
||||||
|
onClick={() => {
|
||||||
|
setReplyMessage(null)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ExitIcon />
|
||||||
|
</ButtonBase>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
<Tiptap isFocusedParent={isFocusedParent} setEditorRef={setEditorRef} onEnter={sendMessage} isChat disableEnter={isMobile ? true : false} setIsFocusedParent={setIsFocusedParent}/>
|
<Tiptap isFocusedParent={isFocusedParent} setEditorRef={setEditorRef} onEnter={sendMessage} isChat disableEnter={isMobile ? true : false} setIsFocusedParent={setIsFocusedParent}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,8 +15,10 @@ import { CustomizedSnackbars } from '../Snackbar/Snackbar'
|
|||||||
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from '../../constants/codes'
|
import { PUBLIC_NOTIFICATION_CODE_FIRST_SECRET_KEY } from '../../constants/codes'
|
||||||
import { useMessageQueue } from '../../MessageQueueContext'
|
import { useMessageQueue } from '../../MessageQueueContext'
|
||||||
import { executeEvent } from '../../utils/events'
|
import { executeEvent } from '../../utils/events'
|
||||||
import { Box } from '@mui/material'
|
import { Box, ButtonBase } from '@mui/material'
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
|
import { ReplyPreview } from './MessageItem'
|
||||||
|
import { ExitIcon } from '../../assets/Icons/ExitIcon'
|
||||||
|
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
@ -34,6 +36,7 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
|
|||||||
const [infoSnack, setInfoSnack] = React.useState(null);
|
const [infoSnack, setInfoSnack] = React.useState(null);
|
||||||
const hasInitialized = useRef(false)
|
const hasInitialized = useRef(false)
|
||||||
const [isFocusedParent, setIsFocusedParent] = useState(false);
|
const [isFocusedParent, setIsFocusedParent] = useState(false);
|
||||||
|
const [replyMessage, setReplyMessage] = useState(null)
|
||||||
|
|
||||||
const hasInitializedWebsocket = useRef(false)
|
const hasInitializedWebsocket = useRef(false)
|
||||||
const socketRef = useRef(null); // WebSocket reference
|
const socketRef = useRef(null); // WebSocket reference
|
||||||
@ -111,6 +114,7 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
|
|||||||
...item,
|
...item,
|
||||||
id: item.signature,
|
id: item.signature,
|
||||||
text: item?.decryptedData?.message || "",
|
text: item?.decryptedData?.message || "",
|
||||||
|
repliedTo: item?.decryptedData?.repliedTo,
|
||||||
unread: item?.sender === myAddress ? false : true
|
unread: item?.sender === myAddress ? false : true
|
||||||
}
|
}
|
||||||
} )
|
} )
|
||||||
@ -121,6 +125,7 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
|
|||||||
...item,
|
...item,
|
||||||
id: item.signature,
|
id: item.signature,
|
||||||
text: item?.decryptedData?.message || "",
|
text: item?.decryptedData?.message || "",
|
||||||
|
repliedTo: item?.decryptedData?.repliedTo,
|
||||||
unread: false
|
unread: false
|
||||||
}
|
}
|
||||||
} )
|
} )
|
||||||
@ -305,8 +310,15 @@ const clearEditorContent = () => {
|
|||||||
setIsSending(true)
|
setIsSending(true)
|
||||||
const message = htmlContent
|
const message = htmlContent
|
||||||
const secretKeyObject = await getSecretKey(false, true)
|
const secretKeyObject = await getSecretKey(false, true)
|
||||||
|
|
||||||
|
let repliedTo = replyMessage?.signature
|
||||||
|
|
||||||
|
if (replyMessage?.chatReference) {
|
||||||
|
repliedTo = replyMessage?.chatReference
|
||||||
|
}
|
||||||
const otherData = {
|
const otherData = {
|
||||||
specialId: uid.rnd()
|
specialId: uid.rnd(),
|
||||||
|
repliedTo
|
||||||
}
|
}
|
||||||
const objectMessage = {
|
const objectMessage = {
|
||||||
message,
|
message,
|
||||||
@ -338,6 +350,7 @@ const clearEditorContent = () => {
|
|||||||
executeEvent("sent-new-message-group", {})
|
executeEvent("sent-new-message-group", {})
|
||||||
}, 150);
|
}, 150);
|
||||||
clearEditorContent()
|
clearEditorContent()
|
||||||
|
setReplyMessage(null)
|
||||||
}
|
}
|
||||||
// send chat message
|
// send chat message
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -362,6 +375,9 @@ const clearEditorContent = () => {
|
|||||||
}
|
}
|
||||||
}, [hide]);
|
}, [hide]);
|
||||||
|
|
||||||
|
const onReply = useCallback((message)=> {
|
||||||
|
setReplyMessage(message)
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
@ -374,7 +390,7 @@ const clearEditorContent = () => {
|
|||||||
left: hide && '-100000px',
|
left: hide && '-100000px',
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
<ChatList chatId={selectedGroup} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>
|
<ChatList onReply={onReply} chatId={selectedGroup} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>
|
||||||
|
|
||||||
|
|
||||||
<div style={{
|
<div style={{
|
||||||
@ -400,7 +416,25 @@ const clearEditorContent = () => {
|
|||||||
flexGrow: isMobile && 1,
|
flexGrow: isMobile && 1,
|
||||||
overflow: !isMobile && "auto",
|
overflow: !isMobile && "auto",
|
||||||
}}>
|
}}>
|
||||||
|
{replyMessage && (
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: '5px',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
width: '100%'
|
||||||
|
}}>
|
||||||
|
<ReplyPreview message={replyMessage} />
|
||||||
|
|
||||||
|
<ButtonBase
|
||||||
|
onClick={() => {
|
||||||
|
setReplyMessage(null)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ExitIcon />
|
||||||
|
</ButtonBase>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
<Tiptap setEditorRef={setEditorRef} onEnter={sendMessage} isChat disableEnter={isMobile ? true : false} isFocusedParent={isFocusedParent} setIsFocusedParent={setIsFocusedParent} />
|
<Tiptap setEditorRef={setEditorRef} onEnter={sendMessage} isChat disableEnter={isMobile ? true : false} isFocusedParent={isFocusedParent} setIsFocusedParent={setIsFocusedParent} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@ import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
|||||||
// defaultHeight: 50,
|
// defaultHeight: 50,
|
||||||
// });
|
// });
|
||||||
|
|
||||||
export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId }) => {
|
export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId, onReply }) => {
|
||||||
|
|
||||||
const hasLoadedInitialRef = useRef(false);
|
const hasLoadedInitialRef = useRef(false);
|
||||||
const listRef = useRef();
|
const listRef = useRef();
|
||||||
@ -18,7 +18,7 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId }) =
|
|||||||
fixedWidth: true,
|
fixedWidth: true,
|
||||||
defaultHeight: 50,
|
defaultHeight: 50,
|
||||||
}), [chatId]); // Recreate cache when chatId changes
|
}), [chatId]); // Recreate cache when chatId changes
|
||||||
|
console.log('messages2', messages)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
cache.clearAll();
|
cache.clearAll();
|
||||||
}, []);
|
}, []);
|
||||||
@ -68,6 +68,10 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId }) =
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const scrollToItem = useCallback((index) => {
|
||||||
|
listRef.current.scrollToRow(index); // This scrolls to the specific index
|
||||||
|
}, []);
|
||||||
|
|
||||||
const recomputeListHeights = () => {
|
const recomputeListHeights = () => {
|
||||||
if (listRef.current) {
|
if (listRef.current) {
|
||||||
listRef.current.recomputeRowHeights();
|
listRef.current.recomputeRowHeights();
|
||||||
@ -93,7 +97,18 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId }) =
|
|||||||
let message = messages[index];
|
let message = messages[index];
|
||||||
const isLargeMessage = message.text?.length > 200; // Adjust based on your message size threshold
|
const isLargeMessage = message.text?.length > 200; // Adjust based on your message size threshold
|
||||||
|
|
||||||
|
// const reply = message?.repliedTo ? messages.find((msg)=> msg?.signature === message?.repliedTo) : undefined
|
||||||
|
let replyIndex = messages.findIndex((msg)=> msg?.signature === message?.repliedTo)
|
||||||
|
let reply
|
||||||
|
if(message?.repliedTo && replyIndex !== -1){
|
||||||
|
reply = messages[replyIndex]
|
||||||
|
}
|
||||||
if(message?.message && message?.groupDirectId){
|
if(message?.message && message?.groupDirectId){
|
||||||
|
replyIndex = messages.findIndex((msg)=> msg?.signature === message?.message?.repliedTo)
|
||||||
|
reply
|
||||||
|
if(message?.message?.repliedTo && replyIndex !== -1){
|
||||||
|
reply = messages[replyIndex]
|
||||||
|
}
|
||||||
message = {
|
message = {
|
||||||
...(message?.message || {}),
|
...(message?.message || {}),
|
||||||
isTemp: true,
|
isTemp: true,
|
||||||
@ -130,6 +145,10 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId }) =
|
|||||||
onSeen={handleMessageSeen}
|
onSeen={handleMessageSeen}
|
||||||
isTemp={!!message?.isTemp}
|
isTemp={!!message?.isTemp}
|
||||||
myAddress={myAddress}
|
myAddress={myAddress}
|
||||||
|
onReply={onReply}
|
||||||
|
reply={reply}
|
||||||
|
scrollToItem={scrollToItem}
|
||||||
|
replyIndex={replyIndex}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
|
|||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import './styles.css'; // Ensure this CSS file is imported
|
import './styles.css'; // Ensure this CSS file is imported
|
||||||
|
|
||||||
export const MessageDisplay = ({ htmlContent }) => {
|
export const MessageDisplay = ({ htmlContent , isReply}) => {
|
||||||
|
|
||||||
const linkify = (text) => {
|
const linkify = (text) => {
|
||||||
// Regular expression to find URLs starting with https://, http://, or www.
|
// Regular expression to find URLs starting with https://, http://, or www.
|
||||||
@ -53,7 +53,7 @@ export const MessageDisplay = ({ htmlContent }) => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="tiptap"
|
className={`tiptap ${isReply ? 'isReply' : ''}`}
|
||||||
dangerouslySetInnerHTML={{ __html: sanitizedContent }}
|
dangerouslySetInnerHTML={{ __html: sanitizedContent }}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
// Delegate click handling to the parent div
|
// Delegate click handling to the parent div
|
||||||
|
@ -2,18 +2,30 @@ import { Message } from "@chatscope/chat-ui-kit-react";
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useInView } from "react-intersection-observer";
|
import { useInView } from "react-intersection-observer";
|
||||||
import { MessageDisplay } from "./MessageDisplay";
|
import { MessageDisplay } from "./MessageDisplay";
|
||||||
import { Avatar, Box, Typography } from "@mui/material";
|
import { Avatar, Box, ButtonBase, Typography } from "@mui/material";
|
||||||
import { formatTimestamp } from "../../utils/time";
|
import { formatTimestamp } from "../../utils/time";
|
||||||
import { getBaseApi } from "../../background";
|
import { getBaseApi } from "../../background";
|
||||||
import { getBaseApiReact } from "../../App";
|
import { getBaseApiReact } from "../../App";
|
||||||
import { generateHTML } from "@tiptap/react";
|
import { generateHTML } from "@tiptap/react";
|
||||||
import Highlight from '@tiptap/extension-highlight'
|
import Highlight from "@tiptap/extension-highlight";
|
||||||
import StarterKit from '@tiptap/starter-kit'
|
import StarterKit from "@tiptap/starter-kit";
|
||||||
import Underline from '@tiptap/extension-underline'
|
import Underline from "@tiptap/extension-underline";
|
||||||
import { executeEvent } from "../../utils/events";
|
import { executeEvent } from "../../utils/events";
|
||||||
import { WrapperUserAction } from "../WrapperUserAction";
|
import { WrapperUserAction } from "../WrapperUserAction";
|
||||||
export const MessageItem = ({ message, onSeen, isLast, isTemp, myAddress }) => {
|
import ReplyIcon from "@mui/icons-material/Reply";
|
||||||
|
|
||||||
|
export const MessageItem = ({
|
||||||
|
message,
|
||||||
|
onSeen,
|
||||||
|
isLast,
|
||||||
|
isTemp,
|
||||||
|
myAddress,
|
||||||
|
onReply,
|
||||||
|
isShowingAsReply,
|
||||||
|
reply,
|
||||||
|
replyIndex,
|
||||||
|
scrollToItem
|
||||||
|
}) => {
|
||||||
const { ref, inView } = useInView({
|
const { ref, inView } = useInView({
|
||||||
threshold: 0.7, // Fully visible
|
threshold: 0.7, // Fully visible
|
||||||
triggerOnce: true, // Only trigger once when it becomes visible
|
triggerOnce: true, // Only trigger once when it becomes visible
|
||||||
@ -34,70 +46,169 @@ export const MessageItem = ({ message, onSeen, isLast, isTemp, myAddress }) => {
|
|||||||
borderRadius: "7px",
|
borderRadius: "7px",
|
||||||
width: "95%",
|
width: "95%",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
gap: '7px',
|
gap: "7px",
|
||||||
opacity: isTemp ? 0.5 : 1
|
opacity: isTemp ? 0.5 : 1,
|
||||||
}}
|
}}
|
||||||
|
id={message?.signature}
|
||||||
>
|
>
|
||||||
<WrapperUserAction disabled={myAddress === message?.sender} address={message?.sender} name={message?.senderName}>
|
{isShowingAsReply ? (
|
||||||
<Avatar
|
<ReplyIcon
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: '#27282c',
|
fontSize: "30px",
|
||||||
color: 'white'
|
}}
|
||||||
}}
|
/>
|
||||||
alt={message?.senderName}
|
) : (
|
||||||
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${message?.senderName}/qortal_avatar?async=true`}
|
<WrapperUserAction
|
||||||
>
|
disabled={myAddress === message?.sender}
|
||||||
{message?.senderName?.charAt(0)}
|
address={message?.sender}
|
||||||
</Avatar>
|
name={message?.senderName}
|
||||||
</WrapperUserAction>
|
>
|
||||||
|
<Avatar
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#27282c",
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
alt={message?.senderName}
|
||||||
|
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||||
|
message?.senderName
|
||||||
|
}/qortal_avatar?async=true`}
|
||||||
|
>
|
||||||
|
{message?.senderName?.charAt(0)}
|
||||||
|
</Avatar>
|
||||||
|
</WrapperUserAction>
|
||||||
|
)}
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: "7px",
|
gap: "7px",
|
||||||
width: '100%'
|
width: "100%",
|
||||||
|
height: isShowingAsReply && "40px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<WrapperUserAction disabled={myAddress === message?.sender} address={message?.sender} name={message?.senderName}>
|
<Box
|
||||||
<Typography
|
|
||||||
sx={{
|
sx={{
|
||||||
fontWight: 600,
|
display: "flex",
|
||||||
fontFamily: "Inter",
|
width: "100%",
|
||||||
color: "cadetBlue",
|
justifyContent: "space-between",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
>
|
>
|
||||||
{message?.senderName || message?.sender}
|
<WrapperUserAction
|
||||||
</Typography>
|
disabled={myAddress === message?.sender}
|
||||||
</WrapperUserAction>
|
address={message?.sender}
|
||||||
|
name={message?.senderName}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontWight: 600,
|
||||||
|
fontFamily: "Inter",
|
||||||
|
color: "cadetBlue",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{message?.senderName || message?.sender}
|
||||||
|
</Typography>
|
||||||
|
</WrapperUserAction>
|
||||||
|
{!isShowingAsReply && (
|
||||||
|
<ButtonBase
|
||||||
|
onClick={() => {
|
||||||
|
onReply(message);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ReplyIcon />
|
||||||
|
</ButtonBase>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{reply && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: "5px",
|
||||||
|
backgroundColor: "var(--bg-primary)",
|
||||||
|
overflow: 'hidden',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '20px',
|
||||||
|
maxHeight: '90px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
onClick={()=> {
|
||||||
|
scrollToItem(replyIndex)
|
||||||
|
|
||||||
|
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{
|
||||||
|
height: '100%',
|
||||||
|
width: '5px',
|
||||||
|
background: 'white'
|
||||||
|
}} />
|
||||||
|
<Box sx={{
|
||||||
|
padding: '5px'
|
||||||
|
}}>
|
||||||
|
<Typography sx={{
|
||||||
|
fontSize: '12px',
|
||||||
|
fontWeight: 600
|
||||||
|
}}>Replied to {reply?.senderName || reply?.senderAddress}</Typography>
|
||||||
|
{reply?.messageText && (
|
||||||
|
<MessageDisplay
|
||||||
|
htmlContent={generateHTML(reply?.messageText, [
|
||||||
|
StarterKit,
|
||||||
|
Underline,
|
||||||
|
Highlight,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{reply?.text?.type === "notification" ? (
|
||||||
|
<MessageDisplay htmlContent={reply.text?.data?.message} />
|
||||||
|
) : (
|
||||||
|
<MessageDisplay isReply htmlContent={reply.text} />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
{message?.messageText && (
|
{message?.messageText && (
|
||||||
<MessageDisplay htmlContent={generateHTML(message?.messageText, [StarterKit, Underline, Highlight])} />
|
<MessageDisplay
|
||||||
|
htmlContent={generateHTML(message?.messageText, [
|
||||||
|
StarterKit,
|
||||||
|
Underline,
|
||||||
|
Highlight,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{message?.text?.type === "notification" ? (
|
{message?.text?.type === "notification" ? (
|
||||||
<MessageDisplay htmlContent={message.text?.data?.message} />
|
<MessageDisplay htmlContent={message.text?.data?.message} />
|
||||||
) : (
|
) : (
|
||||||
<MessageDisplay htmlContent={message.text} />
|
<MessageDisplay htmlContent={message.text} />
|
||||||
)}
|
)}
|
||||||
<Box sx={{
|
<Box
|
||||||
display: 'flex',
|
sx={{
|
||||||
justifyContent: 'flex-end',
|
display: "flex",
|
||||||
width: '100%',
|
justifyContent: "flex-end",
|
||||||
|
width: "100%",
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{isTemp ? (
|
{isTemp ? (
|
||||||
<Typography sx={{
|
<Typography
|
||||||
fontSize: '14px',
|
sx={{
|
||||||
color: 'gray',
|
fontSize: "14px",
|
||||||
fontFamily: 'Inter'
|
color: "gray",
|
||||||
}}>Sending...</Typography>
|
fontFamily: "Inter",
|
||||||
): (
|
}}
|
||||||
<Typography sx={{
|
>
|
||||||
fontSize: '14px',
|
Sending...
|
||||||
color: 'gray',
|
</Typography>
|
||||||
fontFamily: 'Inter'
|
) : (
|
||||||
}}>{formatTimestamp(message.timestamp)}</Typography>
|
<Typography
|
||||||
) }
|
sx={{
|
||||||
|
fontSize: "14px",
|
||||||
|
color: "gray",
|
||||||
|
fontFamily: "Inter",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{formatTimestamp(message.timestamp)}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@ -115,3 +226,51 @@ export const MessageItem = ({ message, onSeen, isLast, isTemp, myAddress }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const ReplyPreview = ({message})=> {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: "5px",
|
||||||
|
backgroundColor: "var(--bg-primary)",
|
||||||
|
overflow: 'hidden',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '20px',
|
||||||
|
maxHeight: '90px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{
|
||||||
|
height: '100%',
|
||||||
|
width: '5px',
|
||||||
|
background: 'white'
|
||||||
|
}} />
|
||||||
|
<Box sx={{
|
||||||
|
padding: '5px'
|
||||||
|
}}>
|
||||||
|
<Typography sx={{
|
||||||
|
fontSize: '12px',
|
||||||
|
fontWeight: 600
|
||||||
|
}}>Replied to {message?.senderName || message?.senderAddress}</Typography>
|
||||||
|
{message?.messageText && (
|
||||||
|
<MessageDisplay
|
||||||
|
htmlContent={generateHTML(message?.messageText, [
|
||||||
|
StarterKit,
|
||||||
|
Underline,
|
||||||
|
Highlight,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{message?.text?.type === "notification" ? (
|
||||||
|
<MessageDisplay htmlContent={message.text?.data?.message} />
|
||||||
|
) : (
|
||||||
|
<MessageDisplay isReply htmlContent={message.text} />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
@ -120,3 +120,6 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.isReply p {
|
||||||
|
font-size: 12px !important;
|
||||||
|
}
|
||||||
|
@ -31,6 +31,7 @@ const IconWrapper = ({ children, label, color }) => {
|
|||||||
fontSize: "12px",
|
fontSize: "12px",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
color: color,
|
color: color,
|
||||||
|
wordBreak: 'normal'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user