put back quote a message logic with hook

pull/1783/head
Audric Ackermann 4 years ago
parent 9a380b716b
commit a54345a42e
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -43,7 +43,7 @@ import autoBind from 'auto-bind';
import { AudioPlayerWithEncryptedFile } from './H5AudioPlayer'; import { AudioPlayerWithEncryptedFile } from './H5AudioPlayer';
import { ClickToTrustSender } from './message/ClickToTrustSender'; import { ClickToTrustSender } from './message/ClickToTrustSender';
import { getMessageById } from '../../data/data'; import { getMessageById } from '../../data/data';
import { deleteMessagesById } from '../../interactions/conversationInteractions'; import { deleteMessagesById, replyToMessage } from '../../interactions/conversationInteractions';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { StateType } from '../../state/reducer'; import { StateType } from '../../state/reducer';
import { getSelectedMessageIds } from '../../state/selectors/conversations'; import { getSelectedMessageIds } from '../../state/selectors/conversations';
@ -56,6 +56,7 @@ import {
} from '../../state/ducks/conversations'; } from '../../state/ducks/conversations';
import { saveAttachmentToDisk } from '../../util/attachmentsUtil'; import { saveAttachmentToDisk } from '../../util/attachmentsUtil';
import { LightBoxOptions } from '../session/conversation/SessionConversation'; import { LightBoxOptions } from '../session/conversation/SessionConversation';
import { pushUnblockToSend } from '../../session/utils/Toast';
// Same as MIN_WIDTH in ImageGrid.tsx // Same as MIN_WIDTH in ImageGrid.tsx
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200; const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
@ -944,9 +945,12 @@ class MessageInner extends React.PureComponent<Props, State> {
} }
private onReplyPrivate(e: any) { private onReplyPrivate(e: any) {
if (this.props && this.props.onReply) { if (this.props.isBlocked) {
this.props.onReply(this.props.timestamp); pushUnblockToSend();
return;
} }
void replyToMessage(this.props.id);
} }
private async onAddModerator() { private async onAddModerator() {

@ -45,6 +45,9 @@ import {
getItemById, getItemById,
hasLinkPreviewPopupBeenDisplayed, hasLinkPreviewPopupBeenDisplayed,
} from '../../../data/data'; } from '../../../data/data';
import { getQuotedMessage } from '../../../state/selectors/conversations';
import { connect } from 'react-redux';
import { StateType } from '../../../state/reducer';
export interface ReplyingToMessageProps { export interface ReplyingToMessageProps {
convoId: string; convoId: string;
@ -80,10 +83,7 @@ interface Props {
selectedConversationKey: string; selectedConversationKey: string;
selectedConversation: ReduxConversationType | undefined; selectedConversation: ReduxConversationType | undefined;
isPublic: boolean; isPublic: boolean;
quotedMessageProps?: ReplyingToMessageProps; quotedMessageProps?: ReplyingToMessageProps;
removeQuotedMessage: () => void;
stagedAttachments: Array<StagedAttachmentType>; stagedAttachments: Array<StagedAttachmentType>;
clearAttachments: () => any; clearAttachments: () => any;
removeAttachment: (toRemove: AttachmentType) => void; removeAttachment: (toRemove: AttachmentType) => void;
@ -135,7 +135,7 @@ const getDefaultState = () => {
}; };
}; };
export class SessionCompositionBox extends React.Component<Props, State> { class SessionCompositionBoxInner extends React.Component<Props, State> {
private readonly textarea: React.RefObject<any>; private readonly textarea: React.RefObject<any>;
private readonly fileInput: React.RefObject<HTMLInputElement>; private readonly fileInput: React.RefObject<HTMLInputElement>;
private emojiPanel: any; private emojiPanel: any;
@ -188,7 +188,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
return ( return (
<Flex flexDirection="column"> <Flex flexDirection="column">
{this.renderQuotedMessage()} <SessionQuotedMessageComposition />
{this.renderStagedLinkPreview()} {this.renderStagedLinkPreview()}
{this.renderAttachmentsStaged()} {this.renderAttachmentsStaged()}
<div className="composition-container"> <div className="composition-container">
@ -665,19 +665,6 @@ export class SessionCompositionBox extends React.Component<Props, State> {
}); });
} }
private renderQuotedMessage() {
const { quotedMessageProps, removeQuotedMessage } = this.props;
if (quotedMessageProps?.id) {
return (
<SessionQuotedMessageComposition
quotedMessageProps={quotedMessageProps}
removeQuotedMessage={removeQuotedMessage}
/>
);
}
return <></>;
}
private onClickAttachment(attachment: AttachmentType) { private onClickAttachment(attachment: AttachmentType) {
this.setState({ showCaptionEditor: attachment }); this.setState({ showCaptionEditor: attachment });
} }
@ -839,6 +826,8 @@ export class SessionCompositionBox extends React.Component<Props, State> {
} }
const { quotedMessageProps } = this.props; const { quotedMessageProps } = this.props;
console.warn('quotedMessageProps', quotedMessageProps);
const { stagedLinkPreview } = this.state; const { stagedLinkPreview } = this.state;
// Send message // Send message
@ -999,3 +988,13 @@ export class SessionCompositionBox extends React.Component<Props, State> {
this.linkPreviewAbortController?.abort(); this.linkPreviewAbortController?.abort();
} }
} }
const mapStateToProps = (state: StateType) => {
return {
quotedMessageProps: getQuotedMessage(state),
};
};
const smart = connect(mapStateToProps);
export const SessionCompositionBox = smart(SessionCompositionBoxInner);

