diff --git a/ts/components/conversation/message/message-content/MessageQuote.tsx b/ts/components/conversation/message/message-content/MessageQuote.tsx index 4f0acf481..bb605c708 100644 --- a/ts/components/conversation/message/message-content/MessageQuote.tsx +++ b/ts/components/conversation/message/message-content/MessageQuote.tsx @@ -10,6 +10,7 @@ import { } from '../../../../state/selectors/conversations'; import { Quote } from './quote/Quote'; import { ToastUtils } from '../../../../session/utils'; +import { Data } from '../../../../data/data'; // tslint:disable: use-simple-attributes @@ -41,8 +42,6 @@ export const MessageQuote = (props: Props) => { quote.referencedMessageNotFound || !quote?.author || !quote.id || !quote.convoId ); - const quoteText = quote?.text || null; - const onQuoteClick = useCallback( async (event: React.MouseEvent) => { event.preventDefault(); @@ -59,16 +58,38 @@ export const MessageQuote = (props: Props) => { return; } + let conversationKey = String(quote.convoId); + let messageIdToNavigateTo = String(quote.id); + let quoteNotFoundInDB = false; + + // If the quote is not found in memory, we try to find it in the DB + if (quoteNotFound && quote.id && quote.author) { + const quotedMessagesCollection = await Data.getMessagesBySenderAndSentAt([ + { timestamp: Number(quote.id), source: quote.author }, + ]); + + if (quotedMessagesCollection?.length) { + const quotedMessage = quotedMessagesCollection.at(0); + // If found, we navigate to the quoted message which also refreshes the message quote component + if (quotedMessage) { + conversationKey = String(quotedMessage.get('conversationId')); + messageIdToNavigateTo = String(quotedMessage.id); + } else { + quoteNotFoundInDB = true; + } + } + } + // For simplicity's sake, we show the 'not found' toast no matter what if we were // not able to find the referenced message when the quote was received or if the conversation no longer exists. - if (quoteNotFound) { + if (quoteNotFoundInDB) { ToastUtils.pushOriginalNotFound(); return; } void openConversationToSpecificMessage({ - conversationKey: String(quote.convoId), - messageIdToNavigateTo: String(quote.id), + conversationKey, + messageIdToNavigateTo, shouldHighlightMessage: true, }); }, @@ -78,7 +99,7 @@ export const MessageQuote = (props: Props) => { return ( ) => void; }; diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index ef5c9492d..2dd30d575 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -569,11 +569,18 @@ function handleMessageExpiredOrDeleted( const messageInStoreIndex = state?.messages.findIndex(m => m.propsForMessage.id === messageId); const editedQuotes = { ...state.quotes }; if (messageInStoreIndex >= 0) { + // we cannot edit the array directly, so slice the first part, and slice the second part, + // keeping the index removed out + const editedMessages = [ + ...state.messages.slice(0, messageInStoreIndex), + ...state.messages.slice(messageInStoreIndex + 1), + ]; + // Check if the message is quoted somewhere, and if so, remove it from the quotes const msgProps = state.messages[messageInStoreIndex].propsForMessage; const { timestamp, sender } = msgProps; if (timestamp && sender) { - const message2Delete = lookupQuote(editedQuotes, timestamp, sender); + const message2Delete = lookupQuote(editedQuotes, editedMessages, timestamp, sender); window.log.debug( `Deleting quote {${timestamp}-${sender}} ${JSON.stringify(message2Delete)}` ); @@ -582,13 +589,6 @@ function handleMessageExpiredOrDeleted( delete editedQuotes[`${timestamp}-${sender}`]; } - // we cannot edit the array directly, so slice the first part, and slice the second part, - // keeping the index removed out - const editedMessages = [ - ...state.messages.slice(0, messageInStoreIndex), - ...state.messages.slice(messageInStoreIndex + 1), - ]; - // FIXME two other thing we have to do: // * update the last message text if the message deleted was the last one // * update the unread count of the convo if the message was the one counted as an unread @@ -1166,8 +1166,27 @@ export async function openConversationToSpecificMessage(args: { */ export function lookupQuote( quotes: QuoteLookupType, + messages: Array, timestamp: number, author: string ): MessageModelPropsWithoutConvoProps | undefined { - return quotes[`${timestamp}-${author}`]; + let sourceMessage = quotes[`${timestamp}-${author}`]; + + // NOTE If a quote is processed but we haven't triggered a render, the quote might not be in the lookup map yet so we check the messages in memory. + if (!sourceMessage) { + const quotedMessages = messages.filter(message => { + const msgProps = message.propsForMessage; + return msgProps.timestamp === timestamp && msgProps.sender === author; + }); + + if (quotedMessages?.length) { + for (const quotedMessage of quotedMessages) { + if (quotedMessage) { + sourceMessage = quotedMessage; + } + } + } + } + + return sourceMessage; } diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index ab07ed77d..e9bc5d7b1 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -983,10 +983,12 @@ export const getMessageLinkPreviewProps = createSelector(getMessagePropsByMessag // tslint:disable: cyclomatic-complexity export const getMessageQuoteProps = createSelector( getConversationLookup, + getMessagesOfSelectedConversation, getConversationQuotes, getMessagePropsByMessageId, ( conversationLookup, + messagesProps, quotesProps, msgModel ): { direction: MessageModelType; quote: PropsForQuote } | undefined => { @@ -1001,7 +1003,9 @@ export const getMessageQuoteProps = createSelector( return undefined; } - let { id, author } = msgProps.quote; + const id = msgProps.quote.id; + let author = msgProps.quote.author; + if (!id || !author) { return undefined; } @@ -1017,6 +1021,7 @@ export const getMessageQuoteProps = createSelector( const quoteNotFound = { direction, quote: { + id, author, isFromMe, referencedMessageNotFound: true, @@ -1027,7 +1032,7 @@ export const getMessageQuoteProps = createSelector( return quoteNotFound; } - const sourceMessage = lookupQuote(quotesProps, Number(id), author); + const sourceMessage = lookupQuote(quotesProps, messagesProps, Number(id), author); if (!sourceMessage) { return quoteNotFound; }