From b66048aad2529b3827b6d06e88dff7becdf8d426 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Thu, 21 Aug 2025 12:05:12 +0200 Subject: [PATCH] Message List, Shared Media, Left Search, Symbol Menu: Add transition to loading spinner --- src/components/common/CustomEmojiPicker.tsx | 138 +++++++------- src/components/left/search/AudioResults.tsx | 10 +- src/components/left/search/BotAppResults.tsx | 11 +- src/components/left/search/FileResults.tsx | 11 +- src/components/left/search/LinkResults.tsx | 11 +- src/components/left/search/MediaResults.tsx | 11 +- src/components/middle/MessageList.tsx | 174 ++++++++++-------- .../middle/composer/EmojiPicker.tsx | 77 ++++---- src/components/middle/composer/GifPicker.scss | 13 +- src/components/middle/composer/GifPicker.tsx | 60 +++--- .../middle/composer/StickerPicker.tsx | 133 ++++++------- src/components/middle/composer/SymbolMenu.tsx | 1 - src/components/right/Profile.tsx | 39 ++-- src/components/ui/ResponsiveHoverButton.tsx | 1 - src/components/ui/Transition.scss | 4 +- src/components/ui/Transition.tsx | 6 + 16 files changed, 384 insertions(+), 316 deletions(-) diff --git a/src/components/common/CustomEmojiPicker.tsx b/src/components/common/CustomEmojiPicker.tsx index bfeabc7df..c9f69b03e 100644 --- a/src/components/common/CustomEmojiPicker.tsx +++ b/src/components/common/CustomEmojiPicker.tsx @@ -1,7 +1,7 @@ -import type { FC } from '../../lib/teact/teact'; +import type { FC } from '@teact'; import { memo, useEffect, useMemo, useRef, -} from '../../lib/teact/teact'; +} from '@teact'; import { getGlobal, withGlobal } from '../../global'; import type { @@ -48,6 +48,7 @@ import { useStickerPickerObservers } from './hooks/useStickerPickerObservers'; import StickerSetCover from '../middle/composer/StickerSetCover'; import Button from '../ui/Button'; import Loading from '../ui/Loading'; +import Transition from '../ui/Transition.tsx'; import Icon from './icons/Icon'; import StickerButton from './StickerButton'; import StickerSet from './StickerSet'; @@ -397,19 +398,6 @@ const CustomEmojiPicker: FC = ({ } const fullClassName = buildClassName('StickerPicker', styles.root, className); - - if (!shouldRenderContent) { - return ( -
- {noPopulatedSets ? ( -
{oldLang('NoStickers')}
- ) : ( - - )} -
- ); - } - const headerClassName = buildClassName( pickerStyles.header, 'no-scrollbar', @@ -423,62 +411,72 @@ const CustomEmojiPicker: FC = ({ pickerStyles.hasHeader, ); - return ( -
-
-
- - - {allSets.map(renderCover)} -
-
-
- {allSets.map((stickerSet, i) => { - const shouldHideHeader = stickerSet.id === TOP_SYMBOL_SET_ID - || (stickerSet.id === RECENT_SYMBOL_SET_ID && (withDefaultTopicIcons || isStatusPicker)); - const isChatEmojiSet = stickerSet.id === chatEmojiSetId; + const isLoading = !shouldRenderContent && !noPopulatedSets; - return ( - = i - 1 && activeSetIndex <= i + 1} - isSavedMessages={isSavedMessages} - isStatusPicker={isStatusPicker} - isReactionPicker={isReactionPicker} - shouldHideHeader={shouldHideHeader} - withDefaultTopicIcon={withDefaultTopicIcons && stickerSet.id === RECENT_SYMBOL_SET_ID} - withDefaultStatusIcon={isStatusPicker && stickerSet.id === RECENT_SYMBOL_SET_ID} - isChatEmojiSet={isChatEmojiSet} - isCurrentUserPremium={isCurrentUserPremium} - selectedReactionIds={selectedReactionIds} - availableReactions={availableReactions} - isTranslucent={isTranslucent} - onReactionSelect={onReactionSelect} - onReactionContext={onReactionContext} - onStickerSelect={handleEmojiSelect} - onContextMenuOpen={onContextMenuOpen} - onContextMenuClose={onContextMenuClose} - onContextMenuClick={onContextMenuClick} - forcePlayback - /> - ); - })} -
-
+ return ( + + {!shouldRenderContent && !noPopulatedSets ? ( + + ) : !shouldRenderContent && noPopulatedSets ? ( +
{oldLang('NoStickers')}
+ ) : ( + <> +
+
+ + + {allSets.map(renderCover)} +
+
+
+ {allSets.map((stickerSet, i) => { + const shouldHideHeader = stickerSet.id === TOP_SYMBOL_SET_ID + || (stickerSet.id === RECENT_SYMBOL_SET_ID && (withDefaultTopicIcons || isStatusPicker)); + const isChatEmojiSet = stickerSet.id === chatEmojiSetId; + + return ( + = i - 1 && activeSetIndex <= i + 1} + isSavedMessages={isSavedMessages} + isStatusPicker={isStatusPicker} + isReactionPicker={isReactionPicker} + shouldHideHeader={shouldHideHeader} + withDefaultTopicIcon={withDefaultTopicIcons && stickerSet.id === RECENT_SYMBOL_SET_ID} + withDefaultStatusIcon={isStatusPicker && stickerSet.id === RECENT_SYMBOL_SET_ID} + isChatEmojiSet={isChatEmojiSet} + isCurrentUserPremium={isCurrentUserPremium} + selectedReactionIds={selectedReactionIds} + availableReactions={availableReactions} + isTranslucent={isTranslucent} + onReactionSelect={onReactionSelect} + onReactionContext={onReactionContext} + onStickerSelect={handleEmojiSelect} + onContextMenuOpen={onContextMenuOpen} + onContextMenuClose={onContextMenuClose} + onContextMenuClick={onContextMenuClick} + forcePlayback + /> + ); + })} +
+ + )} +
); }; diff --git a/src/components/left/search/AudioResults.tsx b/src/components/left/search/AudioResults.tsx index abd3bde83..3dbee6ab4 100644 --- a/src/components/left/search/AudioResults.tsx +++ b/src/components/left/search/AudioResults.tsx @@ -23,6 +23,7 @@ import Audio from '../../common/Audio'; import NothingFound from '../../common/NothingFound'; import InfiniteScroll from '../../ui/InfiniteScroll'; import Loading from '../../ui/Loading'; +import Transition from '../../ui/Transition.tsx'; export type OwnProps = { isVoice?: boolean; @@ -126,7 +127,12 @@ const AudioResults: FC = ({ const canRenderContents = useAsyncRendering([searchQuery], SLIDE_TRANSITION_DURATION) && !isLoading; return ( -
+ = ({ )} {canRenderContents && foundIds && foundIds.length > 0 && renderList()} -
+ ); }; diff --git a/src/components/left/search/BotAppResults.tsx b/src/components/left/search/BotAppResults.tsx index b93f40758..a1818853d 100644 --- a/src/components/left/search/BotAppResults.tsx +++ b/src/components/left/search/BotAppResults.tsx @@ -20,6 +20,7 @@ import NothingFound from '../../common/NothingFound'; import InfiniteScroll from '../../ui/InfiniteScroll'; import Link from '../../ui/Link'; import Loading from '../../ui/Loading'; +import Transition from '../../ui/Transition.tsx'; import LeftSearchResultChat from './LeftSearchResultChat'; export type OwnProps = { @@ -79,7 +80,13 @@ const BotAppResults: FC = ({ const canRenderContents = useAsyncRendering([searchQuery], SLIDE_TRANSITION_DURATION) && !isLoading; return ( -
+ = ({
)} - + ); }; diff --git a/src/components/left/search/FileResults.tsx b/src/components/left/search/FileResults.tsx index 2c55f8a89..6dc10f0b3 100644 --- a/src/components/left/search/FileResults.tsx +++ b/src/components/left/search/FileResults.tsx @@ -25,6 +25,7 @@ import Document from '../../common/Document'; import NothingFound from '../../common/NothingFound'; import InfiniteScroll from '../../ui/InfiniteScroll'; import Loading from '../../ui/Loading'; +import Transition from '../../ui/Transition.tsx'; export type OwnProps = { searchQuery?: string; @@ -129,7 +130,13 @@ const FileResults: FC = ({ const canRenderContents = useAsyncRendering([searchQuery], SLIDE_TRANSITION_DURATION) && !isLoading; return ( -
+ = ({ )} {canRenderContents && foundIds && foundIds.length > 0 && renderList()} -
+ ); }; diff --git a/src/components/left/search/LinkResults.tsx b/src/components/left/search/LinkResults.tsx index f3f27da67..9b9e709ab 100644 --- a/src/components/left/search/LinkResults.tsx +++ b/src/components/left/search/LinkResults.tsx @@ -24,6 +24,7 @@ import NothingFound from '../../common/NothingFound'; import WebLink from '../../common/WebLink'; import InfiniteScroll from '../../ui/InfiniteScroll'; import Loading from '../../ui/Loading'; +import Transition from '../../ui/Transition.tsx'; export type OwnProps = { searchQuery?: string; @@ -122,7 +123,13 @@ const LinkResults: FC = ({ const canRenderContents = useAsyncRendering([searchQuery], SLIDE_TRANSITION_DURATION) && !isLoading; return ( -
+ = ({ )} {canRenderContents && foundIds && foundIds.length > 0 && renderList()} -
+ ); }; diff --git a/src/components/left/search/MediaResults.tsx b/src/components/left/search/MediaResults.tsx index 11cc0651f..b58db26f4 100644 --- a/src/components/left/search/MediaResults.tsx +++ b/src/components/left/search/MediaResults.tsx @@ -22,6 +22,7 @@ import Media from '../../common/Media'; import NothingFound from '../../common/NothingFound'; import InfiniteScroll from '../../ui/InfiniteScroll'; import Loading from '../../ui/Loading'; +import Transition from '../../ui/Transition.tsx'; import ChatMessage from './ChatMessage'; export type OwnProps = { @@ -122,7 +123,13 @@ const MediaResults: FC = ({ ); return ( -
+ = ({ {isMediaGrid && renderGallery()} {isMessageList && renderSearchResult()} -
+ ); }; diff --git a/src/components/middle/MessageList.tsx b/src/components/middle/MessageList.tsx index 61e6a9ce2..b914e027b 100644 --- a/src/components/middle/MessageList.tsx +++ b/src/components/middle/MessageList.tsx @@ -1,16 +1,9 @@ -import type { FC } from '../../lib/teact/teact'; -import { - beginHeavyAnimation, memo, useEffect, useMemo, useRef, -} from '../../lib/teact/teact'; -import { addExtraClass, removeExtraClass } from '../../lib/teact/teact-dom'; +import type { FC } from '@teact'; +import { beginHeavyAnimation, memo, useEffect, useMemo, useRef } from '@teact'; +import { addExtraClass, removeExtraClass } from '@teact/teact-dom.ts'; import { getActions, getGlobal, withGlobal } from '../../global'; -import type { - ApiChatFullInfo, - ApiMessage, - ApiRestrictionReason, - ApiTopic, -} from '../../api/types'; +import type { ApiChatFullInfo, ApiMessage, ApiRestrictionReason, ApiTopic } from '../../api/types'; import type { OnIntersectPinnedMessage } from './hooks/usePinnedMessage'; import { MAIN_THREAD_ID } from '../../api/types'; import { LoadMoreDirection, type MessageListType, type ThreadId } from '../../types'; @@ -83,6 +76,7 @@ import useContainerHeight from './hooks/useContainerHeight'; import useStickyDates from './hooks/useStickyDates'; import Loading from '../ui/Loading'; +import Transition from '../ui/Transition.tsx'; import ContactGreeting from './ContactGreeting'; import MessageListAccountInfo from './MessageListAccountInfo'; import MessageListContent from './MessageListContent'; @@ -150,6 +144,17 @@ type StateProps = { shouldAutoTranslate?: boolean; }; +enum Content { + Loading, + Restricted, + StarsRequired, + PremiumRequired, + AccountInfo, + ContactGreeting, + NoMessages, + MessageList, +} + const MESSAGE_REACTIONS_POLLING_INTERVAL = 20 * 1000; const MESSAGE_COMMENTS_POLLING_INTERVAL = 20 * 1000; const MESSAGE_FACT_CHECK_UPDATE_INTERVAL = 5 * 1000; @@ -711,73 +716,98 @@ const MessageList: FC = ({ onScrollDownToggle(false); }, [hasMessages, onScrollDownToggle]); + const activeKey = isRestricted ? ( + Content.Restricted + ) : paidMessagesStars && !hasMessages && !hasCustomGreeting ? ( + Content.StarsRequired + ) : isContactRequirePremium && !hasMessages ? ( + Content.PremiumRequired + ) : (isBot || isNonContact) && !hasMessages ? ( + Content.AccountInfo + ) : shouldRenderGreeting ? ( + Content.ContactGreeting + ) : messageIds && (!messageGroups || isGroupChatJustCreated || isEmptyTopic) ? ( + Content.NoMessages + ) : hasMessages ? ( + Content.MessageList + ) : ( + Content.Loading + ); + + function renderContent() { + return activeKey === Content.Restricted ? ( +
+ + {restrictionReasons?.[0]?.text || `This is a private ${isChannelChat ? 'channel' : 'chat'}`} + +
+ ) : activeKey === Content.StarsRequired ? ( + + ) : activeKey === Content.PremiumRequired ? ( + + ) : activeKey === Content.AccountInfo ? ( + + ) : activeKey === Content.ContactGreeting ? ( + + ) : activeKey === Content.NoMessages ? ( + + ) : activeKey === Content.MessageList ? ( + + ) : ( + + ); + } + return ( -
- {isRestricted ? ( -
- - {restrictionReasons?.[0]?.text || `This is a private ${isChannelChat ? 'channel' : 'chat'}`} - -
- ) : paidMessagesStars && !hasMessages && !hasCustomGreeting ? ( - - ) : isContactRequirePremium && !hasMessages ? ( - - ) : (isBot || isNonContact) && !hasMessages ? ( - - ) : shouldRenderGreeting ? ( - - ) : messageIds && (!messageGroups || isGroupChatJustCreated || isEmptyTopic) ? ( - - ) : hasMessages ? ( - - ) : ( - - )} -
+ {renderContent()} + ); }; diff --git a/src/components/middle/composer/EmojiPicker.tsx b/src/components/middle/composer/EmojiPicker.tsx index ddbab2230..33c41583b 100644 --- a/src/components/middle/composer/EmojiPicker.tsx +++ b/src/components/middle/composer/EmojiPicker.tsx @@ -1,17 +1,10 @@ import type { FC } from '../../../lib/teact/teact'; -import { - memo, useEffect, useMemo, - useRef, useState, -} from '../../../lib/teact/teact'; +import { memo, useEffect, useMemo, useRef, useState } from '../../../lib/teact/teact'; import { withGlobal } from '../../../global'; import type { GlobalState } from '../../../global/types'; import type { IconName } from '../../../types/icons'; -import type { - EmojiData, - EmojiModule, - EmojiRawData, -} from '../../../util/emoji/emoji'; +import type { EmojiData, EmojiModule, EmojiRawData } from '../../../util/emoji/emoji'; import { MENU_TRANSITION_DURATION, RECENT_SYMBOL_SET_ID } from '../../../config'; import animateHorizontalScroll from '../../../util/animateHorizontalScroll'; @@ -34,6 +27,7 @@ import useAsyncRendering from '../../right/hooks/useAsyncRendering'; import Icon from '../../common/icons/Icon'; import Button from '../../ui/Button'; import Loading from '../../ui/Loading'; +import Transition from '../../ui/Transition.tsx'; import EmojiCategory from './EmojiCategory'; import './EmojiPicker.scss'; @@ -206,46 +200,43 @@ const EmojiPicker: FC = ({ } const containerClassName = buildClassName('EmojiPicker', className); - - if (!shouldRenderContent) { - return ( -
- -
- ); - } - const headerClassName = buildClassName( 'EmojiPicker-header', !shouldHideTopBorder && 'with-top-border', ); return ( -
-
- {allCategories.map(renderCategoryButton)} -
-
- {allCategories.map((category, i) => ( - = i - 1 && activeCategoryIndex <= i + 1} - onEmojiSelect={handleEmojiSelect} - /> - ))} -
-
+ + {!shouldRenderContent ? ( + + ) : ( + <> +
+ {allCategories.map(renderCategoryButton)} +
+
+ {allCategories.map((category, i) => ( + = i - 1 && activeCategoryIndex <= i + 1} + onEmojiSelect={handleEmojiSelect} + /> + ))} +
+ + )} +
); }; diff --git a/src/components/middle/composer/GifPicker.scss b/src/components/middle/composer/GifPicker.scss index a1f749808..eb3ac7162 100644 --- a/src/components/middle/composer/GifPicker.scss +++ b/src/components/middle/composer/GifPicker.scss @@ -3,11 +3,6 @@ top: 0.1875rem; overflow-y: auto; - display: grid; - grid-auto-flow: dense; - grid-auto-rows: 6.25rem; - grid-gap: 0.125rem; - grid-template-columns: repeat(6, 1fr); height: calc(100% - 0.1875rem); margin: 0 0.1875rem; @@ -30,3 +25,11 @@ border-radius: var(--border-radius-default) !important; } } + +.GifPickerGrid { + display: grid; + grid-auto-flow: dense; + grid-auto-rows: 6.25rem; + grid-gap: 0.125rem; + grid-template-columns: repeat(6, 1fr); +} diff --git a/src/components/middle/composer/GifPicker.tsx b/src/components/middle/composer/GifPicker.tsx index b0a73a6e6..4edbc9fc7 100644 --- a/src/components/middle/composer/GifPicker.tsx +++ b/src/components/middle/composer/GifPicker.tsx @@ -1,7 +1,5 @@ import type { FC } from '../../../lib/teact/teact'; -import { - memo, useEffect, useRef, -} from '../../../lib/teact/teact'; +import { memo, useEffect, useRef } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; import type { ApiVideo } from '../../../api/types'; @@ -17,6 +15,7 @@ import useAsyncRendering from '../../right/hooks/useAsyncRendering'; import GifButton from '../../common/GifButton'; import Loading from '../../ui/Loading'; +import Transition from '../../ui/Transition.tsx'; import './GifPicker.scss'; @@ -61,34 +60,37 @@ const GifPicker: FC = ({ }); const canRenderContents = useAsyncRendering([], SLIDE_TRANSITION_DURATION); + const isLoading = canSendGifs && (!canRenderContents || !savedGifs); return ( -
-
- {!canSendGifs ? ( -
Sending GIFs is not allowed in this chat.
- ) : canRenderContents && savedGifs && savedGifs.length ? ( - savedGifs.map((gif) => ( - - )) - ) : canRenderContents && savedGifs ? ( -
No saved GIFs.
- ) : ( - - )} -
-
+ + {!canSendGifs ? ( +
Sending GIFs is not allowed in this chat.
+ ) : canRenderContents && savedGifs && savedGifs.length ? ( + savedGifs.map((gif) => ( + + )) + ) : canRenderContents && savedGifs ? ( +
No saved GIFs.
+ ) : ( + + )} +
); }; diff --git a/src/components/middle/composer/StickerPicker.tsx b/src/components/middle/composer/StickerPicker.tsx index c9c14ea05..d33b7808a 100644 --- a/src/components/middle/composer/StickerPicker.tsx +++ b/src/components/middle/composer/StickerPicker.tsx @@ -1,8 +1,5 @@ import type { FC } from '../../../lib/teact/teact'; -import { - memo, useEffect, useMemo, - useRef, -} from '../../../lib/teact/teact'; +import { memo, useEffect, useMemo, useRef } from '../../../lib/teact/teact'; import { getActions, withGlobal } from '../../../global'; import type { ApiChat, ApiSticker, ApiStickerSet } from '../../../api/types'; @@ -19,7 +16,11 @@ import { STICKER_SIZE_PICKER_HEADER, } from '../../../config'; import { - selectChat, selectChatFullInfo, selectIsChatWithSelf, selectIsCurrentUserPremium, selectShouldLoopStickers, + selectChat, + selectChatFullInfo, + selectIsChatWithSelf, + selectIsCurrentUserPremium, + selectShouldLoopStickers, } from '../../../global/selectors'; import animateHorizontalScroll from '../../../util/animateHorizontalScroll'; import { IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment'; @@ -43,6 +44,7 @@ import StickerButton from '../../common/StickerButton'; import StickerSet from '../../common/StickerSet'; import Button from '../../ui/Button'; import Loading from '../../ui/Loading'; +import Transition from '../../ui/Transition.tsx'; import StickerSetCover from './StickerSetCover'; import styles from './StickerPicker.module.scss'; @@ -329,76 +331,75 @@ const StickerPicker: FC = ({ } const fullClassName = buildClassName(styles.root, className); - - if (!shouldRenderContents) { - return ( -
- {!canSendStickers && !isForEffects ? ( -
{lang('ErrorSendRestrictedStickersAll')}
- ) : noPopulatedSets ? ( -
{lang('NoStickers')}
- ) : ( - - )} -
- ); - } - const headerClassName = buildClassName( styles.header, 'no-scrollbar', !shouldHideTopBorder && styles.headerWithBorder, ); + const isLoading = !shouldRenderContents && (canSendStickers || isForEffects) && !noPopulatedSets; + return ( -
- {!isForEffects && ( -
-
- - {allSets.map(renderCover)} + + {!shouldRenderContents ? ( + !canSendStickers && !isForEffects ? ( +
{lang('ErrorSendRestrictedStickersAll')}
+ ) : noPopulatedSets ? ( +
{lang('NoStickers')}
+ ) : ( + + ) + ) : ( + <> + {!isForEffects && ( +
+
+ + {allSets.map(renderCover)} +
+
+ )} +
+ {allSets.map((stickerSet, i) => ( + = i - 1 && activeSetIndex <= i + 1} + favoriteStickers={favoriteStickers} + isSavedMessages={isSavedMessages} + isCurrentUserPremium={isCurrentUserPremium} + isTranslucent={isTranslucent} + isChatStickerSet={stickerSet.id === chatStickerSetId} + onStickerSelect={handleStickerSelect} + onStickerUnfave={handleStickerUnfave} + onStickerFave={handleStickerFave} + onStickerRemoveRecent={handleRemoveRecentSticker} + forcePlayback + shouldHideHeader={stickerSet.id === EFFECT_EMOJIS_SET_ID} + /> + ))}
-
+ )} -
- {allSets.map((stickerSet, i) => ( - = i - 1 && activeSetIndex <= i + 1} - favoriteStickers={favoriteStickers} - isSavedMessages={isSavedMessages} - isCurrentUserPremium={isCurrentUserPremium} - isTranslucent={isTranslucent} - isChatStickerSet={stickerSet.id === chatStickerSetId} - onStickerSelect={handleStickerSelect} - onStickerUnfave={handleStickerUnfave} - onStickerFave={handleStickerFave} - onStickerRemoveRecent={handleRemoveRecentSticker} - forcePlayback - shouldHideHeader={stickerSet.id === EFFECT_EMOJIS_SET_ID} - /> - ))} -
-
+ ); }; diff --git a/src/components/middle/composer/SymbolMenu.tsx b/src/components/middle/composer/SymbolMenu.tsx index 62ed54a20..835aa85a2 100644 --- a/src/components/middle/composer/SymbolMenu.tsx +++ b/src/components/middle/composer/SymbolMenu.tsx @@ -331,7 +331,6 @@ const SymbolMenu: FC = ({ onMouseLeave={!IS_TOUCH_ENV ? handleMouseLeave : undefined} noCloseOnBackdrop={!IS_TOUCH_ENV} noCompact - {...(isAttachmentModal ? menuPositionOptions : { positionX: 'left', positionY: 'bottom', diff --git a/src/components/right/Profile.tsx b/src/components/right/Profile.tsx index 445eac8e5..f2ed43e18 100644 --- a/src/components/right/Profile.tsx +++ b/src/components/right/Profile.tsx @@ -1,8 +1,5 @@ -import type { FC } from '../../lib/teact/teact'; -import { - memo, useCallback, - useEffect, useMemo, useRef, useState, -} from '../../lib/teact/teact'; +import type { FC } from '@teact'; +import { memo, useCallback, useEffect, useMemo, useRef, useState } from '@teact'; import { getActions, getGlobal, withGlobal } from '../../global'; import type { @@ -16,20 +13,12 @@ import type { ApiUserStatus, } from '../../api/types'; import type { TabState } from '../../global/types'; -import type { - AnimationLevel, - ProfileState, ProfileTabType, SharedMediaType, ThemeKey, ThreadId, -} from '../../types'; +import type { AnimationLevel, ProfileState, ProfileTabType, SharedMediaType, ThemeKey, ThreadId } from '../../types'; import type { RegularLangKey } from '../../types/language'; import { MAIN_THREAD_ID } from '../../api/types'; import { AudioOrigin, MediaViewerOrigin, NewChatMembersProgress } from '../../types'; -import { - MEMBERS_SLICE, - PROFILE_SENSITIVE_AREA, - SHARED_MEDIA_SLICE, - SLIDE_TRANSITION_DURATION, -} from '../../config'; +import { MEMBERS_SLICE, PROFILE_SENSITIVE_AREA, SHARED_MEDIA_SLICE, SLIDE_TRANSITION_DURATION } from '../../config'; import { getHasAdminRight, getIsDownloading, @@ -592,8 +581,19 @@ const Profile: FC = ({ ); } - if ((!viewportIds && !botPreviewMedia) || !canRenderContent || !messagesById) { - const noSpinner = isFirstTab && !canRenderContent; + const noContent = (!viewportIds && !botPreviewMedia) || !canRenderContent || !messagesById; + const noSpinner = isFirstTab && !canRenderContent; + const isSpinner = noContent && !noSpinner; + + return ( + + {renderSpinnerOrContent(noContent, noSpinner)} + + ); + } + + function renderSpinnerOrContent(noContent: boolean, noSpinner: boolean) { + if (noContent) { const forceRenderHiddenMembers = Boolean(resultType === 'members' && areMembersHidden); return ( @@ -651,6 +651,11 @@ const Profile: FC = ({ ); } + if (!messagesById) { + // A TypeScript assertion, should never be really reached + return; + } + return (
= ({ onActivate, ...buttonProps }) => return (