import type { FC } from '../../../lib/teact/teact'; import React, { memo } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; import type { ApiChat, ApiDraft, ApiMessage, ApiMessageOutgoingStatus, ApiPeer, ApiTopic, ApiTypeStory, ApiTypingStatus, } from '../../../api/types'; import type { ObserveFn } from '../../../hooks/useIntersectionObserver'; import type { ChatAnimationTypes } from './hooks'; import { getMessageAction, groupStatetefulContent } from '../../../global/helpers'; import { getMessageReplyInfo } from '../../../global/helpers/replies'; import { selectCanAnimateInterface, selectCanDeleteTopic, selectChat, selectChatMessage, selectCurrentMessageList, selectDraft, selectOutgoingStatus, selectPeerStory, selectSender, selectThreadInfo, selectThreadParam, selectTopics, } from '../../../global/selectors'; import buildClassName from '../../../util/buildClassName'; import { createLocationHash } from '../../../util/routing'; import { IS_OPEN_IN_NEW_TAB_SUPPORTED } from '../../../util/windowEnvironment'; import renderText from '../../common/helpers/renderText'; import useFlag from '../../../hooks/useFlag'; import useLastCallback from '../../../hooks/useLastCallback'; import useOldLang from '../../../hooks/useOldLang'; import useChatListEntry from './hooks/useChatListEntry'; import useTopicContextActions from './hooks/useTopicContextActions'; import Icon from '../../common/icons/Icon'; import LastMessageMeta from '../../common/LastMessageMeta'; import TopicIcon from '../../common/TopicIcon'; import ConfirmDialog from '../../ui/ConfirmDialog'; import ListItem from '../../ui/ListItem'; import MuteChatModal from '../MuteChatModal.async'; import ChatBadge from './ChatBadge'; import styles from './Topic.module.scss'; type OwnProps = { chatId: string; topic: ApiTopic; isSelected: boolean; style: string; observeIntersection?: ObserveFn; orderDiff: number; animationType: ChatAnimationTypes; }; type StateProps = { chat: ApiChat; canDelete?: boolean; lastMessage?: ApiMessage; lastMessageStory?: ApiTypeStory; lastMessageOutgoingStatus?: ApiMessageOutgoingStatus; actionTargetMessage?: ApiMessage; actionTargetUserIds?: string[]; lastMessageSender?: ApiPeer; actionTargetChatId?: string; typingStatus?: ApiTypingStatus; draft?: ApiDraft; canScrollDown?: boolean; wasTopicOpened?: boolean; withInterfaceAnimations?: boolean; topics?: Record; }; const Topic: FC = ({ topic, isSelected, chatId, chat, style, lastMessage, lastMessageStory, canScrollDown, lastMessageOutgoingStatus, observeIntersection, canDelete, actionTargetMessage, actionTargetUserIds, actionTargetChatId, lastMessageSender, animationType, withInterfaceAnimations, orderDiff, typingStatus, draft, wasTopicOpened, topics, }) => { const { openThread, deleteTopic, focusLastMessage, setViewForumAsMessages, } = getActions(); const lang = useOldLang(); const [isDeleteModalOpen, openDeleteModal, closeDeleteModal] = useFlag(); const [isMuteModalOpen, openMuteModal, closeMuteModal] = useFlag(); const [shouldRenderDeleteModal, markRenderDeleteModal, unmarkRenderDeleteModal] = useFlag(); const [shouldRenderMuteModal, markRenderMuteModal, unmarkRenderMuteModal] = useFlag(); const { isPinned, isClosed, } = topic; const isMuted = topic.isMuted || (topic.isMuted === undefined && chat.isMuted); const handleOpenDeleteModal = useLastCallback(() => { markRenderDeleteModal(); openDeleteModal(); }); const handleDelete = useLastCallback(() => { deleteTopic({ chatId: chat.id, topicId: topic.id }); }); const handleMute = useLastCallback(() => { markRenderMuteModal(); openMuteModal(); }); const { renderSubtitle, ref } = useChatListEntry({ chat, chatId, lastMessage, draft, actionTargetMessage, actionTargetUserIds, actionTargetChatId, lastMessageSender, lastMessageTopic: topic, observeIntersection, isTopic: true, typingStatus, topics, statefulMediaContent: groupStatetefulContent({ story: lastMessageStory }), animationType, withInterfaceAnimations, orderDiff, }); const handleOpenTopic = useLastCallback(() => { openThread({ chatId, threadId: topic.id, shouldReplaceHistory: true }); setViewForumAsMessages({ chatId, isEnabled: false }); if (canScrollDown) { focusLastMessage(); } }); const contextActions = useTopicContextActions({ topic, chat, wasOpened: wasTopicOpened, canDelete, handleDelete: handleOpenDeleteModal, handleMute, }); return (

{renderText(topic.title)}

{topic.isMuted && }
{isClosed && ( )} {lastMessage && ( )}
{renderSubtitle()}
{shouldRenderDeleteModal && ( )} {shouldRenderMuteModal && ( )} ); }; export default memo(withGlobal( (global, { chatId, topic, isSelected }) => { const chat = selectChat(global, chatId); const lastMessage = selectChatMessage(global, chatId, topic.lastMessageId); const { isOutgoing } = lastMessage || {}; const replyToMessageId = lastMessage && getMessageReplyInfo(lastMessage)?.replyToMsgId; const lastMessageSender = lastMessage && selectSender(global, lastMessage); const lastMessageAction = lastMessage ? getMessageAction(lastMessage) : undefined; const actionTargetMessage = lastMessageAction && replyToMessageId ? selectChatMessage(global, chatId, replyToMessageId) : undefined; const { targetUserIds: actionTargetUserIds, targetChatId: actionTargetChatId } = lastMessageAction || {}; const typingStatus = selectThreadParam(global, chatId, topic.id, 'typingStatus'); const draft = selectDraft(global, chatId, topic.id); const threadInfo = selectThreadInfo(global, chatId, topic.id); const wasTopicOpened = Boolean(threadInfo?.lastReadInboxMessageId); const topics = selectTopics(global, chatId); const { chatId: currentChatId, threadId: currentThreadId } = selectCurrentMessageList(global) || {}; const storyData = lastMessage?.content.storyData; const lastMessageStory = storyData && selectPeerStory(global, storyData.peerId, storyData.id); return { chat, lastMessage, actionTargetUserIds, actionTargetChatId, actionTargetMessage, lastMessageSender, typingStatus, canDelete: selectCanDeleteTopic(global, chatId, topic.id), withInterfaceAnimations: selectCanAnimateInterface(global), draft, ...(isOutgoing && lastMessage && { lastMessageOutgoingStatus: selectOutgoingStatus(global, lastMessage), }), canScrollDown: isSelected && chat?.id === currentChatId && currentThreadId === topic.id, wasTopicOpened, topics, lastMessageStory, }; }, )(Topic));