import { Message } from "@chatscope/chat-ui-kit-react"; import React, { useCallback, useContext, useEffect, useMemo, useState } from "react"; import { useInView } from "react-intersection-observer"; import { MessageDisplay } from "./MessageDisplay"; import { Avatar, Box, Button, ButtonBase, List, ListItem, ListItemText, Popover, Tooltip, Typography } from "@mui/material"; import { formatTimestamp } from "../../utils/time"; import { getBaseApi } from "../../background"; import { MyContext, getBaseApiReact } from "../../App"; import { generateHTML } from "@tiptap/react"; import Highlight from "@tiptap/extension-highlight"; import Mention from "@tiptap/extension-mention"; import StarterKit from "@tiptap/starter-kit"; import Underline from "@tiptap/extension-underline"; import { executeEvent } from "../../utils/events"; import { WrapperUserAction } from "../WrapperUserAction"; import ReplyIcon from "@mui/icons-material/Reply"; import { Spacer } from "../../common/Spacer"; import { ReactionPicker } from "../ReactionPicker"; import KeyOffIcon from '@mui/icons-material/KeyOff'; import EditIcon from '@mui/icons-material/Edit'; import TextStyle from '@tiptap/extension-text-style'; import { addressInfoKeySelector } from "../../atoms/global"; import { useRecoilValue } from "recoil"; import level0Img from "../../assets/badges/level-0.png" import level1Img from "../../assets/badges/level-1.png" import level2Img from "../../assets/badges/level-2.png" import level3Img from "../../assets/badges/level-3.png" import level4Img from "../../assets/badges/level-4.png" import level5Img from "../../assets/badges/level-5.png" import level6Img from "../../assets/badges/level-6.png" import level7Img from "../../assets/badges/level-7.png" import level8Img from "../../assets/badges/level-8.png" import level9Img from "../../assets/badges/level-9.png" import level10Img from "../../assets/badges/level-10.png" const getBadgeImg = (level)=> { switch(level?.toString()){ case '0': return level0Img case '1': return level1Img case '2': return level2Img case '3': return level3Img case '4': return level4Img case '5': return level5Img case '6': return level6Img case '7': return level7Img case '8': return level8Img case '9': return level9Img case '10': return level10Img default: return level0Img } } export const MessageItem = React.memo(({ message, onSeen, isLast, isTemp, myAddress, onReply, isShowingAsReply, reply, replyIndex, scrollToItem, handleReaction, reactions, isUpdating, lastSignature, onEdit, isPrivate }) => { const {getIndividualUserInfo} = useContext(MyContext) const [anchorEl, setAnchorEl] = useState(null); const [selectedReaction, setSelectedReaction] = useState(null); const [userInfo, setUserInfo] = useState(null) useEffect(()=> { const getInfo = async ()=> { if(!message?.sender) return try { const res = await getIndividualUserInfo(message?.sender) if(!res) return null setUserInfo(res) } catch (error) { // } } getInfo() }, [message?.sender, getIndividualUserInfo]) const htmlText = useMemo(()=> { if(message?.messageText){ return generateHTML(message?.messageText, [ StarterKit, Underline, Highlight, Mention, TextStyle ]) } }, []) const htmlReply = useMemo(()=> { if(reply?.messageText){ return generateHTML(reply?.messageText, [ StarterKit, Underline, Highlight, Mention, TextStyle ]) } }, []) const userAvatarUrl = useMemo(()=> { return message?.senderName ? `${getBaseApiReact()}/arbitrary/THUMBNAIL/${ message?.senderName }/qortal_avatar?async=true` : '' }, []) const onSeenFunc = useCallback(()=> { onSeen(message.id); }, [message?.id]) return ( <> {message?.divide && (
Unread messages below
)}
{isShowingAsReply ? ( ) : ( {message?.senderName?.charAt(0)} )} {message?.senderName || message?.sender} {message?.sender === myAddress && (!message?.isNotEncrypted || isPrivate === false) && ( { onEdit(message); }} > )} {!isShowingAsReply && ( { onReply(message); }} > )} {!isShowingAsReply && handleReaction && ( { if(reactions && reactions[val] && reactions[val]?.find((item)=> item?.sender === myAddress)){ handleReaction(val, message, false) } else { handleReaction(val, message, true) } }} /> )} {reply && ( <> { scrollToItem(replyIndex) }} > Replied to {reply?.senderName || reply?.senderAddress} {reply?.messageText && ( )} {reply?.decryptedData?.type === "notification" ? ( ) : ( )} )} {htmlText && ( )} {message?.decryptedData?.type === "notification" ? ( ) : ( )} {reactions && Object.keys(reactions).map((reaction)=> { const numberOfReactions = reactions[reaction]?.length // const myReaction = reactions if(numberOfReactions === 0) return null return ( { event.stopPropagation(); // Prevent event bubbling setAnchorEl(event.currentTarget); setSelectedReaction(reaction); }}>
{reaction}
{numberOfReactions > 1 && ( {' '} {numberOfReactions} )}
) })}
{selectedReaction && ( { setAnchorEl(null); setSelectedReaction(null); }} anchorOrigin={{ vertical: "top", horizontal: "center", }} transformOrigin={{ vertical: "bottom", horizontal: "center", }} PaperProps={{ style: { backgroundColor: "#232428", color: "white", }, }} > People who reacted with {selectedReaction} {reactions[selectedReaction]?.map((reactionItem) => ( ))} )} {message?.isNotEncrypted && isPrivate && ( )} {isUpdating ? ( {message?.status === 'failed-permanent' ? 'Failed to update' : 'Updating...'} ) : isTemp ? ( {message?.status === 'failed-permanent' ? 'Failed to send' : 'Sending...'} ) : ( <> {message?.isEdit && ( Edited )} {formatTimestamp(message.timestamp)} )}
); }); export const ReplyPreview = ({message, isEdit})=> { return ( {isEdit ? ( Editing Message ) : ( Replied to {message?.senderName || message?.senderAddress} )} {message?.messageText && ( )} {message?.decryptedData?.type === "notification" ? ( ) : ( )} ) } const MessageWragger = ({lastMessage, onSeen, isLast, children})=> { if(lastMessage){ return ( {children} ) } return children } const WatchComponent = ({onSeen, isLast, children})=> { const { ref, inView } = useInView({ threshold: 0.7, // Fully visible triggerOnce: true, // Only trigger once when it becomes visible }); useEffect(() => { if (inView && isLast && onSeen) { onSeen(); } }, [inView, isLast, onSeen]); return
{children}
}