import type { FC } from '../../lib/teact/teact'; import React, { memo, useMemo, useState, } from '../../lib/teact/teact'; import { getActions, getGlobal, withGlobal } from '../../global'; import type { ApiChat, ApiChatMember, ApiUserStatus } from '../../api/types'; import { filterChatsByName, filterUsersByName, isChatChannel, isChatPublic, isChatSuperGroup, isUserBot, sortUserIds, } from '../../global/helpers'; import { selectChat, selectChatFullInfo } from '../../global/selectors'; import buildClassName from '../../util/buildClassName'; import { unique } from '../../util/iteratees'; import sortChatIds from '../common/helpers/sortChatIds'; import useFlag from '../../hooks/useFlag'; import useLang from '../../hooks/useLang'; import useLastCallback from '../../hooks/useLastCallback'; import Icon from '../common/icons/Icon'; import Picker from '../common/Picker'; import Button from '../ui/Button'; import ConfirmDialog from '../ui/ConfirmDialog'; import Modal from '../ui/Modal'; import styles from './AppendEntityPicker.module.scss'; export type OwnProps = { isOpen?: boolean; onClose: () => void; chatId?: string; entityType: 'members' | 'channels' | undefined; onSubmit: (value: string[]) => void; selectionLimit: number; }; interface StateProps { chatId?: string; members?: ApiChatMember[]; adminMembersById?: Record; userStatusesById: Record; channelList?: (ApiChat | undefined)[] | undefined; isChannel?: boolean; isSuperGroup?: boolean; currentUserId?: string | undefined; } const AppendEntityPickerModal: FC = ({ chatId, isOpen, onClose, members, adminMembersById, userStatusesById, entityType, isChannel, isSuperGroup, onSubmit, currentUserId, selectionLimit, }) => { const { showNotification } = getActions(); const lang = useLang(); const [isConfirmModalOpen, openConfirmModal, closeConfirmModal] = useFlag(); const [selectedIds, setSelectedIds] = useState([]); const [pendingChannelId, setPendingChannelId] = useState(undefined); const [searchQuery, setSearchQuery] = useState(''); const channelsIds = useMemo(() => { const chatsById = getGlobal().chats.byId; const activeChatIds = getGlobal().chats.listIds.active; return activeChatIds!.map((id) => chatsById[id]) .filter((chat) => chat && (isChatChannel(chat) || isChatSuperGroup(chat)) && chat.id !== chatId) .map((chat) => chat!.id); }, [chatId]); const adminIds = useMemo(() => { return adminMembersById && Object.keys(adminMembersById); }, [adminMembersById]); const memberIds = useMemo(() => { const usersById = getGlobal().users.byId; if (!members || !usersById) { return []; } const userIds = sortUserIds( members.map(({ userId }) => userId), usersById, userStatusesById, ); return adminIds ? userIds.filter((userId) => userId !== currentUserId) : userIds; }, [adminIds, currentUserId, members, userStatusesById]); const displayedMembersIds = useMemo(() => { const usersById = getGlobal().users.byId; const filteredContactIds = memberIds ? filterUsersByName(memberIds, usersById, searchQuery) : []; return sortChatIds(unique(filteredContactIds).filter((userId) => { const user = usersById[userId]; if (!user) { return true; } return !isUserBot(user); })); }, [memberIds, searchQuery]); const displayedChannelIds = useMemo(() => { const chatsById = getGlobal().chats.byId; const foundChannelIds = channelsIds ? filterChatsByName(lang, channelsIds, chatsById, searchQuery) : []; return sortChatIds(unique(foundChannelIds).filter((contactId) => { const chat = chatsById[contactId]; if (!chat) { return true; } return isChannel || isSuperGroup; }), false, selectedIds); }, [channelsIds, lang, searchQuery, selectedIds, isSuperGroup, isChannel]); const handleCloseButtonClick = useLastCallback(() => { onSubmit([]); onClose(); }); const handleSendIdList = useLastCallback(() => { onSubmit(selectedIds); onClose(); }); const confirmPrivateLinkChannelSelection = useLastCallback(() => { if (pendingChannelId) { setSelectedIds((prevIds) => unique([...prevIds, pendingChannelId])); } closeConfirmModal(); }); const handleSelectedMemberIdsChange = useLastCallback((newSelectedIds: string[]) => { if (newSelectedIds.length > selectionLimit) { showNotification({ message: lang('BoostingSelectUpToWarningUsers', selectionLimit), }); return; } setSelectedIds(newSelectedIds); }); const handleSelectedChannelIdsChange = useLastCallback((newSelectedIds: string[]) => { const chatsById = getGlobal().chats.byId; const newlyAddedIds = newSelectedIds.filter((id) => !selectedIds.includes(id)); const privateLinkChannelId = newlyAddedIds.find((id) => { const chat = chatsById[id]; return chat && !isChatPublic(chat); }); if (selectedIds?.length >= selectionLimit) { showNotification({ message: lang('BoostingSelectUpToWarningChannelsPlural', selectionLimit), }); return; } if (privateLinkChannelId) { setPendingChannelId(privateLinkChannelId); openConfirmModal(); } else { setSelectedIds(newSelectedIds); } }); const handleClose = useLastCallback(() => { onSubmit([]); onClose(); }); function renderSearchField() { return (

{lang(entityType === 'channels' ? 'RequestPeer.ChooseChannelTitle' : 'BoostingAwardSpecificUsers')}

); } return (
{renderSearchField()}
); }; export default memo(withGlobal((global, { chatId, entityType }): StateProps => { const { statusesById: userStatusesById } = global.users; let isChannel; let isSuperGroup; let members: ApiChatMember[] | undefined; let adminMembersById: Record | undefined; let currentUserId: string | undefined; if (entityType === 'members') { currentUserId = global.currentUserId; const chatFullInfo = chatId ? selectChatFullInfo(global, chatId) : undefined; if (chatFullInfo) { members = chatFullInfo.members; adminMembersById = chatFullInfo.adminMembersById; } } if (entityType === 'channels') { const chat = chatId ? selectChat(global, chatId) : undefined; if (chat) { isChannel = isChatChannel(chat); isSuperGroup = isChatSuperGroup(chat); } } return { chatId, members, adminMembersById, userStatusesById, isChannel, isSuperGroup, currentUserId, }; })(AppendEntityPickerModal));