From b91388a6726a8615f4dfcda61eb75520fda68b20 Mon Sep 17 00:00:00 2001 From: William Grant Date: Fri, 2 Jun 2023 16:20:05 +1000 Subject: [PATCH] fix: SES-585 when the app is not focused message quotes now load correectly we now look up the existing messages in memory if not found in the quote lookup map, we also allow jumping to messages quoted but not yet stored in memory --- .../message/message-content/MessageQuote.tsx | 33 ++++++++++++++--- .../message/message-content/quote/Quote.tsx | 4 +- ts/state/ducks/conversations.ts | 37 ++++++++++++++----- ts/state/selectors/conversations.ts | 9 ++++- 4 files changed, 64 insertions(+), 19 deletions(-) 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; }