+) {
+ if (selectedConversationKey) {
+ void deleteMessagesByIdForEveryone(selectedMessageIds, selectedConversationKey);
+ }
+}
+
export const SelectionOverlay = () => {
const selectedMessageIds = useSelector(getSelectedMessageIds);
const selectedConversationKey = useSelectedConversationKey();
const isPublic = useSelectedIsPublic();
const dispatch = useDispatch();
- const { i18n } = window;
-
function onCloseOverlay() {
dispatch(resetSelectedMessageIds());
}
- function onDeleteSelectedMessages() {
- if (selectedConversationKey) {
- void deleteMessagesById(selectedMessageIds, selectedConversationKey);
- }
- }
- function onDeleteSelectedMessagesForEveryone() {
- if (selectedConversationKey) {
- void deleteMessagesByIdForEveryone(selectedMessageIds, selectedConversationKey);
- }
- }
-
const isOnlyServerDeletable = isPublic;
- const deleteMessageButtonText = i18n('delete');
- const deleteForEveryoneMessageButtonText = i18n('deleteForEveryone');
return (
@@ -52,21 +46,23 @@ export const SelectionOverlay = () => {
- {!isOnlyServerDeletable && (
-
- )}
{
+ if (selectedConversationKey) {
+ if (isOnlyServerDeletable) {
+ void onDeleteSelectedMessagesForEveryone(
+ selectedConversationKey,
+ selectedMessageIds
+ );
+ } else {
+ void deleteMessagesById(selectedMessageIds, selectedConversationKey);
+ }
+ }
+ }}
/>
diff --git a/ts/components/conversation/media-gallery/MediaGallery.tsx b/ts/components/conversation/media-gallery/MediaGallery.tsx
index 0900e4622..9cd558233 100644
--- a/ts/components/conversation/media-gallery/MediaGallery.tsx
+++ b/ts/components/conversation/media-gallery/MediaGallery.tsx
@@ -1,9 +1,9 @@
-import React, { useCallback, useState } from 'react';
import classNames from 'classnames';
+import React, { useCallback, useState } from 'react';
+import { MediaItemType } from '../../lightbox/LightboxGallery';
import { AttachmentSection } from './AttachmentSection';
import { EmptyState } from './EmptyState';
-import { MediaItemType } from '../../lightbox/LightboxGallery';
type Props = {
documents: Array;
diff --git a/ts/components/conversation/message/message-content/MessageAttachment.tsx b/ts/components/conversation/message/message-content/MessageAttachment.tsx
index 3c16aef7d..4864af173 100644
--- a/ts/components/conversation/message/message-content/MessageAttachment.tsx
+++ b/ts/components/conversation/message/message-content/MessageAttachment.tsx
@@ -11,6 +11,7 @@ import {
toggleSelectedMessageId,
} from '../../../../state/ducks/conversations';
import { StateType } from '../../../../state/reducer';
+import { useMessageSelected } from '../../../../state/selectors';
import {
getMessageAttachmentProps,
isMessageSelectionMode,
@@ -32,7 +33,7 @@ import { AudioPlayerWithEncryptedFile } from '../../H5AudioPlayer';
import { ImageGrid } from '../../ImageGrid';
import { LightBoxOptions } from '../../SessionConversation';
import { ClickToTrustSender } from './ClickToTrustSender';
-import { StyledMessageHighlighter } from './MessageContent';
+import { MessageHighlighter } from './MessageHighlighter';
export type MessageAttachmentSelectorProps = Pick<
MessageRenderingProps,
@@ -53,7 +54,7 @@ type Props = {
highlight?: boolean;
};
-const StyledAttachmentContainer = styled.div<{
+const StyledImageGridContainer = styled.div<{
messageDirection: MessageModelType;
}>`
text-align: center;
@@ -63,6 +64,10 @@ const StyledAttachmentContainer = styled.div<{
justify-content: ${props => (props.messageDirection === 'incoming' ? 'flex-start' : 'flex-end')};
`;
+const StyledGenericAttachmentContainer = styled(MessageHighlighter)<{ selected: boolean }>`
+ ${props => props.selected && 'box-shadow: var(--drop-shadow);'}
+`;
+
export const MessageAttachment = (props: Props) => {
const { messageId, imageBroken, handleImageError, highlight = false } = props;
@@ -72,6 +77,7 @@ export const MessageAttachment = (props: Props) => {
);
const multiSelectMode = useSelector(isMessageSelectionMode);
+ const selected = useMessageSelected(messageId);
const onClickOnImageGrid = useCallback(
(attachment: AttachmentTypeWithPath | AttachmentType) => {
if (multiSelectMode) {
@@ -138,21 +144,22 @@ export const MessageAttachment = (props: Props) => {
(isVideo(attachments) && hasVideoScreenshot(attachments)))
) {
return (
-
-
+
+
-
-
+
+
);
}
if (!firstAttachment.pending && !firstAttachment.error && isAudio(attachments)) {
return (
- {
@@ -168,14 +175,18 @@ export const MessageAttachment = (props: Props) => {
contentType={firstAttachment.contentType}
messageId={messageId}
/>
-
+
);
}
const { pending, fileName, fileSize, contentType } = firstAttachment;
const extension = getExtensionForDisplay({ contentType, fileName });
return (
-
+
{pending ? (
@@ -211,7 +222,7 @@ export const MessageAttachment = (props: Props) => {
{fileSize}
-
+
);
};
diff --git a/ts/components/conversation/message/message-content/MessageContent.tsx b/ts/components/conversation/message/message-content/MessageContent.tsx
index 1049465cd..98b509a8a 100644
--- a/ts/components/conversation/message/message-content/MessageContent.tsx
+++ b/ts/components/conversation/message/message-content/MessageContent.tsx
@@ -4,23 +4,25 @@ import moment from 'moment';
import React, { createContext, useCallback, useContext, useLayoutEffect, useState } from 'react';
import { InView } from 'react-intersection-observer';
import { useSelector } from 'react-redux';
-import styled, { css, keyframes } from 'styled-components';
+import styled from 'styled-components';
import { MessageModelType, MessageRenderingProps } from '../../../../models/messageType';
import { StateType } from '../../../../state/reducer';
-import { useHideAvatarInMsgList, useMessageIsDeleted } from '../../../../state/selectors';
+import {
+ useHideAvatarInMsgList,
+ useMessageIsDeleted,
+ useMessageSelected,
+} from '../../../../state/selectors';
import {
getMessageContentSelectorProps,
getQuotedMessageToAnimate,
getShouldHighlightMessage,
} from '../../../../state/selectors/conversations';
-import {
- useSelectedIsGroup,
- useSelectedIsPrivate,
-} from '../../../../state/selectors/selectedConversation';
+import { useSelectedIsPrivate } from '../../../../state/selectors/selectedConversation';
import { canDisplayImage } from '../../../../types/Attachment';
import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer';
import { MessageAttachment } from './MessageAttachment';
import { MessageAvatar } from './MessageAvatar';
+import { MessageHighlighter } from './MessageHighlighter';
import { MessageLinkPreview } from './MessageLinkPreview';
import { MessageQuote } from './MessageQuote';
import { MessageText } from './MessageText';
@@ -54,41 +56,13 @@ function onClickOnMessageInnerContainer(event: React.MouseEvent)
const StyledMessageContent = styled.div<{ msgDirection: MessageModelType }>`
display: flex;
-
align-self: ${props => (props.msgDirection === 'incoming' ? 'flex-start' : 'flex-end')};
`;
-const opacityAnimation = keyframes`
- 0% {
- opacity: 1;
- }
- 25% {
- opacity: 0.2;
- }
- 50% {
- opacity: 1;
- }
- 75% {
- opacity: 0.2;
- }
- 100% {
- opacity: 1;
- }
-`;
-
-export const StyledMessageHighlighter = styled.div<{
- highlight: boolean;
-}>`
- ${props =>
- props.highlight &&
- css`
- animation: ${opacityAnimation} 1s linear;
- `}
-`;
-
-const StyledMessageOpaqueContent = styled(StyledMessageHighlighter)<{
+const StyledMessageOpaqueContent = styled(MessageHighlighter)<{
isIncoming: boolean;
highlight: boolean;
+ selected: boolean;
}>`
background: ${props =>
props.isIncoming
@@ -98,13 +72,13 @@ const StyledMessageOpaqueContent = styled(StyledMessageHighlighter)<{
padding: var(--padding-message-content);
border-radius: var(--border-radius-message-box);
width: 100%;
+
+ ${props => props.selected && `box-shadow: var(--drop-shadow);`}
`;
export const IsMessageVisibleContext = createContext(false);
-// NOTE aligns group member avatars with the ExpireTimer
-const StyledAvatarContainer = styled.div<{ hideAvatar: boolean; isGroup: boolean }>`
- /* margin-inline-start: ${props => (!props.hideAvatar && props.isGroup ? '-11px' : '')}; */
+const StyledAvatarContainer = styled.div`
align-self: flex-end;
`;
@@ -119,16 +93,12 @@ export const MessageContent = (props: Props) => {
const scrollToLoadedMessage = useContext(ScrollToLoadedMessageContext);
const selectedIsPrivate = useSelectedIsPrivate();
- const isGroup = useSelectedIsGroup();
const hideAvatar = useHideAvatarInMsgList(props.messageId);
const [imageBroken, setImageBroken] = useState(false);
- const onVisible = (inView: boolean | object) => {
- if (
- inView === true ||
- ((inView as any).type === 'focus' && (inView as any).returnValue === true)
- ) {
+ const onVisible = (inView: boolean, _: IntersectionObserverEntry) => {
+ if (inView) {
if (isMessageVisible !== true) {
setMessageIsVisible(true);
}
@@ -142,6 +112,7 @@ export const MessageContent = (props: Props) => {
const quotedMessageToAnimate = useSelector(getQuotedMessageToAnimate);
const shouldHighlightMessage = useSelector(getShouldHighlightMessage);
const isQuotedMessageToAnimate = quotedMessageToAnimate === props.messageId;
+ const selected = useMessageSelected(props.messageId);
useLayoutEffect(() => {
if (isQuotedMessageToAnimate) {
@@ -200,7 +171,7 @@ export const MessageContent = (props: Props) => {
title={toolTipTitle}
msgDirection={direction}
>
-
+
{
{
>
{hasContentBeforeAttachment && (
-
+
{!isDeleted && (
<>
diff --git a/ts/components/conversation/message/message-content/MessageContextMenu.tsx b/ts/components/conversation/message/message-content/MessageContextMenu.tsx
index 9736949d7..3b7d8927b 100644
--- a/ts/components/conversation/message/message-content/MessageContextMenu.tsx
+++ b/ts/components/conversation/message/message-content/MessageContextMenu.tsx
@@ -88,19 +88,29 @@ const StyledEmojiPanelContainer = styled.div<{ x: number; y: number }>`
}
`;
-const DeleteForEveryone = ({ messageId }: { messageId: string }) => {
+const DeleteItem = ({ messageId }: { messageId: string }) => {
const convoId = useSelectedConversationKey();
+ const isPublic = useSelectedIsPublic();
+
+ const isDeletable = useMessageIsDeletable(messageId);
const isDeletableForEveryone = useMessageIsDeletableForEveryone(messageId);
- if (!convoId || !isDeletableForEveryone) {
+
+ const onDelete = useCallback(() => {
+ if (convoId) {
+ if (!isPublic && isDeletable) {
+ void deleteMessagesById([messageId], convoId);
+ }
+ if (isPublic && isDeletableForEveryone) {
+ void deleteMessagesByIdForEveryone([messageId], convoId);
+ }
+ }
+ }, [convoId, isDeletable, isDeletableForEveryone, isPublic, messageId]);
+
+ if (!convoId || (isPublic && !isDeletableForEveryone) || (!isPublic && !isDeletable)) {
return null;
}
- const onDeleteForEveryone = () => {
- void deleteMessagesByIdForEveryone([messageId], convoId);
- };
-
- const unsendMessageText = window.i18n('deleteForEveryone');
- return - {unsendMessageText}
;
+ return - {window.i18n('delete')}
;
};
type MessageId = { messageId: string };
@@ -193,7 +203,6 @@ export const MessageContextMenu = (props: Props) => {
const isSelectedBlocked = useSelectedIsBlocked();
const convoId = useSelectedConversationKey();
- const isPublic = useSelectedIsPublic();
const direction = useMessageDirection(messageId);
const status = useMessageStatus(messageId);
@@ -238,7 +247,6 @@ export const MessageContextMenu = (props: Props) => {
);
const selectMessageText = window.i18n('selectMessage');
- const deleteMessageJustForMeText = window.i18n('deleteJustForMe');
const onReply = useCallback(() => {
if (isSelectedBlocked) {
@@ -256,12 +264,6 @@ export const MessageContextMenu = (props: Props) => {
dispatch(toggleSelectedMessageId(messageId));
}, [dispatch, messageId]);
- const onDelete = useCallback(() => {
- if (convoId) {
- void deleteMessagesById([messageId], convoId);
- }
- }, [convoId, messageId]);
-
const onShowEmoji = () => {
hideAll();
setMouseX(docX);
@@ -388,10 +390,7 @@ export const MessageContextMenu = (props: Props) => {
{isDeletable ? - {selectMessageText}
: null}
- {isDeletable && !isPublic ? (
- - {deleteMessageJustForMeText}
- ) : null}
-
+
diff --git a/ts/components/conversation/message/message-content/MessageHighlighter.tsx b/ts/components/conversation/message/message-content/MessageHighlighter.tsx
new file mode 100644
index 000000000..d468cacac
--- /dev/null
+++ b/ts/components/conversation/message/message-content/MessageHighlighter.tsx
@@ -0,0 +1,29 @@
+import styled, { css, keyframes } from 'styled-components';
+
+const opacityAnimation = keyframes`
+ 0% {
+ opacity: 1;
+ }
+ 25% {
+ opacity: 0.2;
+ }
+ 50% {
+ opacity: 1;
+ }
+ 75% {
+ opacity: 0.2;
+ }
+ 100% {
+ opacity: 1;
+ }
+`;
+
+export const MessageHighlighter = styled.div<{
+ highlight: boolean;
+}>`
+ ${props =>
+ props.highlight &&
+ css`
+ animation: ${opacityAnimation} 1s linear;
+ `}
+`;
diff --git a/ts/components/conversation/message/message-item/GenericReadableMessage.tsx b/ts/components/conversation/message/message-item/GenericReadableMessage.tsx
index b24c2815b..2ec184836 100644
--- a/ts/components/conversation/message/message-item/GenericReadableMessage.tsx
+++ b/ts/components/conversation/message/message-item/GenericReadableMessage.tsx
@@ -7,9 +7,9 @@ import styled, { keyframes } from 'styled-components';
import { MessageRenderingProps } from '../../../../models/messageType';
import { getConversationController } from '../../../../session/conversations';
import { StateType } from '../../../../state/reducer';
+import { useMessageSelected } from '../../../../state/selectors';
import {
getGenericReadableMessageSelectorProps,
- getIsMessageSelected,
isMessageSelectionMode,
} from '../../../../state/selectors/conversations';
import { MessageContentWithStatuses } from '../message-content/MessageContentWithStatus';
@@ -62,18 +62,6 @@ const StyledReadableMessage = styled.div<{
`
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) => {
@@ -85,9 +73,8 @@ export const GenericReadableMessage = (props: Props) => {
getGenericReadableMessageSelectorProps(state, props.messageId)
);
- const isMessageSelected = useSelector((state: StateType) =>
- getIsMessageSelected(state, props.messageId)
- );
+ const isMessageSelected = useMessageSelected(props.messageId);
+
const multiSelectMode = useSelector(isMessageSelectionMode);
const [isRightClicked, setIsRightClicked] = useState(false);
@@ -155,7 +142,7 @@ export const GenericReadableMessage = (props: Props) => {
selected={selected}
isDetailView={isDetailView}
isRightClicked={isRightClicked}
- className={classNames(selected && 'message-selected')}
+ className={classNames(selected ? 'message-selected' : undefined)}
onContextMenu={handleContextMenu}
key={`readable-message-${messageId}`}
>
diff --git a/ts/components/conversation/message/message-item/GroupInvitation.tsx b/ts/components/conversation/message/message-item/GroupInvitation.tsx
index 566aa0caa..90926ec50 100644
--- a/ts/components/conversation/message/message-item/GroupInvitation.tsx
+++ b/ts/components/conversation/message/message-item/GroupInvitation.tsx
@@ -26,6 +26,7 @@ const StyledGroupInvitation = styled.div`
display: inline-block;
padding: 4px;
+ margin: var(--margins-xs) calc(var(--margins-lg) + var(--margins-md)) 0 var(--margins-lg);
border-radius: var(--border-radius-message-box);
diff --git a/ts/components/conversation/message/message-item/ReadableMessage.tsx b/ts/components/conversation/message/message-item/ReadableMessage.tsx
index 5e04dfc0b..619563732 100644
--- a/ts/components/conversation/message/message-item/ReadableMessage.tsx
+++ b/ts/components/conversation/message/message-item/ReadableMessage.tsx
@@ -116,7 +116,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
});
const onVisible = useCallback(
- async (inView: boolean | object) => {
+ async (inView: boolean, _: IntersectionObserverEntry) => {
if (!selectedConversationKey) {
return;
}
@@ -135,30 +135,16 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
}
}
- if (
- inView === true &&
- isAppFocused &&
- oldestMessageId === messageId &&
- !fetchingMoreInProgress
- ) {
+ if (inView && isAppFocused && oldestMessageId === messageId && !fetchingMoreInProgress) {
debouncedTriggerLoadMoreTop(selectedConversationKey, oldestMessageId);
}
- if (
- inView === true &&
- isAppFocused &&
- youngestMessageId === messageId &&
- !fetchingMoreInProgress
- ) {
+ if (inView && isAppFocused && youngestMessageId === messageId && !fetchingMoreInProgress) {
debouncedTriggerLoadMoreBottom(selectedConversationKey, youngestMessageId);
}
// this part is just handling the marking of the message as read if needed
- if (
- (inView === true ||
- ((inView as any).type === 'focus' && (inView as any).returnValue === true)) &&
- isAppFocused
- ) {
+ if (inView) {
if (isUnread) {
// TODOLATER this is pretty expensive and should instead use values from the redux store
const found = await Data.getMessageById(messageId);
diff --git a/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx b/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx
index c08aa5498..cab16bfee 100644
--- a/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx
+++ b/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx
@@ -42,11 +42,11 @@ import { AttachmentTypeWithPath } from '../../../../types/Attachment';
import { getAbsoluteAttachmentPath } from '../../../../types/MessageAttachment';
import { Avatar, AvatarSize } from '../../../avatar/Avatar';
import { Flex } from '../../../basic/Flex';
-import { SpacerMD } from '../../../basic/Text';
+import { SpacerLG, SpacerMD, SpacerXL } from '../../../basic/Text';
import { PanelButtonGroup, PanelIconButton } from '../../../buttons';
import { MediaItemType } from '../../../lightbox/LightboxGallery';
import { MediaGallery } from '../../media-gallery/MediaGallery';
-import { Header } from './components';
+import { Header, StyledScrollContainer } from './components';
async function getMediaGalleryProps(
conversationId: string
@@ -278,77 +278,81 @@ export const OverlayRightPanelSettings = () => {
};
return (
- <>
-
-
- {showUpdateGroupNameButton && (
- {
- void showUpdateGroupNameByConvoId(selectedConvoKey);
- }}
- dataTestId="edit-group-name"
- />
- )}
-
- {showAddRemoveModeratorsButton && (
- <>
+
+
+
+
+ {showUpdateGroupNameButton && (
{
- showAddModeratorsByConvoId(selectedConvoKey);
+ void showUpdateGroupNameByConvoId(selectedConvoKey);
}}
- dataTestId="add-moderators"
+ dataTestId="edit-group-name"
/>
-
+ )}
+
+ {showAddRemoveModeratorsButton && (
+ <>
+ {
+ showAddModeratorsByConvoId(selectedConvoKey);
+ }}
+ dataTestId="add-moderators"
+ />
+
+ {
+ showRemoveModeratorsByConvoId(selectedConvoKey);
+ }}
+ dataTestId="remove-moderators"
+ />
+ >
+ )}
+
+ {showUpdateGroupMembersButton && (
{
- showRemoveModeratorsByConvoId(selectedConvoKey);
+ void showUpdateGroupMembersByConvoId(selectedConvoKey);
}}
- dataTestId="remove-moderators"
+ dataTestId="group-members"
/>
- >
- )}
+ )}
- {showUpdateGroupMembersButton && (
- {
- void showUpdateGroupMembersByConvoId(selectedConvoKey);
- }}
- dataTestId="group-members"
- />
- )}
-
- {hasDisappearingMessages && (
- {
- dispatch(setRightOverlayMode({ type: 'disappearing_messages', params: null }));
- }}
- />
- )}
+ {hasDisappearingMessages && (
+ {
+ dispatch(setRightOverlayMode({ type: 'disappearing_messages', params: null }));
+ }}
+ />
+ )}
-
- {isGroup && (
- void deleteConvoAction()}
- color={'var(--danger-color)'}
- iconType={'delete'}
- />
- )}
-
- >
+
+ {isGroup && (
+ void deleteConvoAction()}
+ color={'var(--danger-color)'}
+ iconType={'delete'}
+ />
+ )}
+
+
+
+
+
);
};
diff --git a/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx b/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx
index d5358a073..496babbeb 100644
--- a/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx
+++ b/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx
@@ -77,15 +77,13 @@ const MessageBody = ({
);
};
-const StyledMessageDetailContainer = styled.div`
+const StyledMessageInfoContainer = styled.div`
height: calc(100% - 48px);
width: 100%;
- overflow-y: auto;
+ max-width: 650px;
+ overflow: hidden auto;
z-index: 2;
-`;
-const StyledMessageDetail = styled.div`
- max-width: 650px;
margin-inline-start: auto;
margin-inline-end: auto;
padding: var(--margins-sm) var(--margins-2xl) var(--margins-lg);
@@ -254,96 +252,94 @@ export const OverlayMessageInfo = () => {
{window.i18n('messageInfo')}
-
-
-
+
+ {hasAttachments && (
+ <>
+ {supportsAttachmentCarousel && (
+ <>
+ {
+ handleChangeAttachment(1);
+ }}
+ previousAction={() => {
+ handleChangeAttachment(-1);
+ }}
+ />
+
+ >
+ )}
+
+
+ >
+ )}
+
+
+
+ {
+ // eslint-disable-next-line more/no-then
+ void replyToMessage(messageId).then(foundIt => {
+ if (foundIt) {
+ dispatch(closeRightPanel());
+ dispatch(resetRightOverlayMode());
+ }
+ });
+ }}
+ dataTestId="reply-to-msg-from-details"
/>
+ {hasErrors && direction === 'outgoing' && (
+ {
+ void resendMessage(messageId);
+ dispatch(closeRightPanel());
+ dispatch(resetRightOverlayMode());
+ }}
+ dataTestId="resend-msg-from-details"
+ />
+ )}
{hasAttachments && (
- <>
- {supportsAttachmentCarousel && (
- <>
- {
- handleChangeAttachment(1);
- }}
- previousAction={() => {
- handleChangeAttachment(-1);
- }}
- />
-
- >
- )}
-
-
- >
+ {
+ if (hasAttachments) {
+ void saveAttachmentToDisk({
+ conversationId: convoId,
+ messageSender: sender,
+ messageTimestamp: serverTimestamp || timestamp || Date.now(),
+ attachment: attachments[visibleAttachmentIndex],
+ index: visibleAttachmentIndex,
+ });
+ }
+ }}
+ />
)}
-
-
-
+ {isDeletable && (
{
- // eslint-disable-next-line more/no-then
- void replyToMessage(messageId).then(foundIt => {
- if (foundIt) {
- dispatch(closeRightPanel());
- dispatch(resetRightOverlayMode());
- }
- });
+ void deleteMessagesById([messageId], convoId);
}}
- dataTestId="reply-to-msg-from-details"
/>
- {hasErrors && direction === 'outgoing' && (
- {
- void resendMessage(messageId);
- dispatch(closeRightPanel());
- dispatch(resetRightOverlayMode());
- }}
- dataTestId="resend-msg-from-details"
- />
- )}
- {hasAttachments && (
- {
- if (hasAttachments) {
- void saveAttachmentToDisk({
- conversationId: convoId,
- messageSender: sender,
- messageTimestamp: serverTimestamp || timestamp || Date.now(),
- attachment: attachments[visibleAttachmentIndex],
- index: visibleAttachmentIndex,
- });
- }
- }}
- />
- )}
- {isDeletable && (
- {
- void deleteMessagesById([messageId], convoId);
- }}
- />
- )}
-
-
-
-
+ )}
+
+
+
);
diff --git a/ts/state/selectors/messages.ts b/ts/state/selectors/messages.ts
index b97ee2fef..8ae182966 100644
--- a/ts/state/selectors/messages.ts
+++ b/ts/state/selectors/messages.ts
@@ -8,7 +8,7 @@ import {
ReduxConversationType,
} from '../ducks/conversations';
import { StateType } from '../reducer';
-import { getMessagePropsByMessageId } from './conversations';
+import { getIsMessageSelected, getMessagePropsByMessageId } from './conversations';
import { useSelectedIsPrivate } from './selectedConversation';
function useMessagePropsByMessageId(messageId: string | undefined) {
@@ -145,3 +145,7 @@ export function useHideAvatarInMsgList(messageId?: string) {
const selectedIsPrivate = useSelectedIsPrivate();
return msgProps?.propsForMessage.direction === 'outgoing' || selectedIsPrivate;
}
+
+export function useMessageSelected(messageId?: string) {
+ return useSelector((state: StateType) => getIsMessageSelected(state, messageId));
+}
diff --git a/ts/state/selectors/selectedConversation.ts b/ts/state/selectors/selectedConversation.ts
index 07c07daf8..f6a118272 100644
--- a/ts/state/selectors/selectedConversation.ts
+++ b/ts/state/selectors/selectedConversation.ts
@@ -10,7 +10,11 @@ import { UserUtils } from '../../session/utils';
import { ReleasedFeatures } from '../../util/releaseFeature';
import { ReduxConversationType } from '../ducks/conversations';
import { StateType } from '../reducer';
-import { getIsMessageSelectionMode, getSelectedConversation } from './conversations';
+import {
+ getIsMessageSelectionMode,
+ getSelectedConversation,
+ getSelectedMessageIds,
+} from './conversations';
import { getCanWrite, getModerators, getSubscriberCount } from './sogsRoomInfo';
/**
@@ -387,3 +391,7 @@ export function useIsMessageSelectionMode() {
export function useSelectedLastMessage() {
return useSelector((state: StateType) => getSelectedConversation(state)?.lastMessage);
}
+
+export function useSelectedMessageIds() {
+ return useSelector(getSelectedMessageIds);
+}
diff --git a/yarn.lock b/yarn.lock
index ff41fe0d2..232727930 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6155,10 +6155,10 @@ react-h5-audio-player@^3.2.0:
"@iconify/icons-mdi" "~1.1.0"
"@iconify/react" "^3.1.3"
-react-intersection-observer@^8.30.3:
- version "8.34.0"
- resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-8.34.0.tgz#6f6e67831c52e6233f6b6cc7eb55814820137c42"
- integrity sha512-TYKh52Zc0Uptp5/b4N91XydfSGKubEhgZRtcg1rhTKABXijc4Sdr1uTp5lJ8TN27jwUsdXxjHXtHa0kPj704sw==
+react-intersection-observer@^9.7.0:
+ version "9.7.0"
+ resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.7.0.tgz#da65834ace0852e04b73cb97f0c48bdaa5b13589"
+ integrity sha512-euleEjBVaMRwSOMNVcMX5WGn74GfZ9I78nx9SUb5a0eXd0IhegjJcUliSO9Jd+xiaZ5rgFvbGoVln66lpMyUUg==
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"