import React, { FC, memo, useCallback, useEffect, useState, } from '../../lib/teact/teact'; import { withGlobal } from '../../lib/teact/teactn'; import { GlobalActions } from '../../global/types'; import { ManagementScreens, NewChatMembersProgress, ProfileState, RightColumnContent, } from '../../types'; import { MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN } from '../../config'; import captureEscKeyListener from '../../util/captureEscKeyListener'; import { pick } from '../../util/iteratees'; import { selectAreActiveChatsLoaded, selectCurrentMessageList, selectRightColumnContentKey, } from '../../modules/selectors'; import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps'; import useWindowSize from '../../hooks/useWindowSize'; import useCurrentOrPrev from '../../hooks/useCurrentOrPrev'; import useHistoryBack from '../../hooks/useHistoryBack'; import RightHeader from './RightHeader'; import Profile from './Profile'; import Transition from '../ui/Transition'; import RightSearch from './RightSearch.async'; import Management from './management/Management.async'; import StickerSearch from './StickerSearch.async'; import GifSearch from './GifSearch.async'; import PollResults from './PollResults.async'; import AddChatMembers from './AddChatMembers'; import './RightColumn.scss'; type StateProps = { contentKey?: RightColumnContent; chatId?: number; threadId?: number; currentProfileUserId?: number; isChatSelected: boolean; shouldSkipHistoryAnimations?: boolean; }; type DispatchProps = Pick; const COLUMN_CLOSE_DELAY_MS = 300; const MAIN_SCREENS_COUNT = Object.keys(RightColumnContent).length / 2; const MANAGEMENT_SCREENS_COUNT = Object.keys(ManagementScreens).length / 2; function blurSearchInput() { const searchInput = document.querySelector('.RightHeader .SearchInput input') as HTMLInputElement; if (searchInput) { searchInput.blur(); } } const RightColumn: FC = ({ contentKey, chatId, threadId, currentProfileUserId, isChatSelected, toggleChatInfo, toggleManagement, openUserInfo, closeLocalTextSearch, setStickerSearchQuery, setGifSearchQuery, closePollResults, addChatMembers, setNewChatMembersDialogState, shouldSkipHistoryAnimations, }) => { const { width: windowWidth } = useWindowSize(); const [profileState, setProfileState] = useState(ProfileState.Profile); const [managementScreen, setManagementScreen] = useState(ManagementScreens.Initial); const [selectedChatMemberId, setSelectedChatMemberId] = useState(); const [isPromotedByCurrentUser, setIsPromotedByCurrentUser] = useState(); const isScrolledDown = profileState !== ProfileState.Profile; const isOpen = contentKey !== undefined; const isProfile = contentKey === RightColumnContent.ChatInfo || contentKey === RightColumnContent.UserInfo; const isSearch = contentKey === RightColumnContent.Search; const isManagement = contentKey === RightColumnContent.Management; const isStickerSearch = contentKey === RightColumnContent.StickerSearch; const isGifSearch = contentKey === RightColumnContent.GifSearch; const isPollResults = contentKey === RightColumnContent.PollResults; const isAddingChatMembers = contentKey === RightColumnContent.AddingMembers; const isOverlaying = windowWidth <= MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN; const [shouldSkipTransition, setShouldSkipTransition] = useState(!isOpen); const renderingContentKey = useCurrentOrPrev(contentKey, true, !isChatSelected) ?? -1; const close = useCallback((shouldScrollUp = true) => { switch (contentKey) { case RightColumnContent.AddingMembers: setNewChatMembersDialogState(NewChatMembersProgress.Closed); break; case RightColumnContent.ChatInfo: if (isScrolledDown && shouldScrollUp) { setProfileState(ProfileState.Profile); break; } toggleChatInfo(undefined, true); break; case RightColumnContent.UserInfo: if (isScrolledDown && shouldScrollUp) { setProfileState(ProfileState.Profile); break; } openUserInfo({ id: undefined }, true); break; case RightColumnContent.Management: { switch (managementScreen) { case ManagementScreens.Initial: toggleManagement(); break; case ManagementScreens.ChatPrivacyType: case ManagementScreens.Discussion: case ManagementScreens.GroupPermissions: case ManagementScreens.GroupType: case ManagementScreens.ChatAdministrators: case ManagementScreens.ChannelSubscribers: case ManagementScreens.GroupMembers: setManagementScreen(ManagementScreens.Initial); break; case ManagementScreens.GroupUserPermissionsCreate: case ManagementScreens.GroupRemovedUsers: case ManagementScreens.GroupUserPermissions: setManagementScreen(ManagementScreens.GroupPermissions); setSelectedChatMemberId(undefined); setIsPromotedByCurrentUser(undefined); break; case ManagementScreens.ChatAdminRights: case ManagementScreens.GroupRecentActions: setManagementScreen(ManagementScreens.ChatAdministrators); break; } break; } case RightColumnContent.Search: { blurSearchInput(); closeLocalTextSearch(); break; } case RightColumnContent.StickerSearch: blurSearchInput(); setStickerSearchQuery({ query: undefined }); break; case RightColumnContent.GifSearch: { blurSearchInput(); setGifSearchQuery({ query: undefined }); break; } case RightColumnContent.PollResults: closePollResults(); break; } }, [ contentKey, isScrolledDown, toggleChatInfo, openUserInfo, closePollResults, setNewChatMembersDialogState, managementScreen, toggleManagement, closeLocalTextSearch, setStickerSearchQuery, setGifSearchQuery, ]); const handleSelectChatMember = useCallback((memberId, isPromoted) => { setSelectedChatMemberId(memberId); setIsPromotedByCurrentUser(isPromoted); }, []); const handleAppendingChatMembers = useCallback((memberIds: number[]) => { addChatMembers({ chatId, memberIds }); }, [addChatMembers, chatId]); useEffect(() => (isOpen ? captureEscKeyListener(close) : undefined), [isOpen, close]); useEffect(() => { setTimeout(() => { setShouldSkipTransition(!isOpen); }, COLUMN_CLOSE_DELAY_MS); }, [isOpen]); // Close Right Column when it transforms into overlayed state on screen resize useEffect(() => { if (isOpen && isOverlaying) { close(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOverlaying]); // We need to clear profile state and management screen state, when changing chats useLayoutEffectWithPrevDeps(([prevContentKey, prevChatId]) => { if ( (prevContentKey === RightColumnContent.ChatInfo && contentKey === RightColumnContent.UserInfo) || (prevContentKey === RightColumnContent.UserInfo && contentKey === RightColumnContent.ChatInfo) || (prevChatId !== chatId) ) { setProfileState(ProfileState.Profile); setManagementScreen(ManagementScreens.Initial); } }, [contentKey, chatId]); useHistoryBack(isChatSelected && (contentKey === RightColumnContent.ChatInfo || contentKey === RightColumnContent.UserInfo || contentKey === RightColumnContent.Management || contentKey === RightColumnContent.AddingMembers), () => close(false), toggleChatInfo); // eslint-disable-next-line consistent-return function renderContent(isActive: boolean) { if (renderingContentKey === -1) { return undefined; } switch (renderingContentKey) { case RightColumnContent.AddingMembers: return ( ); case RightColumnContent.ChatInfo: case RightColumnContent.UserInfo: return ( ); case RightColumnContent.Search: return ; case RightColumnContent.Management: return ( ); case RightColumnContent.StickerSearch: return ; case RightColumnContent.GifSearch: return ; case RightColumnContent.PollResults: return ; } } return (
{isOverlaying && (
)}
{renderContent}
); }; export default memo(withGlobal( (global): StateProps => { const { chatId, threadId } = selectCurrentMessageList(global) || {}; const areActiveChatsLoaded = selectAreActiveChatsLoaded(global); return { contentKey: selectRightColumnContentKey(global), chatId, threadId, currentProfileUserId: global.users.selectedId, isChatSelected: Boolean(chatId && areActiveChatsLoaded), shouldSkipHistoryAnimations: global.shouldSkipHistoryAnimations, }; }, (setGlobal, actions): DispatchProps => pick(actions, [ 'openUserInfo', 'toggleChatInfo', 'toggleManagement', 'closeLocalTextSearch', 'setStickerSearchQuery', 'setGifSearchQuery', 'closePollResults', 'addChatMembers', 'setNewChatMembersDialogState', ]), )(RightColumn));