import React, { FC, memo, useRef, useCallback, useState, useEffect, } from '../../lib/teact/teact'; import { getDispatch, withGlobal } from '../../lib/teact/teactn'; import { MessageListType } from '../../global/types'; import { MAIN_THREAD_ID } from '../../api/types'; import { IAnchorPosition } from '../../types'; import { ARE_CALLS_SUPPORTED, IS_MAC_OS, IS_PWA, IS_SINGLE_COLUMN_LAYOUT, } from '../../util/environment'; import getKeyFromEvent from '../../util/getKeyFromEvent'; import { isChatBasicGroup, isChatChannel, isChatSuperGroup, isUserId, } from '../../modules/helpers'; import { selectChat, selectChatBot, selectIsUserBlocked, selectIsChatBotNotStarted, selectIsChatWithSelf, selectIsInSelectMode, selectIsRightColumnShown, } from '../../modules/selectors'; import useLang from '../../hooks/useLang'; import Button from '../ui/Button'; import HeaderMenuContainer from './HeaderMenuContainer.async'; interface OwnProps { chatId: string; threadId: number; messageListType: MessageListType; canExpandActions: boolean; } interface StateProps { noMenu?: boolean; isChannel?: boolean; isRightColumnShown?: boolean; canStartBot?: boolean; canRestartBot?: boolean; canSubscribe?: boolean; canSearch?: boolean; canCall?: boolean; canMute?: boolean; canLeave?: boolean; canEnterVoiceChat?: boolean; canCreateVoiceChat?: boolean; } // Chrome breaks layout when focusing input during transition const SEARCH_FOCUS_DELAY_MS = 400; const HeaderActions: FC = ({ chatId, threadId, noMenu, isChannel, canStartBot, canRestartBot, canSubscribe, canSearch, canCall, canMute, canLeave, canEnterVoiceChat, canCreateVoiceChat, isRightColumnShown, canExpandActions, }) => { const { joinChannel, sendBotCommand, openLocalTextSearch, restartBot, openCallFallbackConfirm, } = getDispatch(); // eslint-disable-next-line no-null/no-null const menuButtonRef = useRef(null); const [isMenuOpen, setIsMenuOpen] = useState(false); const [menuPosition, setMenuPosition] = useState(undefined); const handleHeaderMenuOpen = useCallback(() => { setIsMenuOpen(true); const rect = menuButtonRef.current!.getBoundingClientRect(); setMenuPosition({ x: rect.right, y: rect.bottom }); }, []); const handleHeaderMenuClose = useCallback(() => { setIsMenuOpen(false); }, []); const handleHeaderMenuHide = useCallback(() => { setMenuPosition(undefined); }, []); const handleSubscribeClick = useCallback(() => { joinChannel({ chatId }); }, [joinChannel, chatId]); const handleStartBot = useCallback(() => { sendBotCommand({ command: '/start' }); }, [sendBotCommand]); const handleRestartBot = useCallback(() => { restartBot({ chatId }); }, [chatId, restartBot]); const handleSearchClick = useCallback(() => { openLocalTextSearch(); if (IS_SINGLE_COLUMN_LAYOUT) { // iOS requires synchronous focus on user event. const searchInput = document.querySelector('#MobileSearch input')!; searchInput.focus(); } else { setTimeout(() => { const searchInput = document.querySelector('.RightHeader .SearchInput input'); if (searchInput) { searchInput.focus(); } }, SEARCH_FOCUS_DELAY_MS); } }, [openLocalTextSearch]); useEffect(() => { if (!canSearch) { return undefined; } function handleKeyDown(e: KeyboardEvent) { if ( IS_PWA && ((IS_MAC_OS && e.metaKey) || (!IS_MAC_OS && e.ctrlKey)) && !e.shiftKey && getKeyFromEvent(e) === 'f' ) { e.preventDefault(); handleSearchClick(); } } document.addEventListener('keydown', handleKeyDown, false); return () => { document.removeEventListener('keydown', handleKeyDown, false); }; }, [canSearch, handleSearchClick]); const lang = useLang(); return (
{!IS_SINGLE_COLUMN_LAYOUT && ( <> {canExpandActions && canSubscribe && ( )} {canExpandActions && canStartBot && ( )} {canExpandActions && canRestartBot && ( )} {canSearch && ( )} {canCall && ( )} )} {menuPosition && ( )}
); }; export default memo(withGlobal( (global, { chatId, threadId, messageListType }): StateProps => { const chat = selectChat(global, chatId); const isChannel = Boolean(chat && isChatChannel(chat)); if (!chat || chat.isRestricted || selectIsInSelectMode(global)) { return { noMenu: true, }; } const bot = selectChatBot(global, chatId); const isChatWithSelf = selectIsChatWithSelf(global, chatId); const isMainThread = messageListType === 'thread' && threadId === MAIN_THREAD_ID; const isDiscussionThread = messageListType === 'thread' && threadId !== MAIN_THREAD_ID; const isRightColumnShown = selectIsRightColumnShown(global); const canRestartBot = Boolean(bot && selectIsUserBlocked(global, bot.id)); const canStartBot = !canRestartBot && Boolean(selectIsChatBotNotStarted(global, chatId)); const canSubscribe = Boolean( isMainThread && (isChannel || isChatSuperGroup(chat)) && chat.isNotJoined, ); const canSearch = isMainThread || isDiscussionThread; const canCall = ARE_CALLS_SUPPORTED && isUserId(chat.id) && !isChatWithSelf && !bot; const canMute = isMainThread && !isChatWithSelf && !canSubscribe; const canLeave = isMainThread && !canSubscribe; const canEnterVoiceChat = ARE_CALLS_SUPPORTED && chat.isCallActive; const canCreateVoiceChat = ARE_CALLS_SUPPORTED && !chat.isCallActive && (chat.adminRights?.manageCall || (chat.isCreator && isChatBasicGroup(chat))); return { noMenu: false, isChannel, isRightColumnShown, canStartBot, canRestartBot, canSubscribe, canSearch, canCall, canMute, canLeave, canEnterVoiceChat, canCreateVoiceChat, }; }, )(HeaderActions));