@ -21,6 +21,7 @@ import { SessionFileDropzone } from './SessionFileDropzone';
import { import {
fetchMessagesForConversation, fetchMessagesForConversation,
PropsForMessage, PropsForMessage,
quoteMessage,
ReduxConversationType, ReduxConversationType,
resetSelectedMessageIds, resetSelectedMessageIds,
showLightBox, showLightBox,
@ -44,10 +45,6 @@ interface State {
stagedAttachments: Array<StagedAttachmentType>; stagedAttachments: Array<StagedAttachmentType>;
isDraggingFile: boolean; isDraggingFile: boolean;
// quoted message
quotedMessageTimestamp?: number;
quotedMessageProps?: any;
} }
export interface LightBoxOptions { export interface LightBoxOptions {
@ -151,8 +148,6 @@ export class SessionConversation extends React.Component<Props, State> {
showRecordingView: false, showRecordingView: false,
stagedAttachments: [], stagedAttachments: [],
isDraggingFile: false, isDraggingFile: false,
quotedMessageProps: undefined,
quotedMessageTimestamp: undefined,
}); });
} }
} }
@ -174,7 +169,7 @@ export class SessionConversation extends React.Component<Props, State> {
// ~~~~~~~~~~~~~~ RENDER METHODS ~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~ RENDER METHODS ~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public render() { public render() {
const { showRecordingView, quotedMessageProps, isDraggingFile, stagedAttachments } = this.state; const { showRecordingView, isDraggingFile, stagedAttachments } = this.state;
const { const {
selectedConversation, selectedConversation,
@ -210,6 +205,8 @@ export class SessionConversation extends React.Component<Props, State> {
(this.messageContainerRef (this.messageContainerRef
.current as any).scrollTop = this.messageContainerRef.current?.scrollHeight; .current as any).scrollTop = this.messageContainerRef.current?.scrollHeight;
} }
window.inboxStore?.dispatch(quoteMessage(undefined));
}; };
return ( return (
@ -231,7 +228,7 @@ export class SessionConversation extends React.Component<Props, State> {
{lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)} {lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)}
<div className="conversation-messages"> <div className="conversation-messages">
<SessionMessagesList {...this.getMessagesListProps()} /> <SessionMessagesList messageContainerRef={this.messageContainerRef} />
{showRecordingView && <div className="conversation-messages__blocking-overlay" />} {showRecordingView && <div className="conversation-messages__blocking-overlay" />}
{isDraggingFile && <SessionFileDropzone />} {isDraggingFile && <SessionFileDropzone />}
@ -249,10 +246,6 @@ export class SessionConversation extends React.Component<Props, State> {
stagedAttachments={stagedAttachments} stagedAttachments={stagedAttachments}
onLoadVoiceNoteView={this.onLoadVoiceNoteView} onLoadVoiceNoteView={this.onLoadVoiceNoteView}
onExitVoiceNoteView={this.onExitVoiceNoteView} onExitVoiceNoteView={this.onExitVoiceNoteView}
quotedMessageProps={quotedMessageProps}
removeQuotedMessage={() => {
void this.replyToMessage(undefined);
}}
clearAttachments={this.clearAttachments} clearAttachments={this.clearAttachments}
removeAttachment={this.removeAttachment} removeAttachment={this.removeAttachment}
onChoseAttachments={this.onChoseAttachments} onChoseAttachments={this.onChoseAttachments}
@ -292,13 +285,6 @@ export class SessionConversation extends React.Component<Props, State> {
); );
} }
public getMessagesListProps(): SessionMessageListProps {
return {
messageContainerRef: this.messageContainerRef,
replyToMessage: this.replyToMessage,
};
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~ MICROPHONE METHODS ~~~~~~~~~~~~ // ~~~~~~~~~~~~ MICROPHONE METHODS ~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -315,37 +301,6 @@ export class SessionConversation extends React.Component<Props, State> {
}); });
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~ MESSAGE QUOTE ~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private async replyToMessage(quotedMessageTimestamp?: number) {
if (this.props.selectedConversation?.isBlocked) {
pushUnblockToSend();
return;
}
if (!_.isEqual(this.state.quotedMessageTimestamp, quotedMessageTimestamp)) {
const { messagesProps, selectedConversationKey } = this.props;
const conversationModel = getConversationController().getOrThrow(selectedConversationKey);
let quotedMessageProps = null;
if (quotedMessageTimestamp) {
const quotedMessage = messagesProps.find(
m =>
m.propsForMessage.timestamp === quotedMessageTimestamp ||
m.propsForMessage.serverTimestamp === quotedMessageTimestamp
);
if (quotedMessage) {
const quotedMessageModel = await getMessageById(quotedMessage.propsForMessage.id);
if (quotedMessageModel) {
quotedMessageProps = await conversationModel.makeQuote(quotedMessageModel);
}
}
}
this.setState({ quotedMessageTimestamp, quotedMessageProps });
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~ KEYBOARD NAVIGATION ~~~~~~~~~~~~ // ~~~~~~~~~~~ KEYBOARD NAVIGATION ~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@ -52,8 +52,6 @@ interface State {
export type SessionMessageListProps = { export type SessionMessageListProps = {
messageContainerRef: React.RefObject<any>; messageContainerRef: React.RefObject<any>;
replyToMessage: (messageId: number) => Promise<void>;
}; };
type Props = SessionMessageListProps & { type Props = SessionMessageListProps & {
@ -138,10 +136,6 @@ const GenericMessageItem = (props: {
console.warn('FIXME audric'); console.warn('FIXME audric');
if (!props.messageProps) {
debugger;
}
// const onQuoteClick = props.messageProps.propsForMessage.quote // const onQuoteClick = props.messageProps.propsForMessage.quote
// ? this.scrollToQuoteMessage // ? this.scrollToQuoteMessage
// : async () => {}; // : async () => {};
@ -152,7 +146,6 @@ const GenericMessageItem = (props: {
multiSelectMode, multiSelectMode,
// isQuotedMessageToAnimate: messageId === this.state.animateQuotedMessageId, // isQuotedMessageToAnimate: messageId === this.state.animateQuotedMessageId,
// nextMessageToPlay: this.state.nextMessageToPlay, // nextMessageToPlay: this.state.nextMessageToPlay,
onReply: props.replyToMessage,
// playNextMessage: this.playNextMessage, // playNextMessage: this.playNextMessage,
// onQuoteClick, // onQuoteClick,
}; };

@ -1,17 +1,13 @@
import React, { useContext } from 'react'; import React, { useCallback } from 'react';
import { Flex } from '../../basic/Flex'; import { Flex } from '../../basic/Flex';
import { SessionIcon, SessionIconButton, SessionIconSize, SessionIconType } from '../icon'; import { SessionIcon, SessionIconButton, SessionIconSize, SessionIconType } from '../icon';
import { ReplyingToMessageProps } from './SessionCompositionBox'; import styled, { useTheme } from 'styled-components';
import styled, { DefaultTheme, ThemeContext } from 'styled-components'; import { getAlt, isAudio } from '../../../types/Attachment';
import { getAlt, isAudio, isImageAttachment } from '../../../types/Attachment';
import { Image } from '../../conversation/Image'; import { Image } from '../../conversation/Image';
import { AUDIO_MP3 } from '../../../types/MIME'; import { AUDIO_MP3 } from '../../../types/MIME';
import { useDispatch, useSelector } from 'react-redux';
// tslint:disable: react-unused-props-and-state import { getQuotedMessage } from '../../../state/selectors/conversations';
interface Props { import { quoteMessage } from '../../../state/ducks/conversations';
quotedMessageProps: ReplyingToMessageProps;
removeQuotedMessage: any;
}
const QuotedMessageComposition = styled.div` const QuotedMessageComposition = styled.div`
width: 100%; width: 100%;
@ -41,11 +37,13 @@ const ReplyingTo = styled.div`
color: ${props => props.theme.colors.textColor}; color: ${props => props.theme.colors.textColor};
`; `;
export const SessionQuotedMessageComposition = (props: Props) => { export const SessionQuotedMessageComposition = () => {
const { quotedMessageProps, removeQuotedMessage } = props; const theme = useTheme();
const theme = useContext(ThemeContext); const quotedMessageProps = useSelector(getQuotedMessage);
const dispatch = useDispatch();
const { text: body, attachments } = quotedMessageProps; const { text: body, attachments } = quotedMessageProps || {};
const hasAttachments = attachments && attachments.length > 0; const hasAttachments = attachments && attachments.length > 0;
let hasImageAttachment = false; let hasImageAttachment = false;
@ -61,6 +59,14 @@ export const SessionQuotedMessageComposition = (props: Props) => {
const hasAudioAttachment = const hasAudioAttachment =
hasAttachments && attachments && attachments.length > 0 && isAudio(attachments); hasAttachments && attachments && attachments.length > 0 && isAudio(attachments);
const removeQuotedMessage = useCallback(() => {
dispatch(quoteMessage(undefined));
}, []);
if (!quotedMessageProps?.id) {
return null;
}
return ( return (
<QuotedMessageComposition theme={theme}> <QuotedMessageComposition theme={theme}>
<Flex <Flex

@ -34,6 +34,7 @@ import {
} from '../data/data'; } from '../data/data';
import { import {
conversationReset, conversationReset,
quoteMessage,
resetSelectedMessageIds, resetSelectedMessageIds,
SortedMessageModelProps, SortedMessageModelProps,
} from '../state/ducks/conversations'; } from '../state/ducks/conversations';
@ -43,6 +44,7 @@ import { FSv2 } from '../fileserver';
import { fromBase64ToArray, toHex } from '../session/utils/String'; import { fromBase64ToArray, toHex } from '../session/utils/String';
import { SessionButtonColor } from '../components/session/SessionButton'; import { SessionButtonColor } from '../components/session/SessionButton';
import { perfEnd, perfStart } from '../session/utils/Performance'; import { perfEnd, perfStart } from '../session/utils/Performance';
import { ReplyingToMessageProps } from '../components/session/conversation/SessionCompositionBox';
export const getCompleteUrlForV2ConvoId = async (convoId: string) => { export const getCompleteUrlForV2ConvoId = async (convoId: string) => {
if (convoId.match(openGroupV2ConversationIdRegex)) { if (convoId.match(openGroupV2ConversationIdRegex)) {
@ -532,3 +534,22 @@ export async function deleteMessagesById(
void doDelete(); void doDelete();
} }
} }
export async function replyToMessage(messageId: string) {
const quotedMessageModel = await getMessageById(messageId);
if (!quotedMessageModel) {
window.log.warn('Failed to find message to reply to');
return;
}
const conversationModel = getConversationController().getOrThrow(
quotedMessageModel.get('conversationId')
);
const quotedMessageProps = await conversationModel.makeQuote(quotedMessageModel);
if (quotedMessageProps) {
window.inboxStore?.dispatch(quoteMessage(quotedMessageProps));
} else {
window.inboxStore?.dispatch(quoteMessage(undefined));
}
}

@ -43,6 +43,7 @@ import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil';
import { getOpenGroupV2FromConversationId } from '../opengroup/utils/OpenGroupUtils'; import { getOpenGroupV2FromConversationId } from '../opengroup/utils/OpenGroupUtils';
import { createTaskWithTimeout } from '../session/utils/TaskWithTimeout'; import { createTaskWithTimeout } from '../session/utils/TaskWithTimeout';
import { perfEnd, perfStart } from '../session/utils/Performance'; import { perfEnd, perfStart } from '../session/utils/Performance';
import { ReplyingToMessageProps } from '../components/session/conversation/SessionCompositionBox';
export enum ConversationTypeEnum { export enum ConversationTypeEnum {
GROUP = 'group', GROUP = 'group',
@ -566,17 +567,24 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
return []; return [];
} }
public async makeQuote(quotedMessage: MessageModel) { public async makeQuote(quotedMessage: MessageModel): Promise<ReplyingToMessageProps | null> {
const attachments = quotedMessage.get('attachments'); const attachments = quotedMessage.get('attachments');
const preview = quotedMessage.get('preview'); const preview = quotedMessage.get('preview');
const body = quotedMessage.get('body'); const body = quotedMessage.get('body');
const quotedAttachments = await this.getQuoteAttachment(attachments, preview); const quotedAttachments = await this.getQuoteAttachment(attachments, preview);
if (!quotedMessage.get('sent_at')) {
window.log.warn('tried to make a quote without a sent_at timestamp');
return null;
}
return { return {
author: quotedMessage.getSource(), author: quotedMessage.getSource(),
id: quotedMessage.get('sent_at'), id: `${quotedMessage.get('sent_at')}` || '',
text: body, text: body,
attachments: quotedAttachments, attachments: quotedAttachments,
timestamp: quotedMessage.get('sent_at') || 0,
convoId: this.id,
}; };
} }

@ -529,6 +529,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
const conversation = this.getConversation(); const conversation = this.getConversation();
const isGroup = !!conversation && !conversation.isPrivate(); const isGroup = !!conversation && !conversation.isPrivate();
const isBlocked = conversation?.isBlocked() || false;
const isPublic = !!this.get('isPublic'); const isPublic = !!this.get('isPublic');
const isPublicOpenGroupV2 = isOpenGroupV2(this.getConversation()?.id || ''); const isPublicOpenGroupV2 = isOpenGroupV2(this.getConversation()?.id || '');
@ -568,6 +569,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
expirationLength, expirationLength,
expirationTimestamp, expirationTimestamp,
isPublic, isPublic,
isBlocked,
isOpenGroupV2: isPublicOpenGroupV2, isOpenGroupV2: isPublicOpenGroupV2,
isKickedFromGroup: conversation?.get('isKickedFromGroup'), isKickedFromGroup: conversation?.get('isKickedFromGroup'),
isTrustedForAttachmentDownload, isTrustedForAttachmentDownload,
@ -774,9 +776,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
conversationType: ConversationTypeEnum.PRIVATE, conversationType: ConversationTypeEnum.PRIVATE,
multiSelectMode: false, multiSelectMode: false,
firstMessageOfSeries: false, firstMessageOfSeries: false,
onReply: noop,
// tslint:disable-next-line: no-async-without-await no-empty
onQuoteClick: async () => {},
}, },
errors, errors,
contacts: sortedContacts || [], contacts: sortedContacts || [],

@ -237,6 +237,7 @@ export interface MessageRegularProps {
expirationTimestamp?: number; expirationTimestamp?: number;
convoId: string; convoId: string;
isPublic?: boolean; isPublic?: boolean;
isBlocked: boolean;
isOpenGroupV2?: boolean; isOpenGroupV2?: boolean;
isKickedFromGroup: boolean; isKickedFromGroup: boolean;
// whether or not to show check boxes // whether or not to show check boxes
@ -245,8 +246,6 @@ export interface MessageRegularProps {
isUnread: boolean; isUnread: boolean;
isQuotedMessageToAnimate?: boolean; isQuotedMessageToAnimate?: boolean;
isTrustedForAttachmentDownload: boolean; isTrustedForAttachmentDownload: boolean;
onReply: (messagId: number) => void;
onQuoteClick: (options: QuoteClickOptions) => Promise<void>; onQuoteClick: (options: QuoteClickOptions) => Promise<void>;
playableMessageIndex?: number; playableMessageIndex?: number;

@ -16,6 +16,7 @@ import {
} from '../../models/messageType'; } from '../../models/messageType';
import { NotificationForConvoOption } from '../../components/conversation/ConversationHeader'; import { NotificationForConvoOption } from '../../components/conversation/ConversationHeader';
import { LightBoxOptions } from '../../components/session/conversation/SessionConversation'; import { LightBoxOptions } from '../../components/session/conversation/SessionConversation';
import { ReplyingToMessageProps } from '../../components/session/conversation/SessionCompositionBox';
export type MessageModelProps = { export type MessageModelProps = {
propsForMessage: PropsForMessage; propsForMessage: PropsForMessage;
@ -181,6 +182,7 @@ export type PropsForMessage = {
isSenderAdmin: boolean; isSenderAdmin: boolean;
isDeletable: boolean; isDeletable: boolean;
isExpired: boolean; isExpired: boolean;
isBlocked: boolean;
}; };
export type LastMessageType = { export type LastMessageType = {
@ -235,6 +237,7 @@ export type ConversationsStateType = {
showRightPanel: boolean; showRightPanel: boolean;
selectedMessageIds: Array<string>; selectedMessageIds: Array<string>;
lightBox?: LightBoxOptions; lightBox?: LightBoxOptions;
quotedMessage?: ReplyingToMessageProps;
}; };
async function getMessages( async function getMessages(
@ -708,6 +711,8 @@ const conversationsSlice = createSlice({
state.selectedMessageIds = []; state.selectedMessageIds = [];
state.selectedConversation = action.payload.id; state.selectedConversation = action.payload.id;
state.messages = []; state.messages = [];
state.quotedMessage = undefined;
state.lightBox = undefined;
return state; return state;
}, },
showLightBox( showLightBox(
@ -717,6 +722,13 @@ const conversationsSlice = createSlice({
state.lightBox = action.payload; state.lightBox = action.payload;
return state; return state;
}, },
quoteMessage(
state: ConversationsStateType,
action: PayloadAction<ReplyingToMessageProps | undefined>
) {
state.quotedMessage = action.payload;
return state;
},
}, },
extraReducers: (builder: any) => { extraReducers: (builder: any) => {
// Add reducers for additional action types here, and handle loading state as needed // Add reducers for additional action types here, and handle loading state as needed
@ -762,4 +774,5 @@ export const {
resetSelectedMessageIds, resetSelectedMessageIds,
toggleSelectedMessageId, toggleSelectedMessageId,
showLightBox, showLightBox,
quoteMessage,
} = actions; } = actions;

@ -18,6 +18,7 @@ import {
ConversationHeaderTitleProps, ConversationHeaderTitleProps,
} from '../../components/conversation/ConversationHeader'; } from '../../components/conversation/ConversationHeader';
import { LightBoxOptions } from '../../components/session/conversation/SessionConversation'; import { LightBoxOptions } from '../../components/session/conversation/SessionConversation';
import { ReplyingToMessageProps } from '../../components/session/conversation/SessionCompositionBox';
export const getConversations = (state: StateType): ConversationsStateType => state.conversations; export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
@ -289,3 +290,8 @@ export const getLightBoxOptions = createSelector(
getConversations, getConversations,
(state: ConversationsStateType): LightBoxOptions | undefined => state.lightBox (state: ConversationsStateType): LightBoxOptions | undefined => state.lightBox
); );
export const getQuotedMessage = createSelector(
getConversations,
(state: ConversationsStateType): ReplyingToMessageProps | undefined => state.quotedMessage
);

Loading…
Cancel
Save