Page MenuHomePhabricator

D8833.id30100.diff
No OneTemporary

D8833.id30100.diff

diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js
--- a/lib/shared/thread-utils.js
+++ b/lib/shared/thread-utils.js
@@ -1,6 +1,7 @@
// @flow
import invariant from 'invariant';
+import _clone from 'lodash/clone.js';
import _find from 'lodash/fp/find.js';
import _mapValues from 'lodash/fp/mapValues.js';
import _omitBy from 'lodash/fp/omitBy.js';
@@ -77,6 +78,9 @@
type ClientNewThreadRequest,
type NewThreadResult,
type ChangeThreadSettingsPayload,
+ type ResolvedThreadInfo,
+ type ChatMentionCandidatesObj,
+ type ChatMentionCandidates,
} from '../types/thread-types.js';
import { updateTypes } from '../types/update-types-enum.js';
import { type ClientUpdateInfo } from '../types/update-types.js';
@@ -92,6 +96,7 @@
} from '../utils/action-utils.js';
import type { DispatchActionPromise } from '../utils/action-utils.js';
import type { GetENSNames } from '../utils/ens-helpers.js';
+import { useResolvedThreadInfosObj } from '../utils/entity-helpers.js';
import {
ET,
entityTextToRawString,
@@ -1621,6 +1626,138 @@
} within this ${communityOrThreadNoun(threadInfo)}`;
}
+function getChatMentionCandidates(threadInfos: {
+ +[id: string]: ResolvedThreadInfo,
+}): ChatMentionCandidatesObj {
+ const result = {};
+ const visitedGenesisThreads = new Set();
+ for (const currentThreadID in threadInfos) {
+ const currentThreadInfo = threadInfos[currentThreadID];
+ const { community: currentThreadCommunity } = currentThreadInfo;
+ if (!currentThreadCommunity) {
+ if (!result[currentThreadID]) {
+ result[currentThreadID] = { [currentThreadID]: currentThreadInfo };
+ }
+ continue;
+ }
+ if (!result[currentThreadCommunity]) {
+ result[currentThreadCommunity] = {
+ [currentThreadCommunity]: threadInfos[currentThreadCommunity],
+ };
+ }
+ // Handle GENESIS community case: mentioning inside GENESIS should only
+ // show chats and threads inside the top level that is below GENESIS.
+ if (threadInfos[currentThreadCommunity].type === threadTypes.GENESIS) {
+ if (visitedGenesisThreads.has(currentThreadID)) {
+ continue;
+ }
+ const threadTraversePath = [currentThreadInfo];
+ visitedGenesisThreads.add(currentThreadID);
+ let currentlySelectedThreadID = currentThreadInfo.parentThreadID;
+ while (currentlySelectedThreadID) {
+ const currentlySelectedThreadInfo =
+ threadInfos[currentlySelectedThreadID];
+ if (
+ visitedGenesisThreads.has(currentlySelectedThreadID) ||
+ currentlySelectedThreadInfo.type === threadTypes.GENESIS
+ ) {
+ break;
+ }
+ threadTraversePath.push(currentlySelectedThreadInfo);
+ visitedGenesisThreads.add(currentlySelectedThreadID);
+ currentlySelectedThreadID = currentlySelectedThreadInfo.parentThreadID;
+ }
+ const lastThreadInTraversePath =
+ threadTraversePath[threadTraversePath.length - 1];
+ let lastThreadInTraversePathParentID;
+ if (lastThreadInTraversePath.parentThreadID) {
+ lastThreadInTraversePathParentID = threadInfos[
+ lastThreadInTraversePath.parentThreadID
+ ]
+ ? lastThreadInTraversePath.parentThreadID
+ : lastThreadInTraversePath.id;
+ } else {
+ lastThreadInTraversePathParentID = lastThreadInTraversePath.id;
+ }
+ if (
+ threadInfos[lastThreadInTraversePathParentID].type ===
+ threadTypes.GENESIS
+ ) {
+ const threadObjectFromTraversePath = {};
+ for (const threadInfo of threadTraversePath) {
+ threadObjectFromTraversePath[threadInfo.id] = threadInfo;
+ result[threadInfo.id] = threadObjectFromTraversePath;
+ }
+ } else {
+ if (!result[lastThreadInTraversePathParentID]) {
+ result[lastThreadInTraversePathParentID] = {};
+ }
+ for (const threadInfo of threadTraversePath) {
+ result[lastThreadInTraversePathParentID][threadInfo.id] = threadInfo;
+ result[threadInfo.id] = result[lastThreadInTraversePathParentID];
+ }
+ }
+ continue;
+ }
+ result[currentThreadCommunity][currentThreadID] = currentThreadInfo;
+ result[currentThreadID] = result[currentThreadCommunity];
+ }
+
+ for (const currentThreadID in threadInfos) {
+ result[currentThreadID] = _clone(result[currentThreadID]);
+ delete result[currentThreadID][currentThreadID];
+ }
+
+ return result;
+}
+
+function useChatMentionCandidatesObjAndResolvedThreadInfos(): [
+ ChatMentionCandidatesObj,
+ { +[id: string]: ResolvedThreadInfo },
+] {
+ const threadInfos = useSelector(threadInfoSelector);
+ const resolvedThreadInfos = useResolvedThreadInfosObj(threadInfos);
+ const chatMentionCandidates = React.useMemo(
+ () => getChatMentionCandidates(resolvedThreadInfos),
+ [resolvedThreadInfos],
+ );
+ return [chatMentionCandidates, resolvedThreadInfos];
+}
+
+function useChatMentionCandidatesObj(): ChatMentionCandidatesObj {
+ const [chatMentionCandidates] =
+ useChatMentionCandidatesObjAndResolvedThreadInfos();
+ return chatMentionCandidates;
+}
+
+function useThreadChatMentionCandidates(
+ threadInfo: ThreadInfo,
+): ChatMentionCandidates {
+ const [chatMentionCandidates, resolvedThreadInfos] =
+ useChatMentionCandidatesObjAndResolvedThreadInfos();
+ return React.useMemo(() => {
+ if (chatMentionCandidates[threadInfo.id]) {
+ return chatMentionCandidates[threadInfo.id];
+ }
+ if (
+ threadInfo.containingThreadID &&
+ chatMentionCandidates[threadInfo.containingThreadID]
+ ) {
+ return {
+ ...chatMentionCandidates[threadInfo.containingThreadID],
+ [threadInfo.containingThreadID]:
+ resolvedThreadInfos[threadInfo.containingThreadID],
+ };
+ }
+ return {};
+ }, [
+ chatMentionCandidates,
+ resolvedThreadInfos,
+ threadInfo.containingThreadID,
+ threadInfo.id,
+ ]);
+}
+
export {
threadHasPermission,
viewerIsMember,
@@ -1689,4 +1826,6 @@
useRoleMemberCountsForCommunity,
useRoleUserSurfacedPermissions,
getThreadsToDeleteText,
+ useChatMentionCandidatesObj,
+ useThreadChatMentionCandidates,
};
diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js
--- a/lib/types/thread-types.js
+++ b/lib/types/thread-types.js
@@ -456,3 +456,8 @@
export const maxUnreadSidebars = 5;
export type ThreadStoreThreadInfos = { +[id: string]: RawThreadInfo };
+
+export type ChatMentionCandidates = { +[id: string]: ResolvedThreadInfo };
+export type ChatMentionCandidatesObj = {
+ +[id: string]: ChatMentionCandidates,
+};

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 6, 9:28 AM (22 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2248829
Default Alt Text
D8833.id30100.diff (6 KB)

Event Timeline