diff --git a/web/modals/threads/members/member.react.js b/web/modals/threads/members/member.react.js index beacbc6ad..d09e8e4b0 100644 --- a/web/modals/threads/members/member.react.js +++ b/web/modals/threads/members/member.react.js @@ -1,144 +1,141 @@ // @flow -import classNames from 'classnames'; import * as React from 'react'; import { removeUsersFromThread } from 'lib/actions/thread-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; import { removeMemberFromThread, getAvailableThreadMemberActions, } from 'lib/shared/thread-utils.js'; import { stringForUser } from 'lib/shared/user-utils.js'; import type { SetState } from 'lib/types/hook-types.js'; import { type RelativeMemberInfo, type ThreadInfo, } from 'lib/types/thread-types.js'; import { useDispatchActionPromise, useServerCall, } from 'lib/utils/action-utils.js'; import ChangeMemberRoleModal from './change-member-role-modal.react.js'; import css from './members-modal.css'; import UserAvatar from '../../../avatars/user-avatar.react.js'; import CommIcon from '../../../CommIcon.react.js'; import Label from '../../../components/label.react.js'; import MenuItem from '../../../components/menu-item.react.js'; import Menu from '../../../components/menu.react.js'; +import { usePushUserProfileModal } from '../../user-profile/user-profile-utils.js'; const commIconComponent = ; type Props = { +memberInfo: RelativeMemberInfo, +threadInfo: ThreadInfo, +setOpenMenu: SetState, - +isMenuOpen: boolean, }; function ThreadMember(props: Props): React.Node { - const { memberInfo, threadInfo, setOpenMenu, isMenuOpen } = props; + const { memberInfo, threadInfo, setOpenMenu } = props; const { pushModal } = useModalContext(); const userName = stringForUser(memberInfo); const { roles } = threadInfo; const { role } = memberInfo; const onMenuChange = React.useCallback( menuOpen => { if (menuOpen) { setOpenMenu(() => memberInfo.id); } else { setOpenMenu(menu => (menu === memberInfo.id ? null : menu)); } }, [memberInfo.id, setOpenMenu], ); const dispatchActionPromise = useDispatchActionPromise(); const boundRemoveUsersFromThread = useServerCall(removeUsersFromThread); const onClickRemoveUser = React.useCallback( () => removeMemberFromThread( threadInfo, memberInfo, dispatchActionPromise, boundRemoveUsersFromThread, ), [boundRemoveUsersFromThread, dispatchActionPromise, memberInfo, threadInfo], ); const onClickChangeRole = React.useCallback(() => { pushModal( , ); }, [memberInfo, pushModal, threadInfo]); const menuItems = React.useMemo( () => getAvailableThreadMemberActions(memberInfo, threadInfo).map(action => { if (action === 'change_role') { return ( ); } if (action === 'remove_user') { return ( ); } return null; }), [memberInfo, onClickRemoveUser, onClickChangeRole, threadInfo], ); const userSettingsIcon = React.useMemo( () => , [], ); const roleName = role && roles[role].name; const label = React.useMemo( () => , [roleName], ); - const memberContainerClasses = classNames(css.memberContainer, { - [css.memberContainerWithMenuOpen]: isMenuOpen, - }); + const pushUserProfileModal = usePushUserProfileModal(memberInfo.id); return ( -
+
{userName} {label}
{menuItems}
); } export default ThreadMember; diff --git a/web/modals/threads/members/members-list.react.js b/web/modals/threads/members/members-list.react.js index 30a207073..e18ec50a0 100644 --- a/web/modals/threads/members/members-list.react.js +++ b/web/modals/threads/members/members-list.react.js @@ -1,82 +1,81 @@ // @flow import classNames from 'classnames'; import _groupBy from 'lodash/fp/groupBy.js'; import _toPairs from 'lodash/fp/toPairs.js'; import * as React from 'react'; import { useENSNames } from 'lib/hooks/ens-cache.js'; import { stringForUser } from 'lib/shared/user-utils.js'; import { type ThreadInfo, type RelativeMemberInfo, } from 'lib/types/thread-types.js'; import ThreadMember from './member.react.js'; import css from './members-modal.css'; type Props = { +threadInfo: ThreadInfo, +threadMembers: $ReadOnlyArray, }; function ThreadMembersList(props: Props): React.Node { const { threadMembers, threadInfo } = props; const [openMenu, setOpenMenu] = React.useState(null); const hasMembers = threadMembers.length > 0; const threadMembersWithENSNames = useENSNames(threadMembers); const groupedByFirstLetterMembers = React.useMemo( () => _groupBy(member => stringForUser(member)[0].toLowerCase())( threadMembersWithENSNames, ), [threadMembersWithENSNames], ); const groupedMembersList = React.useMemo( () => _toPairs(groupedByFirstLetterMembers) .sort((a, b) => a[0].localeCompare(b[0])) .map(([letter, users]) => { const userList = users .sort((a, b) => stringForUser(a).localeCompare(stringForUser(b))) .map((user: RelativeMemberInfo) => ( )); const letterHeader = (
{letter.toUpperCase()}
); return ( {letterHeader} {userList} ); }), - [groupedByFirstLetterMembers, openMenu, threadInfo], + [groupedByFirstLetterMembers, threadInfo], ); let content = groupedMembersList; if (!hasMembers) { content = (
No matching users were found in the chat!
); } const membersListClasses = classNames(css.membersList, { [css.noScroll]: !!openMenu, }); return
{content}
; } export default ThreadMembersList; diff --git a/web/modals/threads/members/members-modal.css b/web/modals/threads/members/members-modal.css index 50ee4d7de..d48cdf2a1 100644 --- a/web/modals/threads/members/members-modal.css +++ b/web/modals/threads/members/members-modal.css @@ -1,91 +1,89 @@ div.modalContentContainer { height: 617px; overflow: hidden; display: flex; flex-direction: column; row-gap: 16px; } div.membersListTabs { flex: 1; overflow: hidden; } div.addNewMembers button { width: 100%; } div.membersList { overflow: auto; padding: 8px 0; color: var(--members-modal-member-text); } div.noScroll { overflow: hidden; } div.memberContainer { display: flex; flex-direction: row; justify-content: space-between; padding: 8px 16px; } div.memberContainer:hover { - color: var(--members-modal-member-text-hover); -} - -div.memberContainerWithMenuOpen { - color: var(--members-modal-member-text-hover); + cursor: pointer; + background-color: var(--drawer-open-community-bg); + border-radius: 8px; } div.memberInfo { font-size: var(--l-font-18); display: flex; align-items: center; gap: 10px; } div.memberAction { position: relative; } h5.memberletterHeader { margin: 16px; color: var(--members-modal-member-text); font-size: var(--s-font-14); } div.noUsers { padding-top: 16px; text-align: center; } div.addMembersContent { display: flex; flex-direction: column; overflow: auto; color: var(--fg); height: 617px; } div.addMembersPendingList { display: flex; flex-direction: row; flex-wrap: wrap; gap: 6px; padding: 8px; } div.addMembersListContainer { overflow: auto; flex: 1; } div.addMembersFooter { display: flex; justify-content: end; column-gap: 16px; margin-top: 16px; }