You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
4.6 KiB
TypeScript
170 lines
4.6 KiB
TypeScript
import classNames from 'classnames';
|
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
import { contextMenu } from 'react-contexify';
|
|
import { useSelector } from 'react-redux';
|
|
// tslint:disable-next-line: no-submodule-imports
|
|
import _ from 'lodash';
|
|
import { MessageRenderingProps } from '../../../../models/messageType';
|
|
import { getConversationController } from '../../../../session/conversations';
|
|
import {
|
|
getGenericReadableMessageSelectorProps,
|
|
getIsMessageSelected,
|
|
isMessageSelectionMode,
|
|
} from '../../../../state/selectors/conversations';
|
|
import { MessageContentWithStatuses } from '../message-content/MessageContentWithStatus';
|
|
import { ReadableMessage } from './ReadableMessage';
|
|
import styled, { keyframes } from 'styled-components';
|
|
import { isOpenOrClosedGroup } from '../../../../models/conversationAttributes';
|
|
import { ExpirableReadableMessage } from './ExpirableReadableMessage';
|
|
import { StyledMessageReactionsContainer } from '../message-content/MessageReactions';
|
|
|
|
export type GenericReadableMessageSelectorProps = Pick<
|
|
MessageRenderingProps,
|
|
| 'direction'
|
|
| 'conversationType'
|
|
| 'receivedAt'
|
|
| 'isUnread'
|
|
| 'isKickedFromGroup'
|
|
| 'convoId'
|
|
| 'isDeleted'
|
|
>;
|
|
|
|
type Props = {
|
|
messageId: string;
|
|
ctxMenuID: string;
|
|
isDetailView?: boolean;
|
|
};
|
|
// tslint:disable: use-simple-attributes
|
|
|
|
const highlightedMessageAnimation = keyframes`
|
|
1% {
|
|
background-color: var(--primary-color);
|
|
}
|
|
`;
|
|
|
|
const StyledReadableMessage = styled(ReadableMessage)<{
|
|
selected: boolean;
|
|
isRightClicked: boolean;
|
|
}>`
|
|
display: flex;
|
|
align-items: center;
|
|
width: 100%;
|
|
letter-spacing: 0.03rem;
|
|
padding: 0 var(--margins-lg) 0;
|
|
|
|
&.message-highlighted {
|
|
animation: ${highlightedMessageAnimation} 1s ease-in-out;
|
|
}
|
|
|
|
${StyledMessageReactionsContainer} {
|
|
margin-top: var(--margins-xs);
|
|
}
|
|
|
|
${props =>
|
|
props.isRightClicked &&
|
|
`
|
|
background-color: var(--conversation-tab-background-selected-color);
|
|
`}
|
|
|
|
${props =>
|
|
props.selected &&
|
|
`
|
|
&.message-selected {
|
|
.module-message {
|
|
&__container {
|
|
box-shadow: var(--drop-shadow);
|
|
}
|
|
}
|
|
}
|
|
`}
|
|
`;
|
|
|
|
export const GenericReadableMessage = (props: Props) => {
|
|
const { ctxMenuID, messageId, isDetailView } = props;
|
|
|
|
const [enableReactions, setEnableReactions] = useState(true);
|
|
|
|
const msgProps = useSelector(state =>
|
|
getGenericReadableMessageSelectorProps(state as any, props.messageId)
|
|
);
|
|
|
|
const isMessageSelected = useSelector(state =>
|
|
getIsMessageSelected(state as any, props.messageId)
|
|
);
|
|
const multiSelectMode = useSelector(isMessageSelectionMode);
|
|
|
|
const [isRightClicked, setIsRightClicked] = useState(false);
|
|
const onMessageLoseFocus = useCallback(() => {
|
|
if (isRightClicked) {
|
|
setIsRightClicked(false);
|
|
}
|
|
}, [isRightClicked]);
|
|
|
|
const handleContextMenu = useCallback(
|
|
(e: React.MouseEvent<HTMLElement>) => {
|
|
const enableContextMenu = !multiSelectMode && !msgProps?.isKickedFromGroup;
|
|
|
|
if (enableContextMenu) {
|
|
contextMenu.hideAll();
|
|
contextMenu.show({
|
|
id: ctxMenuID,
|
|
event: e,
|
|
});
|
|
}
|
|
setIsRightClicked(enableContextMenu);
|
|
},
|
|
[ctxMenuID, multiSelectMode, msgProps?.isKickedFromGroup]
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (msgProps?.convoId) {
|
|
const conversationModel = getConversationController().get(msgProps?.convoId);
|
|
if (conversationModel) {
|
|
setEnableReactions(conversationModel.hasReactions());
|
|
}
|
|
}
|
|
}, [msgProps?.convoId]);
|
|
|
|
useEffect(() => {
|
|
document.addEventListener('click', onMessageLoseFocus);
|
|
|
|
return () => {
|
|
document.removeEventListener('click', onMessageLoseFocus);
|
|
};
|
|
}, [onMessageLoseFocus]);
|
|
|
|
if (!msgProps) {
|
|
return null;
|
|
}
|
|
const { conversationType, receivedAt, isUnread } = msgProps;
|
|
|
|
const selected = isMessageSelected || false;
|
|
const isGroup = isOpenOrClosedGroup(conversationType);
|
|
|
|
return (
|
|
<StyledReadableMessage
|
|
messageId={messageId}
|
|
selected={selected}
|
|
isRightClicked={isRightClicked}
|
|
className={classNames(
|
|
selected && 'message-selected',
|
|
isGroup && 'public-chat-message-wrapper'
|
|
)}
|
|
onContextMenu={handleContextMenu}
|
|
receivedAt={receivedAt}
|
|
isUnread={!!isUnread}
|
|
key={`readable-message-${messageId}`}
|
|
>
|
|
<ExpirableReadableMessage messageId={messageId}>
|
|
<MessageContentWithStatuses
|
|
ctxMenuID={ctxMenuID}
|
|
messageId={messageId}
|
|
isDetailView={isDetailView}
|
|
dataTestId={`message-content-${messageId}`}
|
|
enableReactions={enableReactions}
|
|
/>
|
|
</ExpirableReadableMessage>
|
|
</StyledReadableMessage>
|
|
);
|
|
};
|