import { Theme } from '@mui/material'; import React, { useCallback, useMemo, useState } from 'react'; import { connect } from 'react-redux'; import { makeStyles } from 'tss-react/mui'; import { IReduxState } from '../../../app/types'; import { translate } from '../../../base/i18n/functions'; import { getParticipantById, getParticipantDisplayName, isPrivateChatEnabled } from '../../../base/participants/functions'; import Popover from '../../../base/popover/components/Popover.web'; import Message from '../../../base/react/components/web/Message'; import { MESSAGE_TYPE_LOCAL } from '../../constants'; import { getFormattedTimestamp, getMessageText, getPrivateNoticeMessage } from '../../functions'; import { IChatMessageProps } from '../../types'; import MessageMenu from './MessageMenu'; import ReactButton from './ReactButton'; interface IProps extends IChatMessageProps { className?: string; enablePrivateChat?: boolean; shouldDisplayMenuOnRight?: boolean; state?: IReduxState; } const useStyles = makeStyles()((theme: Theme) => { return { chatMessageFooter: { display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginTop: theme.spacing(1) }, chatMessageFooterLeft: { display: 'flex', flexGrow: 1, overflow: 'hidden' }, chatMessageWrapper: { maxWidth: '100%' }, chatMessage: { display: 'inline-flex', padding: '12px', backgroundColor: theme.palette.ui02, borderRadius: '4px 12px 12px 12px', maxWidth: '100%', marginTop: '4px', boxSizing: 'border-box' as const, '&.privatemessage': { backgroundColor: theme.palette.support05 }, '&.local': { backgroundColor: theme.palette.ui04, borderRadius: '12px 4px 12px 12px', '&.privatemessage': { backgroundColor: theme.palette.support05 }, '&.local': { backgroundColor: theme.palette.ui04, borderRadius: '12px 4px 12px 12px', '&.privatemessage': { backgroundColor: theme.palette.support05 } }, '&.error': { backgroundColor: theme.palette.actionDanger, borderRadius: 0, fontWeight: 100 }, '&.lobbymessage': { backgroundColor: theme.palette.support05 } }, '&.error': { backgroundColor: theme.palette.actionDanger, borderRadius: 0, fontWeight: 100 }, '&.lobbymessage': { backgroundColor: theme.palette.support05 } }, sideBySideContainer: { display: 'flex', flexDirection: 'row', justifyContent: 'left', alignItems: 'center', marginLeft: theme.spacing(1) }, reactionBox: { display: 'flex', alignItems: 'center', gap: theme.spacing(1), backgroundColor: theme.palette.grey[800], borderRadius: theme.shape.borderRadius, padding: theme.spacing(0, 1), cursor: 'pointer' }, reactionCount: { fontSize: '0.8rem', color: theme.palette.grey[400] }, replyButton: { padding: '2px' }, replyWrapper: { display: 'flex', flexDirection: 'row' as const, alignItems: 'center', maxWidth: '100%' }, messageContent: { maxWidth: '100%', overflow: 'hidden', flex: 1 }, optionsButtonContainer: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: theme.spacing(1), minWidth: '32px', minHeight: '32px' }, displayName: { ...theme.typography.labelBold, color: theme.palette.text02, whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden', marginBottom: theme.spacing(1), maxWidth: '130px' }, userMessage: { ...theme.typography.bodyShortRegular, color: theme.palette.text01, whiteSpace: 'pre-wrap', wordBreak: 'break-word' }, privateMessageNotice: { ...theme.typography.labelRegular, color: theme.palette.text02, marginTop: theme.spacing(1) }, timestamp: { ...theme.typography.labelRegular, color: theme.palette.text03, marginTop: theme.spacing(1), marginLeft: theme.spacing(1), whiteSpace: 'nowrap', flexShrink: 0 }, reactionsPopover: { padding: theme.spacing(2), backgroundColor: theme.palette.ui03, borderRadius: theme.shape.borderRadius, maxWidth: '150px', maxHeight: '400px', overflowY: 'auto', color: theme.palette.text01 }, reactionItem: { display: 'flex', alignItems: 'center', marginBottom: theme.spacing(1), gap: theme.spacing(1), borderBottom: `1px solid ${theme.palette.common.white}`, paddingBottom: theme.spacing(1), '&:last-child': { borderBottom: 'none', paddingBottom: 0 } }, participantList: { marginLeft: theme.spacing(1), fontSize: '0.8rem', maxWidth: '120px' }, participant: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }; }); const ChatMessage = ({ className = '', message, state, showDisplayName, shouldDisplayMenuOnRight, enablePrivateChat, knocking, t }: IProps) => { const { classes, cx } = useStyles(); const [ isHovered, setIsHovered ] = useState(false); const [ isReactionsOpen, setIsReactionsOpen ] = useState(false); const handleMouseEnter = useCallback(() => { setIsHovered(true); }, []); const handleMouseLeave = useCallback(() => { setIsHovered(false); }, []); const handleReactionsOpen = useCallback(() => { setIsReactionsOpen(true); }, []); const handleReactionsClose = useCallback(() => { setIsReactionsOpen(false); }, []); /** * Renders the display name of the sender. * * @returns {React$Element<*>} */ function _renderDisplayName() { const { displayName, isFromVisitor = false } = message; return (
{getFormattedTimestamp(message)}
{reaction} {participants.size}
{state && getParticipantDisplayName(state, participantId)}
))}{reaction}
)} {reactionsArray.length > numReactionsDisplayed && (+{totalReactions - numReactionsDisplayed}
)}