mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
172 lines
4.6 KiB
TypeScript
172 lines
4.6 KiB
TypeScript
import { useMemo, useRef } from 'react';
|
|
import styled from 'styled-components';
|
|
import { isUsAnySogsFromCache } from '../../../../session/apis/open_group_api/sogsv3/knownBlindedkeys';
|
|
import { UserUtils } from '../../../../session/utils';
|
|
import {
|
|
useIsMessageSelectionMode,
|
|
useSelectedIsLegacyGroup,
|
|
} from '../../../../state/selectors/selectedConversation';
|
|
import { SortedReactionList } from '../../../../types/Reaction';
|
|
import { abbreviateNumber } from '../../../../util/numbers';
|
|
import { nativeEmojiData } from '../../../../util/emoji';
|
|
import { ReactionPopup } from './ReactionPopup';
|
|
import { SessionTooltip } from '../../../SessionTooltip';
|
|
|
|
const StyledReaction = styled.button<{
|
|
selected: boolean;
|
|
$showCount: boolean;
|
|
}>`
|
|
display: flex;
|
|
justify-content: ${props => (props.$showCount ? 'flex-start' : 'center')};
|
|
align-items: center;
|
|
|
|
background-color: var(--message-bubbles-received-background-color);
|
|
box-shadow: 0 0 0 1px
|
|
${props => (props.selected ? 'var(--primary-color)' : 'var(--transparent-color)')};
|
|
border-radius: var(--border-radius-message-box);
|
|
box-sizing: border-box;
|
|
padding: 0 7px;
|
|
margin: 0 4px var(--margins-sm);
|
|
height: 24px;
|
|
min-width: ${props => (props.$showCount ? '48px' : '24px')};
|
|
|
|
span {
|
|
width: 100%;
|
|
}
|
|
|
|
${props => !props.onClick && 'cursor: not-allowed;'}
|
|
`;
|
|
|
|
const StyledReactionContainer = styled.div<{
|
|
$inModal: boolean;
|
|
}>`
|
|
position: relative;
|
|
${props => props.$inModal && 'white-space: nowrap; margin-right: 8px;'}
|
|
`;
|
|
|
|
export type ReactionProps = {
|
|
emoji: string;
|
|
messageId: string;
|
|
reactions: SortedReactionList;
|
|
inModal: boolean;
|
|
inGroup: boolean;
|
|
onClick?: (emoji: string) => void;
|
|
onSelected?: (emoji: string) => boolean;
|
|
handlePopupReaction?: (emoji: string) => void;
|
|
handlePopupClick?: (emoji: string) => void;
|
|
};
|
|
|
|
export const Reaction = (props: ReactionProps) => {
|
|
const {
|
|
emoji,
|
|
messageId,
|
|
reactions,
|
|
inModal,
|
|
inGroup,
|
|
onClick,
|
|
onSelected,
|
|
handlePopupReaction,
|
|
handlePopupClick,
|
|
} = props;
|
|
|
|
const isMessageSelection = useIsMessageSelectionMode();
|
|
const reactionsMap = useMemo(
|
|
() => (reactions && Object.fromEntries(reactions)) || {},
|
|
[reactions]
|
|
);
|
|
const senders = reactionsMap[emoji]?.senders || [];
|
|
const count = reactionsMap[emoji]?.count;
|
|
const showCount = count !== undefined && (count > 1 || inGroup);
|
|
|
|
const reactionRef = useRef<HTMLDivElement>(null);
|
|
|
|
const isLegacyGroup = useSelectedIsLegacyGroup();
|
|
|
|
const me = UserUtils.getOurPubKeyStrFromCache();
|
|
const isBlindedMe =
|
|
senders && senders.length > 0 && senders.filter(isUsAnySogsFromCache).length > 0;
|
|
|
|
const selected = () => {
|
|
if (onSelected) {
|
|
return onSelected(emoji);
|
|
}
|
|
|
|
return senders && senders.length > 0 && (senders.includes(me) || isBlindedMe);
|
|
};
|
|
|
|
const handleReactionClick = () => {
|
|
if (!isMessageSelection) {
|
|
// Note: disable emoji clicks if the legacy group is deprecated (group is readonly)
|
|
if (onClick && !isLegacyGroup) {
|
|
onClick(emoji);
|
|
}
|
|
}
|
|
};
|
|
|
|
const renderTooltip = inGroup && !inModal;
|
|
|
|
const content = useMemo(
|
|
() =>
|
|
renderTooltip ? (
|
|
<ReactionPopup
|
|
messageId={messageId}
|
|
emoji={emoji}
|
|
count={reactionsMap[emoji]?.count}
|
|
senders={reactionsMap[emoji]?.senders}
|
|
onClick={() => {
|
|
if (isLegacyGroup) {
|
|
return;
|
|
}
|
|
if (handlePopupReaction) {
|
|
handlePopupReaction('');
|
|
}
|
|
if (handlePopupClick) {
|
|
handlePopupClick(emoji);
|
|
}
|
|
}}
|
|
/>
|
|
) : null,
|
|
[
|
|
emoji,
|
|
handlePopupClick,
|
|
handlePopupReaction,
|
|
isLegacyGroup,
|
|
messageId,
|
|
reactionsMap,
|
|
renderTooltip,
|
|
]
|
|
);
|
|
|
|
const reactionContainer = (
|
|
<StyledReactionContainer ref={reactionRef} $inModal={inModal}>
|
|
<StyledReaction
|
|
$showCount={showCount}
|
|
selected={selected()}
|
|
onClick={handleReactionClick}
|
|
onMouseEnter={() => handlePopupReaction?.(emoji)}
|
|
>
|
|
<span
|
|
role={'img'}
|
|
aria-label={nativeEmojiData?.ariaLabels ? nativeEmojiData.ariaLabels[emoji] : undefined}
|
|
>
|
|
{emoji}
|
|
{showCount && `\u00A0\u00A0${abbreviateNumber(count)}`}
|
|
</span>
|
|
</StyledReaction>
|
|
</StyledReactionContainer>
|
|
);
|
|
|
|
return renderTooltip ? (
|
|
<SessionTooltip
|
|
horizontalPosition="right"
|
|
debounceTimeout={50}
|
|
content={content}
|
|
maxContentWidth={'270px'}
|
|
>
|
|
{reactionContainer}
|
|
</SessionTooltip>
|
|
) : (
|
|
reactionContainer
|
|
);
|
|
};
|