import type { FC } from '../../lib/teact/teact'; import React, { memo, useMemo, useRef, useState, } from '../../lib/teact/teact'; import { getActions, getGlobal } from '../../global'; import type { ApiTopic } from '../../api/types'; import type { ThreadId } from '../../types'; import { CHAT_HEIGHT_PX } from '../../config'; import { getCanPostInChat, isUserId } from '../../global/helpers'; import buildClassName from '../../util/buildClassName'; import { REM } from './helpers/mediaDimensions'; import renderText from './helpers/renderText'; import useInfiniteScroll from '../../hooks/useInfiniteScroll'; import useInputFocusOnOpen from '../../hooks/useInputFocusOnOpen'; import useKeyboardListNavigation from '../../hooks/useKeyboardListNavigation'; import useLang from '../../hooks/useLang'; import useLastCallback from '../../hooks/useLastCallback'; import Button from '../ui/Button'; import InfiniteScroll from '../ui/InfiniteScroll'; import InputText from '../ui/InputText'; import ListItem from '../ui/ListItem'; import Loading from '../ui/Loading'; import Modal from '../ui/Modal'; import Transition from '../ui/Transition'; import GroupChatInfo from './GroupChatInfo'; import PrivateChatInfo from './PrivateChatInfo'; import TopicIcon from './TopicIcon'; import './ChatOrUserPicker.scss'; export type OwnProps = { currentUserId?: string; chatOrUserIds: string[]; isOpen: boolean; searchPlaceholder: string; search: string; className?: string; loadMore?: NoneToVoidFunction; onSearchChange: (search: string) => void; onSelectChatOrUser: (chatOrUserId: string, threadId?: ThreadId) => void; onClose: NoneToVoidFunction; onCloseAnimationEnd?: NoneToVoidFunction; }; const CHAT_LIST_SLIDE = 0; const TOPIC_LIST_SLIDE = 1; const TOPIC_ICON_SIZE = 2.75 * REM; const ChatOrUserPicker: FC = ({ isOpen, currentUserId, chatOrUserIds, search, searchPlaceholder, className, loadMore, onSearchChange, onSelectChatOrUser, onClose, onCloseAnimationEnd, }) => { const { loadTopics } = getActions(); const lang = useLang(); // eslint-disable-next-line no-null/no-null const containerRef = useRef(null); // eslint-disable-next-line no-null/no-null const topicContainerRef = useRef(null); // eslint-disable-next-line no-null/no-null const searchRef = useRef(null); // eslint-disable-next-line no-null/no-null const topicSearchRef = useRef(null); const [viewportIds, getMore] = useInfiniteScroll(loadMore, chatOrUserIds, Boolean(search)); const [forumId, setForumId] = useState(undefined); const [topicSearch, setTopicSearch] = useState(''); const activeKey = forumId ? TOPIC_LIST_SLIDE : CHAT_LIST_SLIDE; const viewportOffset = chatOrUserIds!.indexOf(viewportIds![0]); const resetSearch = useLastCallback(() => { onSearchChange(''); }); useInputFocusOnOpen(searchRef, isOpen && activeKey === CHAT_LIST_SLIDE, resetSearch); useInputFocusOnOpen(topicSearchRef, isOpen && activeKey === TOPIC_LIST_SLIDE); const [topicIds, topics] = useMemo(() => { const global = getGlobal(); const chatsById = global.chats.byId; const chatFullInfoById = global.chats.fullInfoById; const topicsResult = forumId ? chatsById[forumId].topics : undefined; if (!topicsResult) { return [undefined, undefined]; } const searchTitle = topicSearch.toLowerCase(); const result = topicsResult ? Object.values(topicsResult).reduce((acc, topic) => { if ( getCanPostInChat(chatsById[forumId!], topic.id, undefined, chatFullInfoById[forumId!]) && (!searchTitle || topic.title.toLowerCase().includes(searchTitle)) ) { acc[topic.id] = topic; } return acc; }, {} as Record) : topicsResult; return [Object.keys(result).map(Number), result]; }, [forumId, topicSearch]); const handleHeaderBackClick = useLastCallback(() => { setForumId(undefined); setTopicSearch(''); }); const handleSearchChange = useLastCallback((e: React.ChangeEvent) => { onSearchChange(e.currentTarget.value); }); const handleTopicSearchChange = useLastCallback((e: React.ChangeEvent) => { setTopicSearch(e.currentTarget.value); }); const handleKeyDown = useKeyboardListNavigation(containerRef, isOpen, (index) => { if (viewportIds && viewportIds.length > 0) { const chatsById = getGlobal().chats.byId; const chatId = viewportIds[index === -1 ? 0 : index]; const chat = chatsById[chatId]; if (chat?.isForum) { if (!chat.topics) loadTopics({ chatId }); setForumId(chatId); } else { onSelectChatOrUser(chatId); } } }, '.ListItem-button', true); const handleTopicKeyDown = useKeyboardListNavigation(topicContainerRef, isOpen, (index) => { if (topicIds?.length) { onSelectChatOrUser(forumId!, topicIds[index === -1 ? 0 : index]); } }, '.ListItem-button', true); const handleClick = useLastCallback((e: React.MouseEvent, chatId: string) => { const chatsById = getGlobal().chats.byId; const chat = chatsById?.[chatId]; if (chat?.isForum) { if (!chat.topics) loadTopics({ chatId }); setForumId(chatId); resetSearch(); } else { onSelectChatOrUser(chatId); } }); const handleTopicClick = useLastCallback((e: React.MouseEvent, topicId: number) => { onSelectChatOrUser(forumId!, topicId); }); function renderTopicList() { return ( <>
{topicIds ? topicIds.map((topicId, i) => (
{renderText(topics[topicId].title)}
)) : }
); } function renderChatList() { return ( <>
{viewportIds?.length ? ( {viewportIds.map((id, i) => ( {isUserId(id) ? ( ) : ( )} ))} ) : viewportIds && !viewportIds.length ? (

{lang('lng_blocked_list_not_found')}

) : ( )} ); } return ( {() => { return activeKey === TOPIC_LIST_SLIDE ? renderTopicList() : renderChatList(); }} ); }; export default memo(ChatOrUserPicker);