import type { FC } from '../../lib/teact/teact'; import React, { memo, useRef, useCallback, useState, useMemo, } from '../../lib/teact/teact'; import { getActions } from '../../global'; import type { ApiChat, ApiTopic } from '../../api/types'; import { REM } from './helpers/mediaDimensions'; import { CHAT_HEIGHT_PX } from '../../config'; import renderText from './helpers/renderText'; import { getCanPostInChat, isUserId } from '../../global/helpers'; import useInfiniteScroll from '../../hooks/useInfiniteScroll'; import useLang from '../../hooks/useLang'; import useKeyboardListNavigation from '../../hooks/useKeyboardListNavigation'; import useInputFocusOnOpen from '../../hooks/useInputFocusOnOpen'; import Loading from '../ui/Loading'; import Modal from '../ui/Modal'; import InputText from '../ui/InputText'; import Button from '../ui/Button'; import InfiniteScroll from '../ui/InfiniteScroll'; import ListItem from '../ui/ListItem'; import GroupChatInfo from './GroupChatInfo'; import PrivateChatInfo from './PrivateChatInfo'; import Transition from '../ui/Transition'; import TopicIcon from './TopicIcon'; import './ChatOrUserPicker.scss'; export type OwnProps = { currentUserId?: string; chatOrUserIds: string[]; chatsById?: Record; isOpen: boolean; searchPlaceholder: string; search: string; loadMore?: NoneToVoidFunction; onSearchChange: (search: string) => void; onSelectChatOrUser: (chatOrUserId: string, threadId?: number) => 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, chatsById, search, searchPlaceholder, 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 = useCallback(() => { onSearchChange(''); }, [onSearchChange]); useInputFocusOnOpen(searchRef, isOpen && activeKey === CHAT_LIST_SLIDE, resetSearch); useInputFocusOnOpen(topicSearchRef, isOpen && activeKey === TOPIC_LIST_SLIDE); const [topicIds, topics] = useMemo(() => { 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) && (!searchTitle || topic.title.toLowerCase().includes(searchTitle)) ) { acc[topic.id] = topic; } return acc; }, {} as Record) : topicsResult; return [Object.keys(result).map(Number), result]; }, [chatsById, forumId, topicSearch]); const handleHeaderBackClick = useCallback(() => { setForumId(undefined); setTopicSearch(''); }, []); const handleSearchChange = useCallback((e: React.ChangeEvent) => { onSearchChange(e.currentTarget.value); }, [onSearchChange]); const handleTopicSearchChange = useCallback((e: React.ChangeEvent) => { setTopicSearch(e.currentTarget.value); }, []); const handleKeyDown = useKeyboardListNavigation(containerRef, isOpen, (index) => { if (viewportIds && viewportIds.length > 0) { 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 = useCallback((e: React.MouseEvent, chatId: string) => { const chat = chatsById?.[chatId]; if (chat?.isForum) { if (!chat.topics) loadTopics({ chatId }); setForumId(chatId); resetSearch(); } else { onSelectChatOrUser(chatId); } }, [chatsById, loadTopics, onSelectChatOrUser, resetSearch]); const handleTopicClick = useCallback((e: React.MouseEvent, topicId: number) => { onSelectChatOrUser(forumId!, topicId); }, [forumId, onSelectChatOrUser]); 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);