import { isEmpty, isEqual } from 'lodash'; import React, { ReactElement, useEffect, useState } from 'react'; import styled from 'styled-components'; import { useMessageReactsPropsById } from '../../../../hooks/useParamSelector'; import { MessageRenderingProps } from '../../../../models/messageType'; import { REACT_LIMIT } from '../../../../session/constants'; import { useSelectedIsGroup } from '../../../../state/selectors/selectedConversation'; import { SortedReactionList } from '../../../../types/Reaction'; import { nativeEmojiData } from '../../../../util/emoji'; import { Flex } from '../../../basic/Flex'; import { SessionIcon } from '../../../icon'; import { Reaction, ReactionProps } from '../reactions/Reaction'; import { StyledPopupContainer } from '../reactions/ReactionPopup'; export const popupXDefault = -81; export const popupYDefault = -90; export const StyledMessageReactionsContainer = styled(Flex)<{ x: number; y: number; noAvatar: boolean; }>` ${StyledPopupContainer} { position: absolute; top: ${props => `${props.y}px;`}; left: ${props => `${props.x}px;`}; } // MessageAvatar width + margin-inline-end ${props => !props.noAvatar && 'margin-inline-start: calc(36px + 20px);'} `; export const StyledMessageReactions = styled(Flex)<{ fullWidth: boolean }>` ${props => (props.fullWidth ? '' : 'max-width: 640px;')} `; const StyledReactionOverflow = styled.button` display: flex; flex-direction: row-reverse; justify-content: flex-start; align-items: center; border: none; margin-right: 4px; margin-bottom: var(--margins-sm); span { background-color: var(--message-bubbles-received-background-color); border: 1px solid var(--border-color); border-radius: 50%; overflow: hidden; margin-right: -9px; padding: 1px 4.5px; } `; const StyledReadLess = styled.span` font-size: var(--font-size-xs); margin-top: 8px; cursor: pointer; svg { margin-right: 5px; } `; type ReactionsProps = Omit; const Reactions = (props: ReactionsProps): ReactElement => { const { messageId, reactions, inModal } = props; return ( {reactions.map(([emoji, _]) => ( ))} ); }; interface ExpandReactionsProps extends ReactionsProps { handleExpand: () => void; } const CompressedReactions = (props: ExpandReactionsProps): ReactElement => { const { messageId, reactions, inModal, handleExpand } = props; return ( {reactions.slice(0, 4).map(([emoji, _]) => ( ))} {reactions .slice(4, 7) .reverse() .map(([emoji, _]) => { return ( {emoji} ); })} ); }; const ExpandedReactions = (props: ExpandReactionsProps): ReactElement => { const { handleExpand } = props; return ( {window.i18n('expandedReactionsText')} ); }; export type MessageReactsSelectorProps = Pick< MessageRenderingProps, 'convoId' | 'serverId' | 'reacts' | 'sortedReacts' >; type Props = { messageId: string; hasReactLimit?: boolean; onClick: (emoji: string) => void; popupReaction?: string; setPopupReaction?: (emoji: string) => void; onPopupClick?: () => void; inModal?: boolean; onSelected?: (emoji: string) => boolean; noAvatar: boolean; isDetailView?: boolean; }; export const MessageReactions = (props: Props) => { const { messageId, hasReactLimit = true, onClick, popupReaction, setPopupReaction, onPopupClick, inModal = false, onSelected, noAvatar, isDetailView, } = props; const [reactions, setReactions] = useState([]); const [isExpanded, setIsExpanded] = useState(false); const handleExpand = () => { setIsExpanded(!isExpanded); }; const [popupX, setPopupX] = useState(popupXDefault); const [popupY, setPopupY] = useState(popupYDefault); const msgProps = useMessageReactsPropsById(messageId); const inGroup = useSelectedIsGroup(); useEffect(() => { if (msgProps?.sortedReacts && !isEqual(reactions, msgProps?.sortedReacts)) { setReactions(msgProps?.sortedReacts); } if (!isEmpty(reactions) && isEmpty(msgProps?.sortedReacts)) { setReactions([]); } }, [msgProps?.sortedReacts, reactions]); if (!msgProps) { return null; } const { sortedReacts } = msgProps; if (!sortedReacts || !sortedReacts.length) { return null; } const reactionsProps = { messageId, reactions, inModal, inGroup, handlePopupX: setPopupX, handlePopupY: setPopupY, onClick: !isDetailView ? onClick : undefined, popupReaction, onSelected, handlePopupReaction: !isDetailView ? setPopupReaction : undefined, handlePopupClick: onPopupClick, }; const ExtendedReactions = isExpanded ? ExpandedReactions : CompressedReactions; return ( {sortedReacts && sortedReacts?.length !== 0 && (!hasReactLimit || sortedReacts.length <= REACT_LIMIT ? ( ) : ( ))} ); };