import React, { FC, useEffect, useCallback, memo, useState, } from '../../lib/teact/teact'; import { withGlobal } from '../../lib/teact/teactn'; import { ApiUser, ApiChat } from '../../api/types'; import { GlobalActions, GlobalState } from '../../global/types'; import { MediaViewerOrigin } from '../../types'; import { IS_TOUCH_ENV } from '../../util/environment'; import { selectChat, selectUser } from '../../modules/selectors'; import { getUserFullName, getUserStatus, isChatChannel, isUserOnline, } from '../../modules/helpers'; import renderText from './helpers/renderText'; import { pick } from '../../util/iteratees'; import { captureEvents, SwipeDirection } from '../../util/captureEvents'; import buildClassName from '../../util/buildClassName'; import usePhotosPreload from './hooks/usePhotosPreload'; import useLang from '../../hooks/useLang'; import VerifiedIcon from './VerifiedIcon'; import ProfilePhoto from './ProfilePhoto'; import Transition from '../ui/Transition'; import './ProfileInfo.scss'; type OwnProps = { userId: number; forceShowSelf?: boolean; }; type StateProps = { user?: ApiUser; chat?: ApiChat; isSavedMessages?: boolean; animationLevel: 0 | 1 | 2; serverTimeOffset: number; } & Pick; type DispatchProps = Pick; const ProfileInfo: FC = ({ forceShowSelf, user, chat, isSavedMessages, connectionState, animationLevel, serverTimeOffset, loadFullUser, openMediaViewer, }) => { const { id: userId } = user || {}; const { id: chatId } = chat || {}; const fullName = user ? getUserFullName(user) : (chat ? chat.title : ''); const photos = user?.photos || chat?.photos || []; const slideAnimation = animationLevel >= 1 ? 'slide' : 'none'; const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0); const isFirst = isSavedMessages || photos.length <= 1 || currentPhotoIndex === 0; const isLast = isSavedMessages || photos.length <= 1 || currentPhotoIndex === photos.length - 1; // Deleting the last profile photo may result in an error useEffect(() => { if (currentPhotoIndex > photos.length) { setCurrentPhotoIndex(Math.max(0, photos.length - 1)); } }, [currentPhotoIndex, photos.length]); const lang = useLang(); useEffect(() => { if (connectionState === 'connectionStateReady' && userId && !forceShowSelf) { loadFullUser({ userId }); } }, [userId, loadFullUser, connectionState, forceShowSelf]); usePhotosPreload(user || chat, photos, currentPhotoIndex); const handleProfilePhotoClick = useCallback(() => { openMediaViewer({ avatarOwnerId: userId || chatId, profilePhotoIndex: currentPhotoIndex, origin: forceShowSelf ? MediaViewerOrigin.SettingsAvatar : MediaViewerOrigin.ProfileAvatar, }); }, [openMediaViewer, userId, chatId, currentPhotoIndex, forceShowSelf]); const selectPreviousMedia = useCallback(() => { if (isFirst) { return; } setCurrentPhotoIndex(currentPhotoIndex - 1); }, [currentPhotoIndex, isFirst]); const selectNextMedia = useCallback(() => { if (isLast) { return; } setCurrentPhotoIndex(currentPhotoIndex + 1); }, [currentPhotoIndex, isLast]); // Support for swipe gestures and closing on click useEffect(() => { const element = document.querySelector('.photo-wrapper'); if (!element) { return undefined; } return captureEvents(element, { selectorToPreventScroll: '.Profile, .settings-content', onSwipe: IS_TOUCH_ENV ? (e, direction) => { if (direction === SwipeDirection.Right) { selectPreviousMedia(); return true; } else if (direction === SwipeDirection.Left) { selectNextMedia(); return true; } return false; } : undefined, }); }, [selectNextMedia, selectPreviousMedia]); if (!user && !chat) { return undefined; } function renderPhotoTabs() { if (isSavedMessages || !photos || photos.length <= 1) { return undefined; } return (
{photos.map((_, i) => ( ))}
); } function renderPhoto() { const photo = !isSavedMessages && photos && photos.length > 0 ? photos[currentPhotoIndex] : undefined; return ( ); } function renderStatus() { if (user) { return (
{getUserStatus(lang, user, serverTimeOffset)}
); } return ( { isChatChannel(chat!) ? lang('Subscribers', chat!.membersCount ?? 0, 'i') : lang('Members', chat!.membersCount ?? 0, 'i') } ); } const isVerifiedIconShown = (user || chat)?.isVerified; return (
{renderPhotoTabs()} {renderPhoto} {!isFirst && (
{isSavedMessages ? (

{lang('SavedMessages')}

) : (

{fullName && renderText(fullName)}

{isVerifiedIconShown && }
)} {!isSavedMessages && renderStatus()}
); }; export default memo(withGlobal( (global, { userId, forceShowSelf }): StateProps => { const { connectionState, serverTimeOffset } = global; const user = selectUser(global, userId); const chat = selectChat(global, userId); const isSavedMessages = !forceShowSelf && user && user.isSelf; const { animationLevel } = global.settings.byKey; return { connectionState, user, chat, isSavedMessages, animationLevel, serverTimeOffset, }; }, (setGlobal, actions): DispatchProps => pick(actions, ['loadFullUser', 'openMediaViewer']), )(ProfileInfo));