diff --git a/web/settings/relationship/add-users-list.css b/web/settings/relationship/add-users-list.css index c29f1f6ee..233cd2016 100644 --- a/web/settings/relationship/add-users-list.css +++ b/web/settings/relationship/add-users-list.css @@ -1,68 +1,61 @@ .container { height: 625px; display: flex; flex-direction: column; } -.userTagsContainer { - display: flex; - flex-wrap: wrap; - gap: 6px; - margin: 8px; -} - .userRowsContainer { overflow: auto; display: flex; flex-direction: column; flex: 1; } .userListItemContainer { display: flex; color: var(--relationship-modal-color); font-size: var(--l-font-18); line-height: var(--line-height-display); padding: 8px; } .userListItemContainer:hover { cursor: pointer; background-color: var(--listItem-background-primary-hover); border-radius: 8px; } .avatarContainer { margin: 0 8px 0 16px; } .username { color: var(--text-background-secondary-default); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .selectedUsername { color: var(--text-background-primary-default); } .confirmButtonContainer { display: flex; flex-direction: column; align-items: center; } .hidden { visibility: hidden; height: 0; } .error { padding-bottom: 8px; font-size: var(--s-font-14); line-height: var(--line-height-display); color: var(--error); padding-left: 6px; font-style: italic; } diff --git a/web/settings/relationship/add-users-list.react.js b/web/settings/relationship/add-users-list.react.js index ede500229..ee80ece00 100644 --- a/web/settings/relationship/add-users-list.react.js +++ b/web/settings/relationship/add-users-list.react.js @@ -1,177 +1,132 @@ // @flow import * as React from 'react'; import { useENSNames } 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 AddUsersListItem from './add-users-list-item.react.js'; import css from './add-users-list.css'; -import Label from '../../components/label.react.js'; import { useSelector } from '../../redux/redux-utils.js'; type Props = { +searchText: string, +excludedStatuses?: $ReadOnlySet, +errorMessage: string, }; function AddUsersList(props: Props): React.Node { const { searchText, excludedStatuses = new Set(), 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 searchTextPresent = searchText.length > 0; const mergedUserInfos = React.useMemo(() => { const mergedInfos: { [string]: GlobalAccountUserInfo | AccountUserInfo } = {}; for (const userInfo of serverSearchResults) { mergedInfos[userInfo.id] = userInfo; } const userStoreUserIDs = searchTextPresent ? userStoreSearchResults : Object.keys(userInfos); for (const id of userStoreUserIDs) { const { username, relationshipStatus } = userInfos[id]; if (username) { mergedInfos[id] = { id, username, relationshipStatus }; } } return mergedInfos; }, [ searchTextPresent, serverSearchResults, userInfos, userStoreSearchResults, ]); const sortedUsers = React.useMemo( () => Object.keys(mergedUserInfos) .map(userID => mergedUserInfos[userID]) .filter( user => user.id !== viewerID && (!user.relationshipStatus || !excludedStatuses.has(user.relationshipStatus)), ) .sort((user1, user2) => user1.username.localeCompare(user2.username)), [excludedStatuses, mergedUserInfos, viewerID], ); const [pendingUsersToAdd, setPendingUsersToAdd] = React.useState< - $ReadOnlyArray, - >([]); - const selectUser = React.useCallback( + $ReadOnlySet, + >(new Set()); + + const toggleUser = React.useCallback( (userID: string) => { setPendingUsersToAdd(pendingUsers => { - const username = mergedUserInfos[userID]?.username; - if (!username || pendingUsers.some(user => user.id === userID)) { - return pendingUsers; - } + const newPendingUsers = new Set(pendingUsers); - const newPendingUser = { - id: userID, - username, - }; - let targetIndex = 0; - while ( - targetIndex < pendingUsers.length && - newPendingUser.username.localeCompare( - pendingUsers[targetIndex].username, - ) > 0 - ) { - targetIndex++; + if (!newPendingUsers.delete(userID)) { + newPendingUsers.add(userID); } - return [ - ...pendingUsers.slice(0, targetIndex), - newPendingUser, - ...pendingUsers.slice(targetIndex), - ]; + + return newPendingUsers; }); }, - [mergedUserInfos], - ); - const deselectUser = React.useCallback( - (userID: string) => - setPendingUsersToAdd(pendingUsers => - pendingUsers.filter(userInfo => userInfo.id !== userID), - ), - [], - ); - const pendingUserIDs = React.useMemo( - () => new Set(pendingUsersToAdd.map(userInfo => userInfo.id)), - [pendingUsersToAdd], + [setPendingUsersToAdd], ); - const pendingUsersWithENSNames = useENSNames(pendingUsersToAdd); - const userTags = React.useMemo(() => { - if (pendingUsersWithENSNames.length === 0) { - return null; - } - const tags = pendingUsersWithENSNames.map(userInfo => ( - - )); - return
{tags}
; - }, [deselectUser, pendingUsersWithENSNames]); - - const filteredUsers = React.useMemo( - () => sortedUsers.filter(userInfo => !pendingUserIDs.has(userInfo.id)), - [pendingUserIDs, sortedUsers], - ); - const filteredUsersWithENSNames = useENSNames(filteredUsers); + const sortedUsersWithENSNames = useENSNames(sortedUsers); const userRows = React.useMemo( () => - filteredUsersWithENSNames.map(userInfo => ( + sortedUsersWithENSNames.map(userInfo => ( )), - [filteredUsersWithENSNames, selectUser], + [sortedUsersWithENSNames, toggleUser, pendingUsersToAdd], ); let errors; if (errorMessage) { errors =
{errorMessage}
; } return (
- {userTags}
{userRows}
{errors}
); } export default AddUsersList;