import type { FC } from '@teact'; import { memo, useEffect, useRef, useState } from '@teact'; import { getActions, withGlobal } from '../../global'; import type { AnimationLevel, ThreadId } from '../../types'; import { ManagementScreens, NewChatMembersProgress, ProfileState, RightColumnContent } from '../../types'; import { ANIMATION_END_DELAY, MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN } from '../../config'; import { getIsSavedDialog } from '../../global/helpers'; import { selectAreActiveChatsLoaded, selectCurrentMessageList, selectIsChatWithSelf, selectRightColumnContentKey, selectTabState, } from '../../global/selectors'; import { selectSharedSettings } from '../../global/selectors/sharedState.ts'; import captureEscKeyListener from '../../util/captureEscKeyListener'; import { resolveTransitionName } from '../../util/resolveTransitionName.ts'; import useCurrentOrPrev from '../../hooks/useCurrentOrPrev'; import useHistoryBack from '../../hooks/useHistoryBack'; import useLastCallback from '../../hooks/useLastCallback'; import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps'; import useScrollNotch from '../../hooks/useScrollNotch.ts'; import useWindowSize from '../../hooks/window/useWindowSize'; import Transition from '../ui/Transition'; import AddChatMembers from './AddChatMembers'; import CreateTopic from './CreateTopic.async'; import EditTopic from './EditTopic.async'; import GifSearch from './GifSearch.async'; import Management from './management/Management.async'; import PollResults from './PollResults.async'; import Profile from './Profile'; import RightHeader from './RightHeader'; import BoostStatistics from './statistics/BoostStatistics'; import MessageStatistics from './statistics/MessageStatistics.async'; import MonetizationStatistics from './statistics/MonetizationStatistics'; import Statistics from './statistics/Statistics.async'; import StoryStatistics from './statistics/StoryStatistics.async'; import StickerSearch from './StickerSearch.async'; import './RightColumn.scss'; interface OwnProps { isMobile?: boolean; } type StateProps = { contentKey?: RightColumnContent; chatId?: string; threadId?: ThreadId; isChatSelected: boolean; animationLevel: AnimationLevel; shouldSkipHistoryAnimations?: boolean; nextManagementScreen?: ManagementScreens; shouldCloseRightColumn?: boolean; isSavedMessages?: boolean; isSavedDialog?: boolean; isOwnProfile?: boolean; }; const ANIMATION_DURATION = 450 + ANIMATION_END_DELAY; 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, isMobile, isChatSelected, animationLevel, shouldSkipHistoryAnimations, nextManagementScreen, shouldCloseRightColumn, isSavedMessages, isSavedDialog, isOwnProfile, }) => { const { toggleChatInfo, toggleManagement, setStickerSearchQuery, setGifSearchQuery, closePollResults, addChatMembers, setNewChatMembersDialogState, setEditingExportedInvite, toggleStatistics, toggleMessageStatistics, toggleStoryStatistics, setOpenedInviteInfo, requestNextManagementScreen, closeCreateTopicPanel, closeEditTopicPanel, closeBoostStatistics, setShouldCloseRightColumn, closeMonetizationStatistics, } = getActions(); const containerRef = useRef(); const { width: windowWidth } = useWindowSize(); const [profileState, setProfileState] = useState( isSavedMessages && !isSavedDialog ? ProfileState.SavedDialogs : 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; const isManagement = contentKey === RightColumnContent.Management; const isStatistics = contentKey === RightColumnContent.Statistics; const isMessageStatistics = contentKey === RightColumnContent.MessageStatistics; const isStoryStatistics = contentKey === RightColumnContent.StoryStatistics; const isBoostStatistics = contentKey === RightColumnContent.BoostStatistics; const isMonetizationStatistics = contentKey === RightColumnContent.MonetizationStatistics; const isStickerSearch = contentKey === RightColumnContent.StickerSearch; const isGifSearch = contentKey === RightColumnContent.GifSearch; const isPollResults = contentKey === RightColumnContent.PollResults; const isAddingChatMembers = contentKey === RightColumnContent.AddingMembers; const isCreatingTopic = contentKey === RightColumnContent.CreateTopic; const isEditingTopic = contentKey === RightColumnContent.EditTopic; const isOverlaying = windowWidth <= MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN; const [shouldSkipTransition, setShouldSkipTransition] = useState(!isOpen); const renderingContentKey = useCurrentOrPrev(contentKey, true, !isChatSelected) ?? -1; useScrollNotch({ containerRef, selector: ':scope .custom-scroll, :scope .panel-content', }, [contentKey, managementScreen, chatId, threadId]); const close = useLastCallback((shouldScrollUp = true) => { switch (contentKey) { case RightColumnContent.AddingMembers: setNewChatMembersDialogState({ newChatMembersProgress: NewChatMembersProgress.Closed }); break; case RightColumnContent.ChatInfo: if (isScrolledDown && shouldScrollUp && !isSavedMessages) { setProfileState(ProfileState.Profile); break; } toggleChatInfo({ force: false }, { forceSyncOnIOs: 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: case ManagementScreens.Invites: case ManagementScreens.Reactions: case ManagementScreens.JoinRequests: case ManagementScreens.ChannelRemovedUsers: setManagementScreen(ManagementScreens.Initial); break; case ManagementScreens.GroupUserPermissionsCreate: case ManagementScreens.GroupRemovedUsers: case ManagementScreens.GroupUserPermissions: setManagementScreen(ManagementScreens.GroupPermissions); setSelectedChatMemberId(undefined); setIsPromotedByCurrentUser(undefined); break; case ManagementScreens.NewDiscussionGroup: setManagementScreen(ManagementScreens.Discussion); break; case ManagementScreens.ChatAdminRights: case ManagementScreens.ChatNewAdminRights: case ManagementScreens.GroupAddAdmins: case ManagementScreens.GroupRecentActions: setManagementScreen(ManagementScreens.ChatAdministrators); break; case ManagementScreens.EditInvite: case ManagementScreens.InviteInfo: setManagementScreen(ManagementScreens.Invites); setOpenedInviteInfo({ chatId: chatId!, invite: undefined }); setEditingExportedInvite({ chatId: chatId!, invite: undefined }); break; } break; } case RightColumnContent.MessageStatistics: toggleMessageStatistics(); break; case RightColumnContent.StoryStatistics: toggleStoryStatistics(); break; case RightColumnContent.Statistics: toggleStatistics(); break; case RightColumnContent.BoostStatistics: closeBoostStatistics(); break; case RightColumnContent.MonetizationStatistics: closeMonetizationStatistics(); break; case RightColumnContent.StickerSearch: blurSearchInput(); setStickerSearchQuery({ query: undefined }); break; case RightColumnContent.GifSearch: { blurSearchInput(); setGifSearchQuery({ query: undefined }); break; } case RightColumnContent.PollResults: closePollResults(); break; case RightColumnContent.CreateTopic: closeCreateTopicPanel(); break; case RightColumnContent.EditTopic: closeEditTopicPanel(); break; } }); const handleSelectChatMember = useLastCallback((memberId, isPromoted) => { setSelectedChatMemberId(memberId); setIsPromotedByCurrentUser(isPromoted); }); const handleAppendingChatMembers = useLastCallback((memberIds: string[]) => { addChatMembers({ chatId: chatId!, memberIds }); }); useEffect(() => (isOpen && chatId ? captureEscKeyListener(close) : undefined), [isOpen, close, chatId]); useEffect(() => { setTimeout(() => { setShouldSkipTransition(!isOpen); }, ANIMATION_DURATION); }, [isOpen]); useEffect(() => { if (nextManagementScreen) { setManagementScreen(nextManagementScreen); requestNextManagementScreen(undefined); } }, [nextManagementScreen]); useEffect(() => { if (shouldCloseRightColumn) { close(); setShouldCloseRightColumn({ value: undefined }); } }, [shouldCloseRightColumn]); // Close Right Column when it transforms into overlayed state on screen resize useEffect(() => { if (isOpen && isOverlaying) { close(); } // eslint-disable-next-line react-hooks-static-deps/exhaustive-deps }, [isOverlaying]); // We need to clear profile state and management screen state, when changing chats useLayoutEffectWithPrevDeps(([prevChatId, prevThreadId]) => { if (prevChatId !== chatId || prevThreadId !== threadId) { setProfileState( isSavedMessages && !isSavedDialog ? ProfileState.SavedDialogs : ProfileState.Profile, ); setManagementScreen(ManagementScreens.Initial); } }, [chatId, threadId, isSavedDialog, isSavedMessages]); useHistoryBack({ isActive: isChatSelected && ( contentKey === RightColumnContent.ChatInfo || contentKey === RightColumnContent.Management || contentKey === RightColumnContent.AddingMembers || contentKey === RightColumnContent.CreateTopic || contentKey === RightColumnContent.EditTopic), onBack: () => close(false), }); function renderContent(isActive: boolean) { if (renderingContentKey === -1) { return undefined; } switch (renderingContentKey) { case RightColumnContent.AddingMembers: return ( ); case RightColumnContent.ChatInfo: return ( ); case RightColumnContent.Management: return ( ); case RightColumnContent.Statistics: return ; case RightColumnContent.BoostStatistics: return ; case RightColumnContent.MonetizationStatistics: return ; case RightColumnContent.MessageStatistics: return ; case RightColumnContent.StoryStatistics: return ; case RightColumnContent.StickerSearch: return ; case RightColumnContent.GifSearch: return ; case RightColumnContent.PollResults: return ; case RightColumnContent.CreateTopic: return ; case RightColumnContent.EditTopic: return ; } return undefined; // Unreachable } return (
{isOverlaying && (
)}
{renderContent}
); }; export default memo(withGlobal( (global, { isMobile }): Complete => { const { chatId, threadId } = selectCurrentMessageList(global) || {}; const areActiveChatsLoaded = selectAreActiveChatsLoaded(global); const { animationLevel } = selectSharedSettings(global); const { management, shouldSkipHistoryAnimations, shouldCloseRightColumn, chatInfo, } = selectTabState(global); const nextManagementScreen = chatId ? management.byChatId[chatId]?.nextScreen : undefined; const isOwnProfile = chatInfo?.isOwnProfile; const isSavedMessages = chatId && !isOwnProfile ? selectIsChatWithSelf(global, chatId) : undefined; const isSavedDialog = chatId ? getIsSavedDialog(chatId, threadId, global.currentUserId) : undefined; return { contentKey: selectRightColumnContentKey(global, isMobile), chatId, threadId, isChatSelected: Boolean(chatId && areActiveChatsLoaded), animationLevel, shouldSkipHistoryAnimations, nextManagementScreen, shouldCloseRightColumn, isSavedMessages, isSavedDialog, isOwnProfile, }; }, )(RightColumn));