diff --git a/lib/hooks/sidebar-hooks.js b/lib/hooks/sidebar-hooks.js index 3f9710c8aa..e7e5c4e81c 100644 --- a/lib/hooks/sidebar-hooks.js +++ b/lib/hooks/sidebar-hooks.js @@ -3,18 +3,32 @@ import _orderBy from 'lodash/fp/orderBy.js'; import * as React from 'react'; -import { useGetLastUpdatedTimes } from './thread-time.js'; import { childThreadInfos } from '../selectors/thread-selectors.js'; import { getMostRecentNonLocalMessageID } from '../shared/message-utils.js'; import { threadInChatList } from '../shared/thread-utils.js'; +import type { MessageStore, RawMessageInfo } from '../types/message-types.js'; +import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; import { threadTypeIsSidebar } from '../types/thread-types-enum.js'; import type { SidebarInfo } from '../types/thread-types.js'; import { useSelector } from '../utils/redux-utils.js'; +function getMostRecentRawMessageInfo( + threadInfo: ThreadInfo, + messageStore: MessageStore, +): ?RawMessageInfo { + const thread = messageStore.threads[threadInfo.id]; + if (!thread) { + return null; + } + for (const messageID of thread.messageIDs) { + return messageStore.messages[messageID]; + } + return null; +} + function useSidebarInfos(): { +[id: string]: $ReadOnlyArray } { const childThreadInfoByParentID = useSelector(childThreadInfos); const messageStore = useSelector(state => state.messageStore); - const getLastUpdatedTimes = useGetLastUpdatedTimes(); return React.useMemo(() => { const result: { [id: string]: $ReadOnlyArray } = {}; @@ -28,11 +42,12 @@ function useSidebarInfos(): { +[id: string]: $ReadOnlyArray } { ) { continue; } - const { lastUpdatedAtLeastTime: lastUpdatedTime } = getLastUpdatedTimes( + const mostRecentRawMessageInfo = getMostRecentRawMessageInfo( childThreadInfo, messageStore, - messageStore.messages, ); + const lastUpdatedTime = + mostRecentRawMessageInfo?.time ?? childThreadInfo.creationTime; const mostRecentNonLocalMessage = getMostRecentNonLocalMessageID( childThreadInfo.id, messageStore, @@ -46,7 +61,7 @@ function useSidebarInfos(): { +[id: string]: $ReadOnlyArray } { result[parentID] = _orderBy('lastUpdatedTime')('desc')(sidebarInfos); } return result; - }, [childThreadInfoByParentID, messageStore, getLastUpdatedTimes]); + }, [childThreadInfoByParentID, messageStore]); } export { useSidebarInfos }; diff --git a/lib/hooks/thread-time.js b/lib/hooks/thread-time.js index 0a33e9a1b0..1bb46590df 100644 --- a/lib/hooks/thread-time.js +++ b/lib/hooks/thread-time.js @@ -1,107 +1,25 @@ // @flow -import * as React from 'react'; - -import { useGetLatestMessageEdit } from './latest-message-edit.js'; -import { messageSpecs } from '../shared/messages/message-specs.js'; -import type { - MessageInfo, - RawMessageInfo, - MessageStore, -} from '../types/message-types.js'; +import type { MessageInfo, MessageStore } from '../types/message-types.js'; import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; -import type { LastUpdatedTimes } from '../types/thread-types.js'; -import { useSelector } from '../utils/redux-utils.js'; -function useGetLastUpdatedTimes(): ( +function getLastUpdatedTime( threadInfo: ThreadInfo, messageStore: MessageStore, - messages: { +[id: string]: ?MessageInfo | RawMessageInfo }, -) => LastUpdatedTimes { - const viewerID = useSelector(state => state.currentUserInfo?.id); - const fetchMessage = useGetLatestMessageEdit(); - return React.useCallback( - (threadInfo, messageStore, messages) => { - // This callback returns two variables: - // - lastUpdatedTime: this is a Promise that resolves with the final value - // - lastUpdatedAtLeastTime: this is a number that represents what we - // should use while we're waiting for lastUpdatedTime to resolve. It's - // set based on the most recent message whose spec returns a non-Promise - // when getLastUpdatedTime is called - let lastUpdatedAtLeastTime = threadInfo.creationTime; - - const thread = messageStore.threads[threadInfo.id]; - if (!thread || !viewerID) { - return { - lastUpdatedAtLeastTime, - lastUpdatedTime: Promise.resolve(lastUpdatedAtLeastTime), - }; - } - - const getLastUpdatedTimeParams = { - threadInfo, - viewerID, - fetchMessage, - }; - - let lastUpdatedTime: ?Promise; - for (const messageID of thread.messageIDs) { - const messageInfo = messages[messageID]; - if (!messageInfo) { - continue; - } - - // We call getLastUpdatedTime on the message spec. It can return either - // ?number or Promise. If the message spec doesn't implement - // getLastUpdatedTime, then we default to messageInfo.time. - const { getLastUpdatedTime } = messageSpecs[messageInfo.type]; - const lastUpdatedTimePromisable = getLastUpdatedTime - ? getLastUpdatedTime(messageInfo, getLastUpdatedTimeParams) - : messageInfo.time; - - // We rely on the fact that thread.messageIDs is ordered chronologically - // (newest first) to chain together lastUpdatedTime. An older message's - // lastUpdatedTime is only considered if all of the newer messages - // return falsey. - lastUpdatedTime = (async () => { - if (lastUpdatedTime) { - const earlierChecks = await lastUpdatedTime; - if (earlierChecks) { - return earlierChecks; - } - } - return await lastUpdatedTimePromisable; - })(); - - if (typeof lastUpdatedTimePromisable === 'number') { - // We break from the loop the first time this condition is met. - // There's no need to consider any older messages, since both - // lastUpdated and lastUpdatedAtLeastTime will be this value (or - // higher, in the case of lastUpdated). That is also why this loop - // only sets lastUpdatedAtLeastTime once: once we get to this - // "baseline" case, there's no need to consider any more messages. - lastUpdatedAtLeastTime = lastUpdatedTimePromisable; - break; - } - } - - const lastUpdatedWithFallback = (async () => { - if (lastUpdatedTime) { - const earlierChecks = await lastUpdatedTime; - if (earlierChecks) { - return earlierChecks; - } - } - return lastUpdatedAtLeastTime; - })(); - - return { - lastUpdatedAtLeastTime, - lastUpdatedTime: lastUpdatedWithFallback, - }; - }, - [viewerID, fetchMessage], - ); + messages: { +[id: string]: ?MessageInfo }, +): number { + const thread = messageStore.threads[threadInfo.id]; + if (!thread) { + return threadInfo.creationTime; + } + for (const messageID of thread.messageIDs) { + const messageInfo = messages[messageID]; + if (!messageInfo) { + continue; + } + return messageInfo.time; + } + return threadInfo.creationTime; } -export { useGetLastUpdatedTimes }; +export { getLastUpdatedTime }; diff --git a/lib/selectors/chat-selectors.js b/lib/selectors/chat-selectors.js index d62b05247f..dc6f9787d3 100644 --- a/lib/selectors/chat-selectors.js +++ b/lib/selectors/chat-selectors.js @@ -14,7 +14,7 @@ import { threadInfoSelector, } from './thread-selectors.js'; import { useSidebarInfos } from '../hooks/sidebar-hooks.js'; -import { useGetLastUpdatedTimes } from '../hooks/thread-time.js'; +import { getLastUpdatedTime } from '../hooks/thread-time.js'; import { createMessageInfo, getMostRecentNonLocalMessageID, @@ -97,15 +97,13 @@ function useCreateChatThreadItem(): ThreadInfo => ChatThreadItem { const messageInfos = useSelector(messageInfoSelector); const sidebarInfos = useSidebarInfos(); const messageStore = useSelector(state => state.messageStore); - const getLastUpdatedTimes = useGetLastUpdatedTimes(); return React.useCallback( threadInfo => { const mostRecentNonLocalMessage = getMostRecentNonLocalMessageID( threadInfo.id, messageStore, ); - - const { lastUpdatedAtLeastTime: lastUpdatedTime } = getLastUpdatedTimes( + const lastUpdatedTime = getLastUpdatedTime( threadInfo, messageStore, messageInfos, @@ -172,7 +170,7 @@ function useCreateChatThreadItem(): ThreadInfo => ChatThreadItem { sidebars: sidebarItems, }; }, - [messageInfos, messageStore, sidebarInfos, getLastUpdatedTimes], + [messageInfos, messageStore, sidebarInfos], ); } diff --git a/lib/shared/messages/message-spec.js b/lib/shared/messages/message-spec.js index 6774f694ab..6356f6647c 100644 --- a/lib/shared/messages/message-spec.js +++ b/lib/shared/messages/message-spec.js @@ -141,8 +141,4 @@ export type MessageSpec = { messageInfo: Info, params: ShowInMessagePreviewParams, ) => Promise, - +getLastUpdatedTime?: ( - messageInfoOrRawMessageInfo: Info | RawInfo, - params: ShowInMessagePreviewParams, - ) => ?number | Promise, }; diff --git a/lib/shared/messages/multimedia-message-spec.js b/lib/shared/messages/multimedia-message-spec.js index de5ba1cbcd..5ac2efa274 100644 --- a/lib/shared/messages/multimedia-message-spec.js +++ b/lib/shared/messages/multimedia-message-spec.js @@ -369,14 +369,6 @@ export const multimediaMessageSpec: MultimediaMessageSpec = Object.freeze({ showInMessagePreview: (messageInfo: MediaMessageInfo | ImagesMessageInfo) => Promise.resolve(messageInfo.media.length > 0), - - getLastUpdatedTime: ( - messageInfo: - | MediaMessageInfo - | ImagesMessageInfo - | RawMediaMessageInfo - | RawImagesMessageInfo, - ) => (messageInfo.media.length > 0 ? messageInfo.time : null), }); // Four photos were uploaded before dimensions were calculated server-side, diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js index 771c147728..8e2b8d0b6b 100644 --- a/lib/types/thread-types.js +++ b/lib/types/thread-types.js @@ -436,13 +436,6 @@ export type ThreadFetchMediaRequest = { +offset: number, }; -export type LastUpdatedTimes = { - // The last updated time is at least this number, but possibly higher - // We won't know for sure until the below Promise resolves - +lastUpdatedAtLeastTime: number, - +lastUpdatedTime: Promise, -}; - export type SidebarInfo = { +threadInfo: ThreadInfo, +lastUpdatedTime: number,