diff --git a/src/components/right/Profile.tsx b/src/components/right/Profile.tsx index 15b9d66b7..b56f9a53a 100644 --- a/src/components/right/Profile.tsx +++ b/src/components/right/Profile.tsx @@ -701,7 +701,8 @@ export default memo(withGlobal( const areMembersHidden = hasMembersTab && chat && (chat.isForbidden || (chatFullInfo && !chatFullInfo.canViewMembers)); const canAddMembers = hasMembersTab && chat - && (getHasAdminRight(chat, 'inviteUsers') || !isUserRightBanned(chat, 'inviteUsers') || chat.isCreator); + && (getHasAdminRight(chat, 'inviteUsers') || (!isChannel && !isUserRightBanned(chat, 'inviteUsers')) + || chat.isCreator); const canDeleteMembers = hasMembersTab && chat && (getHasAdminRight(chat, 'banUsers') || chat.isCreator); const activeDownloads = selectActiveDownloads(global, chatId); const { similarChannelIds } = selectSimilarChannelIds(global, chatId) || {}; diff --git a/src/components/right/management/ManageGroupMembers.tsx b/src/components/right/management/ManageGroupMembers.tsx index bbc99eaa6..53da047ff 100644 --- a/src/components/right/management/ManageGroupMembers.tsx +++ b/src/components/right/management/ManageGroupMembers.tsx @@ -1,15 +1,15 @@ import type { FC } from '../../../lib/teact/teact'; import React, { - memo, useCallback, useMemo, useRef, useState, + memo, useMemo, useRef, useState, } from '../../../lib/teact/teact'; import { getActions, getGlobal, withGlobal } from '../../../global'; import type { ApiChatMember, ApiUserStatus } from '../../../api/types'; -import { ManagementScreens } from '../../../types'; +import { ManagementScreens, NewChatMembersProgress } from '../../../types'; import { filterUsersByName, getHasAdminRight, isChatBasicGroup, - isChatChannel, isUserBot, sortUserIds, + isChatChannel, isUserBot, isUserRightBanned, sortUserIds, } from '../../../global/helpers'; import { selectChat, selectChatFullInfo, selectTabState } from '../../../global/selectors'; import { unique } from '../../../util/iteratees'; @@ -20,9 +20,12 @@ import useHistoryBack from '../../../hooks/useHistoryBack'; import useInfiniteScroll from '../../../hooks/useInfiniteScroll'; import useKeyboardListNavigation from '../../../hooks/useKeyboardListNavigation'; import useLang from '../../../hooks/useLang'; +import useLastCallback from '../../../hooks/useLastCallback'; +import Icon from '../../common/Icon'; import NothingFound from '../../common/NothingFound'; import PrivateChatInfo from '../../common/PrivateChatInfo'; +import FloatingActionButton from '../../ui/FloatingActionButton'; import InfiniteScroll from '../../ui/InfiniteScroll'; import InputText from '../../ui/InputText'; import ListItem, { type MenuItemContextAction } from '../../ui/ListItem'; @@ -42,6 +45,7 @@ type OwnProps = { type StateProps = { userStatusesById: Record; members?: ApiChatMember[]; + canAddMembers?: boolean; adminMembersById?: Record; isChannel?: boolean; localContactIds?: string[]; @@ -59,6 +63,7 @@ const ManageGroupMembers: FC = ({ chatId, noAdmins, members, + canAddMembers, adminMembersById, userStatusesById, isChannel, @@ -77,7 +82,8 @@ const ManageGroupMembers: FC = ({ onChatMemberSelect, }) => { const { - openChat, setUserSearchQuery, closeManagement, toggleParticipantsHidden, + openChat, setUserSearchQuery, closeManagement, + toggleParticipantsHidden, setNewChatMembersDialogState, toggleManagement, } = getActions(); const lang = useLang(); // eslint-disable-next-line no-null/no-null @@ -137,7 +143,7 @@ const ManageGroupMembers: FC = ({ const [viewportIds, getMore] = useInfiniteScroll(undefined, displayedIds, Boolean(searchQuery)); - const handleMemberClick = useCallback((id: string) => { + const handleMemberClick = useLastCallback((id: string) => { if (noAdmins) { onChatMemberSelect!(id, true); onScreenSelect!(ManagementScreens.ChatNewAdminRights); @@ -145,24 +151,30 @@ const ManageGroupMembers: FC = ({ closeManagement(); openChat({ id }); } - }, [closeManagement, noAdmins, onChatMemberSelect, onScreenSelect, openChat]); + }); - const handleFilterChange = useCallback((e: React.ChangeEvent) => { + const handleFilterChange = useLastCallback((e: React.ChangeEvent) => { setUserSearchQuery({ query: e.target.value }); - }, [setUserSearchQuery]); + }); + const handleKeyDown = useKeyboardListNavigation(containerRef, isActive, (index) => { if (viewportIds && viewportIds.length > 0) { handleMemberClick(viewportIds[index === -1 ? 0 : index]); } }, '.ListItem-button', true); - const handleDeleteMembersModalClose = useCallback(() => { + const handleDeleteMembersModalClose = useLastCallback(() => { setDeletingUserId(undefined); - }, []); + }); - const handleToggleParticipantsHidden = useCallback(() => { + const handleToggleParticipantsHidden = useLastCallback(() => { toggleParticipantsHidden({ chatId, isEnabled: !areParticipantsHidden }); - }, [areParticipantsHidden, chatId, toggleParticipantsHidden]); + }); + + const handleNewMemberDialogOpen = useLastCallback(() => { + toggleManagement(); + setNewChatMembersDialogState({ newChatMembersProgress: NewChatMembersProgress.InProgress }); + }); useHistoryBack({ isActive, @@ -240,6 +252,15 @@ const ManageGroupMembers: FC = ({ )} + {canAddMembers && ( + + + + )} {canDeleteMembers && ( ( const canHideParticipants = canDeleteMembers && !isChatBasicGroup(chat) && chat.membersCount !== undefined && hiddenMembersMinCount !== undefined && chat.membersCount >= hiddenMembersMinCount; + const canAddMembers = chat && ((getHasAdminRight(chat, 'inviteUsers') + || (!isChannel && !isUserRightBanned(chat, 'inviteUsers'))) + || chat.isCreator + ); + const { query: searchQuery, fetchingStatus, @@ -275,6 +301,7 @@ export default memo(withGlobal( return { areParticipantsHidden: Boolean(chat && areParticipantsHidden), members, + canAddMembers, adminMembersById, userStatusesById, isChannel,