import type { FC } from '../../lib/teact/teact'; import React, { memo, useCallback, useEffect, useMemo, useState, } from '../../lib/teact/teact'; import { getActions, withGlobal } from '../../global'; import type { ApiBotCommand, ApiChat } from '../../api/types'; import type { IAnchorPosition } from '../../types'; import { MAIN_THREAD_ID } from '../../api/types'; import { REPLIES_USER_ID } from '../../config'; import { disableScrolling, enableScrolling } from '../../util/scrollLock'; import { selectChat, selectChatBot, selectChatFullInfo, selectCurrentMessageList, selectIsPremiumPurchaseBlocked, selectNotifyExceptions, selectNotifySettings, selectTabState, selectUser, selectUserFullInfo, } from '../../global/selectors'; import { getCanAddContact, getCanDeleteChat, getCanManageTopic, getHasAdminRight, isChatChannel, isChatGroup, isUserId, isUserRightBanned, selectIsChatMuted, } from '../../global/helpers'; import useShowTransition from '../../hooks/useShowTransition'; import usePrevDuringAnimation from '../../hooks/usePrevDuringAnimation'; import useLang from '../../hooks/useLang'; import useAppLayout from '../../hooks/useAppLayout'; import Portal from '../ui/Portal'; import Menu from '../ui/Menu'; import MenuItem from '../ui/MenuItem'; import MenuSeparator from '../ui/MenuSeparator'; import DeleteChatModal from '../common/DeleteChatModal'; import ReportModal from '../common/ReportModal'; import './HeaderMenuContainer.scss'; const BOT_BUTTONS: Record = { settings: { icon: 'bots', label: 'BotSettings', }, privacy: { icon: 'info', label: 'Privacy', }, help: { icon: 'help', label: 'BotHelp', }, }; export type OwnProps = { chatId: string; threadId: number; isOpen: boolean; withExtraActions: boolean; anchor: IAnchorPosition; isChannel?: boolean; canStartBot?: boolean; canRestartBot?: boolean; canSubscribe?: boolean; canSearch?: boolean; canCall?: boolean; canMute?: boolean; canViewStatistics?: boolean; withForumActions?: boolean; canLeave?: boolean; canEnterVoiceChat?: boolean; canCreateVoiceChat?: boolean; pendingJoinRequests?: number; onSubscribeChannel: () => void; onSearchClick: () => void; onAsMessagesClick: () => void; onClose: () => void; onCloseAnimationEnd: () => void; onJoinRequestsClick?: () => void; }; type StateProps = { chat?: ApiChat; botCommands?: ApiBotCommand[]; isPrivate?: boolean; isMuted?: boolean; isTopic?: boolean; isForum?: boolean; canAddContact?: boolean; canReportChat?: boolean; canDeleteChat?: boolean; canGiftPremium?: boolean; canCreateTopic?: boolean; canEditTopic?: boolean; hasLinkedChat?: boolean; isChatInfoShown?: boolean; }; const CLOSE_MENU_ANIMATION_DURATION = 200; const HeaderMenuContainer: FC = ({ chatId, threadId, isOpen, withExtraActions, anchor, isChannel, botCommands, withForumActions, isTopic, isForum, isChatInfoShown, canStartBot, canRestartBot, canSubscribe, canSearch, canCall, canMute, canViewStatistics, pendingJoinRequests, canLeave, canEnterVoiceChat, canCreateVoiceChat, chat, isPrivate, isMuted, canReportChat, canDeleteChat, canGiftPremium, hasLinkedChat, canAddContact, canCreateTopic, canEditTopic, onJoinRequestsClick, onSubscribeChannel, onSearchClick, onAsMessagesClick, onClose, onCloseAnimationEnd, }) => { const { updateChatMutedState, enterMessageSelectMode, sendBotCommand, restartBot, requestMasterAndJoinGroupCall, createGroupCall, openLinkedChat, openAddContactDialog, requestMasterAndRequestCall, toggleStatistics, openGiftPremiumModal, openChatWithInfo, openCreateTopicPanel, openEditTopicPanel, openChat, } = getActions(); const { isMobile } = useAppLayout(); const [isMenuOpen, setIsMenuOpen] = useState(true); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isReportModalOpen, setIsReportModalOpen] = useState(false); const { x, y } = anchor; useShowTransition(isOpen, onCloseAnimationEnd, undefined, false); const isViewGroupInfoShown = usePrevDuringAnimation( (!isChatInfoShown && isForum) ? true : undefined, CLOSE_MENU_ANIMATION_DURATION, ); const handleReport = useCallback(() => { setIsMenuOpen(false); setIsReportModalOpen(true); }, []); const closeReportModal = useCallback(() => { setIsReportModalOpen(false); onClose(); }, [onClose]); const handleDelete = useCallback(() => { setIsMenuOpen(false); setIsDeleteModalOpen(true); }, []); const closeMenu = useCallback(() => { setIsMenuOpen(false); onClose(); }, [onClose]); const handleViewGroupInfo = useCallback(() => { openChatWithInfo({ id: chatId, threadId }); closeMenu(); }, [chatId, closeMenu, openChatWithInfo, threadId]); const closeDeleteModal = useCallback(() => { setIsDeleteModalOpen(false); onClose(); }, [onClose]); const handleStartBot = useCallback(() => { sendBotCommand({ command: '/start' }); }, [sendBotCommand]); const handleRestartBot = useCallback(() => { restartBot({ chatId }); }, [chatId, restartBot]); const handleToggleMuteClick = useCallback(() => { updateChatMutedState({ chatId, isMuted: !isMuted }); closeMenu(); }, [chatId, closeMenu, isMuted, updateChatMutedState]); const handleCreateTopicClick = useCallback(() => { openCreateTopicPanel({ chatId }); closeMenu(); }, [openCreateTopicPanel, chatId, closeMenu]); const handleEditTopicClick = useCallback(() => { openEditTopicPanel({ chatId, topicId: threadId }); closeMenu(); }, [openEditTopicPanel, chatId, threadId, closeMenu]); const handleViewAsTopicsClick = useCallback(() => { openChat({ id: undefined }); closeMenu(); }, [closeMenu, openChat]); const handleEnterVoiceChatClick = useCallback(() => { if (canCreateVoiceChat) { // TODO Show popup to schedule createGroupCall({ chatId, }); } else { requestMasterAndJoinGroupCall({ chatId, }); } closeMenu(); }, [closeMenu, canCreateVoiceChat, chatId, requestMasterAndJoinGroupCall, createGroupCall]); const handleLinkedChatClick = useCallback(() => { openLinkedChat({ id: chatId }); closeMenu(); }, [chatId, closeMenu, openLinkedChat]); const handleGiftPremiumClick = useCallback(() => { openGiftPremiumModal({ forUserId: chatId }); closeMenu(); }, [openGiftPremiumModal, chatId, closeMenu]); const handleAddContactClick = useCallback(() => { openAddContactDialog({ userId: chatId }); closeMenu(); }, [openAddContactDialog, chatId, closeMenu]); const handleSubscribe = useCallback(() => { onSubscribeChannel(); closeMenu(); }, [closeMenu, onSubscribeChannel]); const handleVideoCall = useCallback(() => { requestMasterAndRequestCall({ userId: chatId, isVideo: true }); closeMenu(); }, [chatId, closeMenu, requestMasterAndRequestCall]); const handleCall = useCallback(() => { requestMasterAndRequestCall({ userId: chatId }); closeMenu(); }, [chatId, closeMenu, requestMasterAndRequestCall]); const handleSearch = useCallback(() => { onSearchClick(); closeMenu(); }, [closeMenu, onSearchClick]); const handleStatisticsClick = useCallback(() => { toggleStatistics(); closeMenu(); }, [closeMenu, toggleStatistics]); const handleSelectMessages = useCallback(() => { enterMessageSelectMode(); closeMenu(); }, [closeMenu, enterMessageSelectMode]); const handleOpenAsMessages = useCallback(() => { onAsMessagesClick(); closeMenu(); }, [closeMenu, onAsMessagesClick]); useEffect(() => { disableScrolling(); return enableScrolling; }, []); const lang = useLang(); const botButtons = useMemo(() => { return botCommands?.map(({ command }) => { const cmd = BOT_BUTTONS[command]; if (!cmd) return undefined; const handleClick = () => { sendBotCommand({ command: `/${command}` }); closeMenu(); }; return ( {lang(cmd.label)} ); }); }, [botCommands, closeMenu, lang, sendBotCommand]); return (
{isMobile && canSearch && ( {lang('Search')} )} {withForumActions && canCreateTopic && ( <> {lang('lng_forum_create_topic')} )} {isViewGroupInfoShown && ( {isTopic ? lang('lng_context_view_topic') : lang('lng_context_view_group')} )} {canEditTopic && ( {lang('lng_forum_topic_edit')} )} {isMobile && !withForumActions && isForum && !isTopic && ( {lang('Chat.ContextViewAsTopics')} )} {withForumActions && Boolean(pendingJoinRequests) && ( {isChannel ? lang('SubscribeRequests') : lang('MemberRequests')}
{pendingJoinRequests}
)} {withForumActions && !isTopic && ( {lang('lng_forum_view_as_messages')} )} {withExtraActions && canStartBot && ( {lang('BotStart')} )} {withExtraActions && canRestartBot && ( {lang('BotRestart')} )} {withExtraActions && canSubscribe && ( {lang(isChannel ? 'ProfileJoinChannel' : 'ProfileJoinGroup')} )} {canAddContact && ( {lang('AddContact')} )} {isMobile && canCall && ( {lang('Call')} )} {canCall && ( {lang('VideoCall')} )} {canMute && ( {lang(isMuted ? 'ChatsUnmute' : 'ChatsMute')} )} {(canEnterVoiceChat || canCreateVoiceChat) && ( {lang(canCreateVoiceChat ? 'StartVoipChat' : 'VoipGroupJoinCall')} )} {hasLinkedChat && ( {lang(isChannel ? 'ViewDiscussion' : 'lng_profile_view_channel')} )} {!withForumActions && ( {lang('ReportSelectMessages')} )} {canViewStatistics && ( {lang('Statistics')} )} {canReportChat && ( {lang('ReportPeer.Report')} )} {botButtons} {canGiftPremium && ( {lang('GiftPremium')} )} {canLeave && ( <> {lang(isPrivate ? 'DeleteChatUser' : (canDeleteChat ? 'GroupInfo.DeleteAndExit' : (isChannel ? 'LeaveChannel' : 'Group.LeaveGroup')))} )}
{chat && ( )} {canReportChat && chat?.id && ( )}
); }; export default memo(withGlobal( (global, { chatId, threadId }): StateProps => { const chat = selectChat(global, chatId); if (!chat || chat.isRestricted) { return {}; } const isPrivate = isUserId(chat.id); const user = isPrivate ? selectUser(global, chatId) : undefined; const canAddContact = user && getCanAddContact(user); const isMainThread = threadId === MAIN_THREAD_ID; const canReportChat = isMainThread && (isChatChannel(chat) || isChatGroup(chat) || (user && !user.isSelf)); const { chatId: currentChatId, threadId: currentThreadId } = selectCurrentMessageList(global) || {}; const chatBot = chatId !== REPLIES_USER_ID ? selectChatBot(global, chatId) : undefined; const userFullInfo = isPrivate ? selectUserFullInfo(global, chatId) : undefined; const chatFullInfo = !isPrivate ? selectChatFullInfo(global, chatId) : undefined; const canGiftPremium = Boolean( global.lastSyncTime && userFullInfo?.premiumGifts?.length && !selectIsPremiumPurchaseBlocked(global), ); const topic = chat?.topics?.[threadId]; const canCreateTopic = chat.isForum && ( chat.isCreator || !isUserRightBanned(chat, 'manageTopics') || getHasAdminRight(chat, 'manageTopics') ); const canEditTopic = topic && getCanManageTopic(chat, topic); return { chat, isMuted: selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)), isPrivate, isTopic: chat?.isForum && !isMainThread, isForum: chat?.isForum, canAddContact, canReportChat, canDeleteChat: getCanDeleteChat(chat), canGiftPremium, hasLinkedChat: Boolean(chatFullInfo?.linkedChatId), botCommands: chatBot ? userFullInfo?.botInfo?.commands : undefined, isChatInfoShown: selectTabState(global).isChatInfoShown && currentChatId === chatId && currentThreadId === threadId, canCreateTopic, canEditTopic, }; }, )(HeaderMenuContainer));