diff --git a/web/settings/relationship/add-users-list.react.js b/web/settings/relationship/add-users-list.react.js --- a/web/settings/relationship/add-users-list.react.js +++ b/web/settings/relationship/add-users-list.react.js @@ -3,20 +3,14 @@ import * as React from 'react'; import { useSortedENSResolvedUsers } from 'lib/hooks/ens-cache.js'; -import { useUserSearchIndex } from 'lib/selectors/nav-selectors.js'; -import { useSearchUsers } from 'lib/shared/search-utils.js'; import type { SetState } from 'lib/types/hook-types.js'; import type { UserRelationshipStatus } from 'lib/types/relationship-types.js'; -import type { - GlobalAccountUserInfo, - AccountUserInfo, -} from 'lib/types/user-types.js'; -import { values } from 'lib/utils/objects.js'; +import type { GlobalAccountUserInfo } from 'lib/types/user-types.js'; import AddUsersListItem from './add-users-list-item.react.js'; import css from './add-users-list.css'; +import { useUserRelationshipUserInfos } from './add-users-utils.js'; import Button from '../../components/button.react.js'; -import { useSelector } from '../../redux/redux-utils.js'; type Props = { +searchText: string, @@ -35,50 +29,8 @@ errorMessage, } = props; - const viewerID = useSelector(state => state.currentUserInfo?.id); - const userInfos = useSelector(state => state.userStore.userInfos); - const userInfosArray = React.useMemo(() => values(userInfos), [userInfos]); - - const userStoreSearchIndex = useUserSearchIndex(userInfosArray); - const [userStoreSearchResults, setUserStoreSearchResults] = React.useState< - $ReadOnlySet, - >(new Set(userStoreSearchIndex.getSearchResults(searchText))); - React.useEffect(() => { - setUserStoreSearchResults( - new Set(userStoreSearchIndex.getSearchResults(searchText)), - ); - }, [searchText, userStoreSearchIndex]); - - const serverSearchResults = useSearchUsers(searchText); - const searchModeActive = searchText.length > 0; - const mergedUserInfos = React.useMemo(() => { - const mergedInfos: { [string]: GlobalAccountUserInfo | AccountUserInfo } = - {}; - - for (const userInfo of serverSearchResults) { - mergedInfos[userInfo.id] = userInfo; - } - - const userStoreUserIDs = searchModeActive - ? userStoreSearchResults - : Object.keys(userInfos); - for (const id of userStoreUserIDs) { - const { username, relationshipStatus } = userInfos[id]; - if (username) { - mergedInfos[id] = { id, username, relationshipStatus }; - } - } - - return mergedInfos; - }, [ - searchModeActive, - serverSearchResults, - userInfos, - userStoreSearchResults, - ]); - const [previouslySelectedUsers, setPreviouslySelectedUsers] = React.useState< $ReadOnlyMap, >(new Map()); @@ -90,19 +42,12 @@ // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchModeActive]); - const filteredUsers = React.useMemo( - () => - Object.keys(mergedUserInfos) - .map(userID => mergedUserInfos[userID]) - .filter( - user => - user.id !== viewerID && - (!user.relationshipStatus || - !excludedStatuses.has(user.relationshipStatus)) && - !previouslySelectedUsers.has(user.id), - ), - [excludedStatuses, mergedUserInfos, viewerID, previouslySelectedUsers], - ); + const { mergedUserInfos, sortedUsersWithENSNames } = + useUserRelationshipUserInfos({ + searchText, + excludedStatuses, + previouslySelectedUsers, + }); const previouslySelectedUsersList = React.useMemo( () => Array.from(previouslySelectedUsers.values()), @@ -139,8 +84,6 @@ [mergedUserInfos, setPendingUsersToAdd, previouslySelectedUsers], ); - const sortedUsersWithENSNames = useSortedENSResolvedUsers(filteredUsers); - const userRows = React.useMemo( () => sortedUsersWithENSNames.map(userInfo => ( diff --git a/web/settings/relationship/add-users-utils.js b/web/settings/relationship/add-users-utils.js new file mode 100644 --- /dev/null +++ b/web/settings/relationship/add-users-utils.js @@ -0,0 +1,106 @@ +// @flow + +import * as React from 'react'; + +import { useSortedENSResolvedUsers } from 'lib/hooks/ens-cache.js'; +import { useUserSearchIndex } from 'lib/selectors/nav-selectors.js'; +import { useSearchUsers } from 'lib/shared/search-utils.js'; +import type { UserRelationshipStatus } from 'lib/types/relationship-types.js'; +import type { + GlobalAccountUserInfo, + AccountUserInfo, +} from 'lib/types/user-types.js'; +import { values } from 'lib/utils/objects.js'; + +import { useSelector } from '../../redux/redux-utils.js'; + +type UseUserRelationshipUserInfosParams = { + +searchText: string, + +excludedStatuses: $ReadOnlySet, + +previouslySelectedUsers: $ReadOnlyMap, +}; + +function useUserRelationshipUserInfos( + params: UseUserRelationshipUserInfosParams, +): { + +mergedUserInfos: { + [string]: GlobalAccountUserInfo | AccountUserInfo, + }, + +sortedUsersWithENSNames: $ReadOnlyArray< + GlobalAccountUserInfo | AccountUserInfo, + >, +} { + const { searchText, excludedStatuses, previouslySelectedUsers } = params; + + const viewerID = useSelector(state => state.currentUserInfo?.id); + const userInfos = useSelector(state => state.userStore.userInfos); + const userInfosArray = React.useMemo(() => values(userInfos), [userInfos]); + + const userStoreSearchIndex = useUserSearchIndex(userInfosArray); + const [userStoreSearchResults, setUserStoreSearchResults] = React.useState< + $ReadOnlySet, + >(new Set(userStoreSearchIndex.getSearchResults(searchText))); + React.useEffect(() => { + setUserStoreSearchResults( + new Set(userStoreSearchIndex.getSearchResults(searchText)), + ); + }, [searchText, userStoreSearchIndex]); + + const serverSearchResults = useSearchUsers(searchText); + + const searchModeActive = searchText.length > 0; + + const mergedUserInfos = React.useMemo(() => { + const mergedInfos: { [string]: GlobalAccountUserInfo | AccountUserInfo } = + {}; + + for (const userInfo of serverSearchResults) { + mergedInfos[userInfo.id] = userInfo; + } + + const userStoreUserIDs = searchModeActive + ? userStoreSearchResults + : Object.keys(userInfos); + for (const id of userStoreUserIDs) { + const { username, relationshipStatus } = userInfos[id]; + if (username) { + mergedInfos[id] = { id, username, relationshipStatus }; + } + } + + return mergedInfos; + }, [ + searchModeActive, + serverSearchResults, + userInfos, + userStoreSearchResults, + ]); + + const filteredUsers = React.useMemo( + () => + Object.keys(mergedUserInfos) + .map(userID => mergedUserInfos[userID]) + .filter( + user => + user.id !== viewerID && + (!user.relationshipStatus || + !excludedStatuses.has(user.relationshipStatus)) && + !previouslySelectedUsers.has(user.id), + ), + [excludedStatuses, mergedUserInfos, viewerID, previouslySelectedUsers], + ); + + const sortedUsersWithENSNames = useSortedENSResolvedUsers(filteredUsers); + + const result = React.useMemo( + () => ({ + mergedUserInfos, + sortedUsersWithENSNames, + }), + [mergedUserInfos, sortedUsersWithENSNames], + ); + + return result; +} + +export { useUserRelationshipUserInfos };