From 87830f574812976caf0ff87c81b0759f5ae7e41d Mon Sep 17 00:00:00 2001 From: Rohan Khanderia Date: Tue, 28 Nov 2023 11:44:45 -0500 Subject: [PATCH] [lib] Detect a valid ENS name in search experiences Summary: Now that we have a regex to capture a valid ENS name and we have consolidated the search functions that will need to be updated to perform a 'forward lookup', we need to actually make the changes to these two functions (`useThreadListSearch` and `useSearchUsers`). The important change here is the introduction of `useForwardLookupSearchText`, a hook that will attempt to match the search text to a valid ENS name. If so, it then executes the `getAddressForName` call (so we can map something like `jack.eth` to `0x837412947319247` if it's a valid user). If no matched wallet address is found for the username search text, we just return the original search text. The approach in both `useThreadListSearch` and `useSearchUsers` is functionally the same. Instead of just using the username search text provided from the parameter, we call `useForwardLookupSearchText` with it to either get the wallet address that matches the ENS user OR default back to the original provided search text. (Small note: `useThreadListSearch` already works fine for threads with ENS users). Addresses [[ https://linear.app/comm/issue/ENG-5412/detect-a-valid-ens-name-in-search-experiences | ENG-5412 ]], [[ https://linear.app/comm/issue/ENG-5414/execute-a-forward-lookup-upon-ens-name-detection | ENG-5414 ]] and [[ https://linear.app/comm/issue/ENG-5415/include-the-matched-ens-user-in-the-search-results | ENG-5415 ]]. Depends on D9884 Test Plan: Please see the attached videos below that covers both `web` and `native`. I'm reproducing the [[ https://linear.app/comm/issue/ENG-5478/final-testing-task | final testing task ]] plan to confirm that these changes give the expected results. `web` | Searching Inbox | {F876661} | | Composing a new chat | {F876664} | | Add friends from friends list | {F876665} | `native (dev)` | Searching Inbox | {F879319} | | Composing a new chat | {F879316} | | Add friends from friends list | {F879317} | `native (prod)` | Searching Inbox | {F879362} | | Composing a new chat | {F879357} | | Add friends from friends list | {F879361} | Reviewers: atul, ginsu, inka Reviewed By: ginsu Subscribers: ashoat, tomek Differential Revision: https://phab.comm.dev/D9885 --- lib/shared/search-utils.js | 37 ++++++++++++++++++++++++++++++++++--- lib/shared/thread-utils.js | 6 ++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/shared/search-utils.js b/lib/shared/search-utils.js index 5151d37d12..a4b864cd50 100644 --- a/lib/shared/search-utils.js +++ b/lib/shared/search-utils.js @@ -17,6 +17,7 @@ import { searchUsers, searchUsersActionTypes, } from '../actions/user-actions.js'; +import { ENSCacheContext } from '../components/ens-cache-provider.react.js'; import genesis from '../facts/genesis.js'; import type { ChatMessageInfoItem, @@ -37,6 +38,7 @@ import { useServerCall, useDispatchActionPromise, } from '../utils/action-utils.js'; +import { isValidENSName } from '../utils/ens-helpers.js'; import { values } from '../utils/objects.js'; import { useSelector } from '../utils/redux-utils.js'; @@ -278,12 +280,40 @@ function useSearchMessages(): ( ); } +function useForwardLookupSearchText(originalText: string): string { + const cacheContext = React.useContext(ENSCacheContext); + const { ensCache } = cacheContext; + const lowercaseText = originalText.toLowerCase(); + + const [usernameToSearch, setUsernameToSearch] = + React.useState(lowercaseText); + + React.useEffect(() => { + (async () => { + if (!ensCache || !isValidENSName(lowercaseText)) { + setUsernameToSearch(lowercaseText); + return; + } + + const address = await ensCache.getAddressForName(lowercaseText); + if (address) { + setUsernameToSearch(address); + } else { + setUsernameToSearch(lowercaseText); + } + })(); + }, [ensCache, lowercaseText]); + + return usernameToSearch; +} + function useSearchUsers( usernameInputText: string, ): $ReadOnlyArray { const currentUserID = useSelector( state => state.currentUserInfo && state.currentUserInfo.id, ); + const forwardLookupSearchText = useForwardLookupSearchText(usernameInputText); const [serverSearchResults, setServerSearchResults] = React.useState< $ReadOnlyArray, @@ -292,11 +322,11 @@ function useSearchUsers( const dispatchActionPromise = useDispatchActionPromise(); React.useEffect(() => { const searchUsersPromise = (async () => { - if (usernameInputText.length === 0) { + if (forwardLookupSearchText.length === 0) { setServerSearchResults([]); } else { try { - const { userInfos } = await callSearchUsers(usernameInputText); + const { userInfos } = await callSearchUsers(forwardLookupSearchText); setServerSearchResults( userInfos.filter(({ id }) => id !== currentUserID), ); @@ -310,7 +340,7 @@ function useSearchUsers( callSearchUsers, currentUserID, dispatchActionPromise, - usernameInputText, + forwardLookupSearchText, ]); return serverSearchResults; @@ -354,4 +384,5 @@ export { useSearchMessages, useSearchUsers, filterChatMessageInfosForSearch, + useForwardLookupSearchText, }; diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js index 6dd2de64bc..4a34c13801 100644 --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -11,6 +11,7 @@ import { type ParserRules } from './markdown.js'; import { extractUserMentionsFromText } from './mention-utils.js'; import { getMessageTitle, isInvalidSidebarSource } from './message-utils.js'; import { relationshipBlockedInEitherDirection } from './relationship-utils.js'; +import { useForwardLookupSearchText } from './search-utils.js'; import threadWatcher from './thread-watcher.js'; import { fetchMostRecentMessagesActionTypes, @@ -1513,6 +1514,7 @@ function useThreadListSearch( ): ThreadListSearchResult { const callSearchUsers = useServerCall(searchUserCall); const usersWithPersonalThread = useSelector(usersWithPersonalThreadSelector); + const forwardLookupSearchText = useForwardLookupSearchText(searchText); const searchUsers = React.useCallback( async (usernamePrefix: string) => { if (usernamePrefix.length === 0) { @@ -1538,10 +1540,10 @@ function useThreadListSearch( (async () => { const results = threadSearchIndex.getSearchResults(searchText); setThreadSearchResults(new Set(results)); - const usersResults = await searchUsers(searchText); + const usersResults = await searchUsers(forwardLookupSearchText); setUsersSearchResults(usersResults); })(); - }, [searchText, threadSearchIndex, searchUsers]); + }, [searchText, forwardLookupSearchText, threadSearchIndex, searchUsers]); return { threadSearchResults, usersSearchResults }; }