[Refactoring] User: Extract nested data to a separate path (#4953)
This commit is contained in:
parent
8b76de86ba
commit
25b4aae4cd
@ -5,7 +5,6 @@ import type {
|
||||
ApiChat, ApiPeer, ApiSticker, ApiUser,
|
||||
} from '../../types';
|
||||
|
||||
import { COMMON_CHATS_LIMIT } from '../../../config';
|
||||
import { buildApiChatFromPreview } from '../apiBuilders/chats';
|
||||
import { buildApiPhoto } from '../apiBuilders/common';
|
||||
import { buildApiPeerId } from '../apiBuilders/peers';
|
||||
@ -87,21 +86,21 @@ export async function fetchFullUser({
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchCommonChats(id: string, accessHash?: string, maxId?: string) {
|
||||
const commonChats = await invokeRequest(new GramJs.messages.GetCommonChats({
|
||||
userId: buildInputEntity(id, accessHash) as GramJs.InputUser,
|
||||
export async function fetchCommonChats(user: ApiUser, maxId?: string) {
|
||||
const result = await invokeRequest(new GramJs.messages.GetCommonChats({
|
||||
userId: buildInputEntity(user.id, user.accessHash) as GramJs.InputUser,
|
||||
maxId: maxId ? buildMtpPeerId(maxId, getEntityTypeById(maxId)) : undefined,
|
||||
limit: COMMON_CHATS_LIMIT,
|
||||
}));
|
||||
|
||||
if (!commonChats) {
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const chats = commonChats.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean);
|
||||
const chats = result.chats.map((c) => buildApiChatFromPreview(c)).filter(Boolean);
|
||||
const chatIds = chats.map(({ id: chatId }) => chatId);
|
||||
const count = 'count' in result ? result.count : chatIds.length;
|
||||
|
||||
return { chatIds, isFullyLoaded: chatIds.length < COMMON_CHATS_LIMIT };
|
||||
return { chatIds, count };
|
||||
}
|
||||
|
||||
export async function fetchNearestCountry() {
|
||||
|
||||
@ -3,7 +3,7 @@ import type { ApiBotCommand } from './bots';
|
||||
import type {
|
||||
ApiChatReactions, ApiFormattedText, ApiPhoto, ApiStickerSet,
|
||||
} from './messages';
|
||||
import type { ApiChatInviteImporter, ApiPeerPhotos } from './misc';
|
||||
import type { ApiChatInviteImporter } from './misc';
|
||||
import type {
|
||||
ApiEmojiStatus, ApiFakeType, ApiUser, ApiUsername,
|
||||
} from './users';
|
||||
@ -41,7 +41,6 @@ export interface ApiChat {
|
||||
membersCount?: number;
|
||||
creationDate?: number;
|
||||
isSupport?: true;
|
||||
profilePhotos?: ApiPeerPhotos;
|
||||
draftDate?: number;
|
||||
isProtected?: boolean;
|
||||
fakeType?: ApiFakeType;
|
||||
|
||||
@ -3,7 +3,6 @@ import type { ApiBotInfo } from './bots';
|
||||
import type { ApiBusinessIntro, ApiBusinessLocation, ApiBusinessWorkHours } from './business';
|
||||
import type { ApiPeerColor } from './chats';
|
||||
import type { ApiDocument, ApiPhoto } from './messages';
|
||||
import type { ApiPeerPhotos } from './misc';
|
||||
|
||||
export interface ApiUser {
|
||||
id: string;
|
||||
@ -23,14 +22,8 @@ export interface ApiUser {
|
||||
accessHash?: string;
|
||||
hasVideoAvatar?: boolean;
|
||||
avatarPhotoId?: string;
|
||||
profilePhotos?: ApiPeerPhotos;
|
||||
botPlaceholder?: string;
|
||||
canBeInvitedToGroup?: boolean;
|
||||
commonChats?: {
|
||||
ids: string[];
|
||||
maxId: string;
|
||||
isFullyLoaded: boolean;
|
||||
};
|
||||
fakeType?: ApiFakeType;
|
||||
isAttachBot?: boolean;
|
||||
emojiStatus?: ApiEmojiStatus;
|
||||
@ -82,6 +75,12 @@ export interface ApiUserStatus {
|
||||
isReadDateRestricted?: boolean;
|
||||
}
|
||||
|
||||
export interface ApiUserCommonChats {
|
||||
ids: string[];
|
||||
maxId?: string;
|
||||
isFullyLoaded: boolean;
|
||||
}
|
||||
|
||||
export interface ApiUsername {
|
||||
username: string;
|
||||
isActive?: boolean;
|
||||
|
||||
@ -3,7 +3,7 @@ import React, { memo, useEffect, useState } from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import type {
|
||||
ApiChat, ApiSticker, ApiTopic, ApiUser, ApiUserStatus,
|
||||
ApiChat, ApiPeerPhotos, ApiSticker, ApiTopic, ApiUser, ApiUserStatus,
|
||||
} from '../../api/types';
|
||||
import { MediaViewerOrigin } from '../../types';
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
import {
|
||||
selectChat,
|
||||
selectCurrentMessageList,
|
||||
selectPeerPhotos,
|
||||
selectTabState,
|
||||
selectThreadMessagesCount,
|
||||
selectUser,
|
||||
@ -54,6 +55,7 @@ type StateProps =
|
||||
topic?: ApiTopic;
|
||||
messagesCount?: number;
|
||||
emojiStatusSticker?: ApiSticker;
|
||||
profilePhotos?: ApiPeerPhotos;
|
||||
};
|
||||
|
||||
const EMOJI_STATUS_SIZE = 24;
|
||||
@ -72,6 +74,7 @@ const ProfileInfo: FC<OwnProps & StateProps> = ({
|
||||
topic,
|
||||
messagesCount,
|
||||
emojiStatusSticker,
|
||||
profilePhotos,
|
||||
peerId,
|
||||
}) => {
|
||||
const {
|
||||
@ -84,9 +87,7 @@ const ProfileInfo: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const lang = useOldLang();
|
||||
|
||||
const userProfilePhotos = user?.profilePhotos;
|
||||
const chatProfilePhotos = chat?.profilePhotos;
|
||||
const photos = userProfilePhotos?.photos || chatProfilePhotos?.photos || MEMO_EMPTY_ARRAY;
|
||||
const photos = profilePhotos?.photos || MEMO_EMPTY_ARRAY;
|
||||
const prevMediaIndex = usePreviousDeprecated(mediaIndex);
|
||||
const prevAvatarOwnerId = usePreviousDeprecated(avatarOwnerId);
|
||||
const [hasSlideAnimation, setHasSlideAnimation] = useState(true);
|
||||
@ -213,7 +214,7 @@ const ProfileInfo: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
|
||||
function renderPhotoTabs() {
|
||||
const totalPhotosLength = Math.max(photos.length, userProfilePhotos?.count || 0, chatProfilePhotos?.count || 0);
|
||||
const totalPhotosLength = Math.max(photos.length, profilePhotos?.count || 0);
|
||||
if (!photos || totalPhotosLength <= 1) {
|
||||
return undefined;
|
||||
}
|
||||
@ -293,18 +294,18 @@ const ProfileInfo: FC<OwnProps & StateProps> = ({
|
||||
>
|
||||
<div className={styles.photoWrapper}>
|
||||
{renderPhotoTabs()}
|
||||
{!forceShowSelf && userProfilePhotos?.personalPhoto && (
|
||||
{!forceShowSelf && profilePhotos?.personalPhoto && (
|
||||
<div className={buildClassName(
|
||||
styles.fallbackPhoto,
|
||||
isFirst && styles.fallbackPhotoVisible,
|
||||
)}
|
||||
>
|
||||
<div className={styles.fallbackPhotoContents}>
|
||||
{lang(userProfilePhotos.personalPhoto.isVideo ? 'UserInfo.CustomVideo' : 'UserInfo.CustomPhoto')}
|
||||
{lang(profilePhotos.personalPhoto.isVideo ? 'UserInfo.CustomVideo' : 'UserInfo.CustomPhoto')}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{forceShowSelf && userProfilePhotos?.fallbackPhoto && (
|
||||
{forceShowSelf && profilePhotos?.fallbackPhoto && (
|
||||
<div className={buildClassName(
|
||||
styles.fallbackPhoto,
|
||||
(isFirst || isLast) && styles.fallbackPhotoVisible,
|
||||
@ -313,12 +314,12 @@ const ProfileInfo: FC<OwnProps & StateProps> = ({
|
||||
<div className={styles.fallbackPhotoContents} onClick={handleSelectFallbackPhoto}>
|
||||
{!isLast && (
|
||||
<Avatar
|
||||
photo={userProfilePhotos.fallbackPhoto}
|
||||
photo={profilePhotos.fallbackPhoto}
|
||||
className={styles.fallbackPhotoAvatar}
|
||||
size="mini"
|
||||
/>
|
||||
)}
|
||||
{lang(userProfilePhotos.fallbackPhoto.isVideo ? 'UserInfo.PublicVideo' : 'UserInfo.PublicPhoto')}
|
||||
{lang(profilePhotos.fallbackPhoto.isVideo ? 'UserInfo.PublicVideo' : 'UserInfo.PublicPhoto')}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -368,6 +369,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const user = selectUser(global, peerId);
|
||||
const userStatus = selectUserStatus(global, peerId);
|
||||
const chat = selectChat(global, peerId);
|
||||
const profilePhotos = selectPeerPhotos(global, peerId);
|
||||
const { mediaIndex, chatId: avatarOwnerId } = selectTabState(global).mediaViewer;
|
||||
const isForum = chat?.isForum;
|
||||
const { threadId: currentTopicId } = selectCurrentMessageList(global) || {};
|
||||
@ -383,6 +385,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
mediaIndex,
|
||||
avatarOwnerId,
|
||||
emojiStatusSticker,
|
||||
profilePhotos,
|
||||
...(topic && {
|
||||
topic,
|
||||
messagesCount: selectThreadMessagesCount(global, peerId, currentTopicId!),
|
||||
|
||||
@ -6,7 +6,11 @@ import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import type {
|
||||
ApiChat,
|
||||
ApiMessage, ApiPeer, ApiPhoto, ApiSponsoredMessage,
|
||||
ApiMessage,
|
||||
ApiPeer,
|
||||
ApiPeerPhotos,
|
||||
ApiPhoto,
|
||||
ApiSponsoredMessage,
|
||||
} from '../../api/types';
|
||||
import { type MediaViewerMedia, MediaViewerOrigin, type ThreadId } from '../../types';
|
||||
|
||||
@ -25,6 +29,7 @@ import {
|
||||
selectListedIds,
|
||||
selectOutlyingListByMessageId,
|
||||
selectPeer,
|
||||
selectPeerPhotos,
|
||||
selectPerformanceSettingsValue,
|
||||
selectScheduledMessage, selectSponsoredMessage,
|
||||
selectTabState,
|
||||
@ -69,6 +74,7 @@ type StateProps = {
|
||||
origin?: MediaViewerOrigin;
|
||||
avatar?: ApiPhoto;
|
||||
avatarOwner?: ApiPeer;
|
||||
profilePhotos?: ApiPeerPhotos;
|
||||
chatMessages?: Record<number, ApiMessage>;
|
||||
sponsoredMessage?: ApiSponsoredMessage;
|
||||
standaloneMedia?: MediaViewerMedia[];
|
||||
@ -95,6 +101,7 @@ const MediaViewer = ({
|
||||
origin,
|
||||
avatar,
|
||||
avatarOwner,
|
||||
profilePhotos,
|
||||
chatMessages,
|
||||
sponsoredMessage,
|
||||
standaloneMedia,
|
||||
@ -132,7 +139,7 @@ const MediaViewer = ({
|
||||
const [isReportModalOpen, openReportModal, closeReportModal] = useFlag();
|
||||
|
||||
const currentItem = getMediaViewerItem({
|
||||
message, avatarOwner, standaloneMedia, mediaIndex, sponsoredMessage,
|
||||
message, avatarOwner, standaloneMedia, profilePhotos, mediaIndex, sponsoredMessage,
|
||||
});
|
||||
const { media, isSingle } = getViewableMedia(currentItem) || {};
|
||||
|
||||
@ -275,7 +282,7 @@ const MediaViewer = ({
|
||||
if (!item || isLoadingMoreMedia) return;
|
||||
|
||||
if (item.type === 'avatar') {
|
||||
const isNearEnd = item.mediaIndex >= item.avatarOwner.profilePhotos!.photos.length - AVATAR_LOAD_TRIGGER;
|
||||
const isNearEnd = item.mediaIndex >= item.profilePhotos.photos.length - AVATAR_LOAD_TRIGGER;
|
||||
if (!isNearEnd) return;
|
||||
loadMoreProfilePhotos({ peerId: item.avatarOwner.id });
|
||||
}
|
||||
@ -299,10 +306,15 @@ const MediaViewer = ({
|
||||
}
|
||||
|
||||
if (from.type === 'avatar') {
|
||||
const { avatarOwner: fromAvatarOwner, mediaIndex: fromMediaIndex } = from;
|
||||
const { avatarOwner: fromAvatarOwner, profilePhotos: fromProfilePhotos, mediaIndex: fromMediaIndex } = from;
|
||||
const nextIndex = fromMediaIndex + direction;
|
||||
if (nextIndex >= 0 && fromAvatarOwner.profilePhotos && nextIndex < fromAvatarOwner.profilePhotos.photos.length) {
|
||||
return { type: 'avatar', avatarOwner: fromAvatarOwner, mediaIndex: nextIndex };
|
||||
if (nextIndex >= 0 && fromProfilePhotos && nextIndex < fromProfilePhotos.photos.length) {
|
||||
return {
|
||||
type: 'avatar',
|
||||
avatarOwner: fromAvatarOwner,
|
||||
profilePhotos: fromProfilePhotos,
|
||||
mediaIndex: nextIndex,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@ -367,7 +379,7 @@ const MediaViewer = ({
|
||||
});
|
||||
|
||||
const handleBeforeDelete = useLastCallback(() => {
|
||||
const mediaCount = avatarOwner?.profilePhotos?.photos.length
|
||||
const mediaCount = profilePhotos?.photos.length
|
||||
|| standaloneMedia?.length || messageMediaIds?.length || 0;
|
||||
if (mediaCount <= 1 || !currentItem) {
|
||||
handleClose();
|
||||
@ -489,9 +501,10 @@ export default memo(withGlobal(
|
||||
canUpdateMedia = isUserId(peer.id) ? peer.id === currentUserId : isChatAdmin(peer as ApiChat);
|
||||
}
|
||||
|
||||
const profilePhotos = peer?.profilePhotos;
|
||||
const profilePhotos = selectPeerPhotos(global, chatId!);
|
||||
|
||||
return {
|
||||
profilePhotos,
|
||||
avatar: profilePhotos?.photos[mediaIndex!],
|
||||
avatarOwner: peer,
|
||||
isLoadingMoreMedia: profilePhotos?.isLoading,
|
||||
|
||||
@ -128,8 +128,8 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const handleUpdate = useLastCallback(() => {
|
||||
if (item?.type !== 'avatar') return;
|
||||
const { avatarOwner, mediaIndex } = item;
|
||||
const avatarPhoto = avatarOwner.profilePhotos?.photos[mediaIndex]!;
|
||||
const { avatarOwner, profilePhotos, mediaIndex } = item;
|
||||
const avatarPhoto = profilePhotos?.photos[mediaIndex]!;
|
||||
if (isUserId(avatarOwner.id)) {
|
||||
updateProfilePhoto({ photo: avatarPhoto });
|
||||
} else {
|
||||
@ -170,7 +170,7 @@ const MediaViewerActions: FC<OwnProps & StateProps> = ({
|
||||
onClose={closeDeleteModal}
|
||||
onConfirm={onBeforeDelete}
|
||||
profileId={item.avatarOwner.id}
|
||||
photo={item.avatarOwner.profilePhotos!.photos[item.mediaIndex!]}
|
||||
photo={item.profilePhotos.photos[item.mediaIndex!]}
|
||||
/>
|
||||
) : undefined;
|
||||
}
|
||||
@ -390,7 +390,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
const message = item?.type === 'message' ? item.message : undefined;
|
||||
const avatarOwner = item?.type === 'avatar' ? item.avatarOwner : undefined;
|
||||
const avatarPhoto = avatarOwner?.profilePhotos?.photos[item!.mediaIndex!];
|
||||
const avatarPhoto = item?.type === 'avatar' && item.profilePhotos.photos[item.mediaIndex];
|
||||
|
||||
const currentMessageList = selectCurrentMessageList(global);
|
||||
const { threadId } = selectCurrentMessageList(global) || {};
|
||||
|
||||
@ -68,14 +68,15 @@ const SenderInfo: FC<OwnProps & StateProps> = ({
|
||||
if (!item || item.type === 'standalone') return undefined;
|
||||
|
||||
const avatarOwner = item.type === 'avatar' ? item.avatarOwner : undefined;
|
||||
const avatar = avatarOwner?.profilePhotos?.photos[item.mediaIndex!];
|
||||
const isFallbackAvatar = avatar?.id === avatarOwner?.profilePhotos?.fallbackPhoto?.id;
|
||||
const profilePhotos = item.type === 'avatar' ? item.profilePhotos : undefined;
|
||||
const avatar = profilePhotos?.photos[item.mediaIndex!];
|
||||
const isFallbackAvatar = avatar?.id === profilePhotos?.fallbackPhoto?.id;
|
||||
const date = item.type === 'message' ? item.message.date : avatar?.date;
|
||||
if (!date) return undefined;
|
||||
|
||||
const formattedDate = formatMediaDateTime(lang, date * 1000, true);
|
||||
const count = avatarOwner?.profilePhotos?.count
|
||||
&& (avatarOwner.profilePhotos.count + (avatarOwner?.profilePhotos?.fallbackPhoto ? 1 : 0));
|
||||
const count = profilePhotos?.count
|
||||
&& (profilePhotos.count + (profilePhotos?.fallbackPhoto ? 1 : 0));
|
||||
const countText = count && lang('Of', [item.mediaIndex! + 1, count]);
|
||||
|
||||
const parts: string[] = [];
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import type { ApiMessage, ApiPeer, ApiSponsoredMessage } from '../../../api/types';
|
||||
import type {
|
||||
ApiMessage, ApiPeer, ApiPeerPhotos, ApiSponsoredMessage,
|
||||
} from '../../../api/types';
|
||||
import type { MediaViewerMedia } from '../../../types';
|
||||
|
||||
import { getMessageContent, isDocumentPhoto, isDocumentVideo } from '../../../global/helpers';
|
||||
@ -10,6 +12,7 @@ export type MediaViewerItem = {
|
||||
} | {
|
||||
type: 'avatar';
|
||||
avatarOwner: ApiPeer;
|
||||
profilePhotos: ApiPeerPhotos;
|
||||
mediaIndex: number;
|
||||
} | {
|
||||
type: 'standalone';
|
||||
@ -27,18 +30,20 @@ type ViewableMedia = {
|
||||
};
|
||||
|
||||
export function getMediaViewerItem({
|
||||
message, avatarOwner, standaloneMedia, mediaIndex, sponsoredMessage,
|
||||
message, avatarOwner, profilePhotos, standaloneMedia, mediaIndex, sponsoredMessage,
|
||||
}: {
|
||||
message?: ApiMessage;
|
||||
avatarOwner?: ApiPeer;
|
||||
profilePhotos?: ApiPeerPhotos;
|
||||
standaloneMedia?: MediaViewerMedia[];
|
||||
sponsoredMessage?: ApiSponsoredMessage;
|
||||
mediaIndex?: number;
|
||||
}): MediaViewerItem | undefined {
|
||||
if (avatarOwner) {
|
||||
if (avatarOwner && profilePhotos) {
|
||||
return {
|
||||
type: 'avatar',
|
||||
avatarOwner,
|
||||
profilePhotos,
|
||||
mediaIndex: mediaIndex!,
|
||||
};
|
||||
}
|
||||
@ -81,7 +86,7 @@ export default function getViewableMedia(params?: MediaViewerItem): ViewableMedi
|
||||
}
|
||||
|
||||
if (params.type === 'avatar') {
|
||||
const avatar = params.avatarOwner.profilePhotos?.photos[params.mediaIndex];
|
||||
const avatar = params.profilePhotos?.photos[params.mediaIndex];
|
||||
if (avatar) {
|
||||
return {
|
||||
media: avatar,
|
||||
|
||||
@ -37,7 +37,6 @@ import {
|
||||
isChatChannel,
|
||||
isChatGroup,
|
||||
isUserBot,
|
||||
isUserId,
|
||||
isUserRightBanned,
|
||||
} from '../../global/helpers';
|
||||
import {
|
||||
@ -48,12 +47,12 @@ import {
|
||||
selectCurrentSharedMediaSearch,
|
||||
selectIsCurrentUserPremium,
|
||||
selectIsRightColumnShown,
|
||||
selectPeerFullInfo,
|
||||
selectPeerStories,
|
||||
selectSimilarChannelIds,
|
||||
selectTabState,
|
||||
selectTheme,
|
||||
selectUser,
|
||||
selectUserCommonChats,
|
||||
selectUserFullInfo,
|
||||
} from '../../global/selectors';
|
||||
import { selectPremiumLimit } from '../../global/selectors/limits';
|
||||
@ -110,7 +109,6 @@ type StateProps = {
|
||||
theme: ISettings['theme'];
|
||||
isChannel?: boolean;
|
||||
currentUserId?: string;
|
||||
resolvedUserId?: string;
|
||||
messagesById?: Record<number, ApiMessage>;
|
||||
foundIds?: number[];
|
||||
mediaSearchType?: SharedMediaType;
|
||||
@ -166,10 +164,8 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
chatId,
|
||||
threadId,
|
||||
profileState,
|
||||
onProfileStateChange,
|
||||
theme,
|
||||
isChannel,
|
||||
resolvedUserId,
|
||||
currentUserId,
|
||||
messagesById,
|
||||
foundIds,
|
||||
@ -205,6 +201,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
isSavedDialog,
|
||||
forceScrollProfileTab,
|
||||
isSynced,
|
||||
onProfileStateChange,
|
||||
}) => {
|
||||
const {
|
||||
setSharedMediaSearchType,
|
||||
@ -230,7 +227,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
const lang = useOldLang();
|
||||
const [deletingUserId, setDeletingUserId] = useState<string | undefined>();
|
||||
|
||||
const profileId = isSavedDialog ? String(threadId) : (resolvedUserId || chatId);
|
||||
const profileId = isSavedDialog ? String(threadId) : chatId;
|
||||
const isSavedMessages = profileId === currentUserId && !isSavedDialog;
|
||||
|
||||
const tabs = useMemo(() => ([
|
||||
@ -303,6 +300,9 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const renderingActiveTab = activeTab > tabs.length - 1 ? tabs.length - 1 : activeTab;
|
||||
const tabType = tabs[renderingActiveTab].type as ProfileTabType;
|
||||
const handleLoadCommonChats = useCallback(() => {
|
||||
loadCommonChats({ userId: chatId });
|
||||
}, [chatId]);
|
||||
const handleLoadPeerStories = useCallback(({ offsetId }: { offsetId: number }) => {
|
||||
loadPeerProfileStories({ peerId: chatId, offsetId });
|
||||
}, [chatId]);
|
||||
@ -312,7 +312,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
|
||||
const [resultType, viewportIds, getMore, noProfileInfo] = useProfileViewportIds(
|
||||
loadMoreMembers,
|
||||
loadCommonChats,
|
||||
handleLoadCommonChats,
|
||||
searchSharedMediaMessages,
|
||||
handleLoadPeerStories,
|
||||
handleLoadStoriesArchive,
|
||||
@ -746,9 +746,12 @@ export default memo(withGlobal<OwnProps>(
|
||||
(global, {
|
||||
chatId, threadId, isMobile,
|
||||
}): StateProps => {
|
||||
const user = selectUser(global, chatId);
|
||||
const chat = selectChat(global, chatId);
|
||||
const chatFullInfo = selectChatFullInfo(global, chatId);
|
||||
const userFullInfo = selectUserFullInfo(global, chatId);
|
||||
const messagesById = selectChatMessages(global, chatId);
|
||||
|
||||
const { currentType: mediaSearchType, resultsByType } = selectCurrentSharedMediaSearch(global) || {};
|
||||
const { foundIds } = (resultsByType && mediaSearchType && resultsByType[mediaSearchType]) || {};
|
||||
|
||||
@ -774,19 +777,13 @@ export default memo(withGlobal<OwnProps>(
|
||||
const { similarChannelIds } = selectSimilarChannelIds(global, chatId) || {};
|
||||
const isCurrentUserPremium = selectIsCurrentUserPremium(global);
|
||||
|
||||
let hasCommonChatsTab;
|
||||
let resolvedUserId;
|
||||
let user;
|
||||
if (isUserId(chatId)) {
|
||||
resolvedUserId = chatId;
|
||||
user = selectUser(global, resolvedUserId);
|
||||
hasCommonChatsTab = user && !user.isSelf && !isUserBot(user) && !isSavedDialog;
|
||||
}
|
||||
|
||||
const peer = user || chat;
|
||||
const peerFullInfo = selectPeerFullInfo(global, chatId);
|
||||
const peerFullInfo = userFullInfo || chatFullInfo;
|
||||
|
||||
const hasCommonChatsTab = user && !user.isSelf && !isUserBot(user) && !isSavedDialog
|
||||
&& Boolean(userFullInfo?.commonChatsCount);
|
||||
const commonChats = selectUserCommonChats(global, chatId);
|
||||
|
||||
const userFullInfo = selectUserFullInfo(global, chatId);
|
||||
const hasPreviewMediaTab = userFullInfo?.botInfo?.hasPreviewMedia;
|
||||
const botPreviewMedia = global.users.previewMediaByBotId[chatId];
|
||||
|
||||
@ -801,7 +798,6 @@ export default memo(withGlobal<OwnProps>(
|
||||
return {
|
||||
theme: selectTheme(global),
|
||||
isChannel,
|
||||
resolvedUserId,
|
||||
messagesById,
|
||||
foundIds,
|
||||
mediaSearchType,
|
||||
@ -835,7 +831,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
isSynced: global.isSynced,
|
||||
limitSimilarChannels: selectPremiumLimit(global, 'recommendedChannels'),
|
||||
...(hasMembersTab && members && { members, adminMembersById }),
|
||||
...(hasCommonChatsTab && user && { commonChatIds: user.commonChats?.ids }),
|
||||
...(hasCommonChatsTab && user && { commonChatIds: commonChats?.ids }),
|
||||
};
|
||||
},
|
||||
)(Profile));
|
||||
|
||||
@ -86,7 +86,6 @@ export const PINNED_MESSAGES_LIMIT = 50;
|
||||
export const BLOCKED_LIST_LIMIT = 100;
|
||||
export const PROFILE_SENSITIVE_AREA = 500;
|
||||
export const TOPIC_LIST_SENSITIVE_AREA = 600;
|
||||
export const COMMON_CHATS_LIMIT = 100;
|
||||
export const GROUP_CALL_PARTICIPANTS_LIMIT = 100;
|
||||
export const STORY_LIST_LIMIT = 100;
|
||||
export const API_GENERAL_ID_LIMIT = 100;
|
||||
|
||||
@ -23,6 +23,7 @@ import {
|
||||
updatePeerPhotos,
|
||||
updatePeerPhotosIsLoading,
|
||||
updateUser,
|
||||
updateUserCommonChats,
|
||||
updateUserFullInfo,
|
||||
updateUsers,
|
||||
updateUserSearch,
|
||||
@ -31,10 +32,11 @@ import {
|
||||
import {
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectCurrentMessageList,
|
||||
selectPeer,
|
||||
selectPeerPhotos,
|
||||
selectTabState,
|
||||
selectUser,
|
||||
selectUserCommonChats,
|
||||
selectUserFullInfo,
|
||||
} from '../../selectors';
|
||||
|
||||
@ -56,6 +58,7 @@ addActionHandler('loadFullUser', async (global, actions, payload): Promise<void>
|
||||
global = getGlobal();
|
||||
const fullInfo = selectUserFullInfo(global, userId);
|
||||
const { user: newUser, fullInfo: newFullInfo } = result;
|
||||
const profilePhotos = selectPeerPhotos(global, userId);
|
||||
const hasChangedAvatar = user.avatarPhotoId !== newUser.avatarPhotoId;
|
||||
const hasChangedProfilePhoto = fullInfo?.profilePhoto?.id !== newFullInfo?.profilePhoto?.id;
|
||||
const hasChangedFallbackPhoto = fullInfo?.fallbackPhoto?.id !== newFullInfo?.fallbackPhoto?.id;
|
||||
@ -71,7 +74,7 @@ addActionHandler('loadFullUser', async (global, actions, payload): Promise<void>
|
||||
global = updateChats(global, buildCollectionByKey(result.chats, 'id'));
|
||||
|
||||
setGlobal(global);
|
||||
if (withPhotos || (user.profilePhotos?.count && hasChangedPhoto)) {
|
||||
if (withPhotos || (profilePhotos?.count && hasChangedPhoto)) {
|
||||
actions.loadMoreProfilePhotos({ peerId: userId, shouldInvalidateCache: true });
|
||||
}
|
||||
});
|
||||
@ -156,28 +159,27 @@ addActionHandler('loadCurrentUser', (): ActionReturnType => {
|
||||
});
|
||||
|
||||
addActionHandler('loadCommonChats', async (global, actions, payload): Promise<void> => {
|
||||
const { tabId = getCurrentTabId() } = payload || {};
|
||||
const { chatId } = selectCurrentMessageList(global, tabId) || {};
|
||||
const user = chatId ? selectUser(global, chatId) : undefined;
|
||||
if (!user || isUserBot(user) || user.commonChats?.isFullyLoaded) {
|
||||
const { userId } = payload;
|
||||
const user = selectUser(global, userId);
|
||||
const commonChats = selectUserCommonChats(global, userId);
|
||||
if (!user || isUserBot(user) || commonChats?.isFullyLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
const maxId = user.commonChats?.maxId;
|
||||
const result = await callApi('fetchCommonChats', user.id, user.accessHash!, maxId);
|
||||
const result = await callApi('fetchCommonChats', user, commonChats?.maxId);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { chatIds, isFullyLoaded } = result;
|
||||
const { chatIds, count } = result;
|
||||
|
||||
const ids = unique((commonChats?.ids || []).concat(chatIds));
|
||||
|
||||
global = getGlobal();
|
||||
global = updateUser(global, user.id, {
|
||||
commonChats: {
|
||||
maxId: chatIds.length ? chatIds[chatIds.length - 1] : '0',
|
||||
ids: unique((user.commonChats?.ids || []).concat(chatIds)),
|
||||
isFullyLoaded,
|
||||
},
|
||||
global = updateUserCommonChats(global, user.id, {
|
||||
maxId: chatIds.length ? chatIds[chatIds.length - 1] : undefined,
|
||||
ids,
|
||||
isFullyLoaded: ids.length >= count,
|
||||
});
|
||||
|
||||
setGlobal(global);
|
||||
@ -258,11 +260,12 @@ addActionHandler('loadMoreProfilePhotos', async (global, actions, payload): Prom
|
||||
const user = isPrivate ? selectUser(global, peerId) : undefined;
|
||||
const chat = !isPrivate ? selectChat(global, peerId) : undefined;
|
||||
const peer = user || chat;
|
||||
const profilePhotos = selectPeerPhotos(global, peerId);
|
||||
if (!peer?.avatarPhotoId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (peer.profilePhotos && !shouldInvalidateCache && (isPreload || !peer.profilePhotos.nextOffset)) return;
|
||||
if (profilePhotos && !shouldInvalidateCache && (isPreload || !profilePhotos.nextOffset)) return;
|
||||
|
||||
global = updatePeerPhotosIsLoading(global, peerId, true);
|
||||
setGlobal(global);
|
||||
@ -292,7 +295,7 @@ addActionHandler('loadMoreProfilePhotos', async (global, actions, payload): Prom
|
||||
const peerFullInfo = userFullInfo || chatFullInfo;
|
||||
if (!peerFullInfo) return;
|
||||
|
||||
const offset = peer.profilePhotos?.nextOffset;
|
||||
const offset = profilePhotos?.nextOffset;
|
||||
const limit = !offset || isPreload || shouldInvalidateCache ? PROFILE_PHOTOS_FIRST_LOAD_LIMIT : undefined;
|
||||
|
||||
const result = await callApi('fetchProfilePhotos', {
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
deletePeerPhoto,
|
||||
leaveChat,
|
||||
removeUnreadMentions,
|
||||
replacePeerPhotos,
|
||||
replaceThreadParam,
|
||||
updateChat,
|
||||
updateChatFullInfo,
|
||||
@ -548,8 +549,8 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
if (!photoId || peer.avatarPhotoId === photoId) {
|
||||
global = updateChat(global, peerId, {
|
||||
avatarPhotoId: undefined,
|
||||
profilePhotos: undefined,
|
||||
});
|
||||
global = replacePeerPhotos(global, peerId, undefined);
|
||||
} else {
|
||||
global = deletePeerPhoto(global, peerId, photoId);
|
||||
}
|
||||
|
||||
@ -245,6 +245,9 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
|
||||
if (!cached.topBotApps) {
|
||||
cached.topBotApps = initialState.topBotApps;
|
||||
}
|
||||
if (!cached.users.commonChatsById) {
|
||||
cached.users.commonChatsById = initialState.users.commonChatsById;
|
||||
}
|
||||
}
|
||||
|
||||
function updateCache(force?: boolean) {
|
||||
@ -390,10 +393,10 @@ function reduceUsers<T extends GlobalState>(global: T): GlobalState['users'] {
|
||||
]).slice(0, GLOBAL_STATE_CACHE_USER_LIST_LIMIT);
|
||||
|
||||
return {
|
||||
...INITIAL_GLOBAL_STATE.users,
|
||||
byId: pickTruthy(byId, idsToSave),
|
||||
statusesById: pickTruthy(statusesById, idsToSave),
|
||||
fullInfoById: pickTruthy(fullInfoById, idsToSave),
|
||||
previewMediaByBotId: {},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -98,6 +98,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
||||
statusesById: {},
|
||||
fullInfoById: {},
|
||||
previewMediaByBotId: {},
|
||||
commonChatsById: {},
|
||||
},
|
||||
|
||||
chats: {
|
||||
@ -298,6 +299,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
||||
isHidden: false,
|
||||
},
|
||||
|
||||
profilePhotosById: {},
|
||||
monetizationInfo: {},
|
||||
};
|
||||
|
||||
|
||||
@ -12,5 +12,5 @@ export * from './payments';
|
||||
export * from './statistics';
|
||||
export * from './stories';
|
||||
export * from './translations';
|
||||
export * from './peers';
|
||||
export * from './password';
|
||||
export * from './general';
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
import type {
|
||||
ApiChat, ApiChatFullInfo, ApiPhoto, ApiUser, ApiUserFullInfo,
|
||||
ApiChat, ApiChatFullInfo, ApiPeerPhotos, ApiPhoto, ApiUser, ApiUserFullInfo,
|
||||
} from '../../api/types';
|
||||
import type { GlobalState } from '../types';
|
||||
|
||||
import { uniqueByField } from '../../util/iteratees';
|
||||
import { omit, uniqueByField } from '../../util/iteratees';
|
||||
import { isChatChannel, isUserId } from '../helpers';
|
||||
import { selectChatFullInfo, selectPeer, selectUserFullInfo } from '../selectors';
|
||||
import {
|
||||
selectChatFullInfo,
|
||||
selectPeer,
|
||||
selectPeerPhotos,
|
||||
selectUserFullInfo,
|
||||
} from '../selectors';
|
||||
import { updateChat, updateChatFullInfo } from './chats';
|
||||
import { updateUser, updateUserFullInfo } from './users';
|
||||
|
||||
@ -38,19 +43,38 @@ export function updatePeerPhotosIsLoading<T extends GlobalState>(
|
||||
peerId: string,
|
||||
isLoading: boolean,
|
||||
) {
|
||||
const peer = selectPeer(global, peerId);
|
||||
if (!peer || !peer.profilePhotos) {
|
||||
const profilePhotos = selectPeerPhotos(global, peerId);
|
||||
if (!profilePhotos) {
|
||||
return global;
|
||||
}
|
||||
|
||||
return updatePeer(global, peerId, {
|
||||
profilePhotos: {
|
||||
...peer.profilePhotos,
|
||||
isLoading,
|
||||
},
|
||||
return replacePeerPhotos(global, peerId, {
|
||||
...profilePhotos,
|
||||
isLoading,
|
||||
});
|
||||
}
|
||||
|
||||
export function replacePeerPhotos<T extends GlobalState>(
|
||||
global: T,
|
||||
peerId: string,
|
||||
value?: ApiPeerPhotos,
|
||||
) {
|
||||
if (!value) {
|
||||
return {
|
||||
...global,
|
||||
profilePhotosById: omit(global.profilePhotosById, [peerId]),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...global,
|
||||
profilePhotosById: {
|
||||
...global.profilePhotosById,
|
||||
[peerId]: value,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function updatePeerPhotos<T extends GlobalState>(
|
||||
global: T,
|
||||
peerId: string,
|
||||
@ -62,15 +86,12 @@ export function updatePeerPhotos<T extends GlobalState>(
|
||||
shouldInvalidateCache?: boolean;
|
||||
},
|
||||
) {
|
||||
const peer = selectPeer(global, peerId);
|
||||
if (!peer) {
|
||||
return global;
|
||||
}
|
||||
const profilePhotos = selectPeerPhotos(global, peerId);
|
||||
|
||||
const {
|
||||
newPhotos, count, nextOffset, fullInfo, shouldInvalidateCache,
|
||||
} = update;
|
||||
const currentPhotos = peer.profilePhotos;
|
||||
const currentPhotos = profilePhotos;
|
||||
const profilePhoto = fullInfo.profilePhoto;
|
||||
const fallbackPhoto = 'fallbackPhoto' in fullInfo ? fullInfo.fallbackPhoto : undefined;
|
||||
const personalPhoto = 'personalPhoto' in fullInfo ? fullInfo.personalPhoto : undefined;
|
||||
@ -89,15 +110,13 @@ export function updatePeerPhotos<T extends GlobalState>(
|
||||
newPhotos.push(fallbackPhoto);
|
||||
}
|
||||
|
||||
return updatePeer(global, peerId, {
|
||||
profilePhotos: {
|
||||
fallbackPhoto,
|
||||
personalPhoto,
|
||||
photos: newPhotos,
|
||||
count,
|
||||
nextOffset,
|
||||
isLoading: false,
|
||||
},
|
||||
return replacePeerPhotos(global, peerId, {
|
||||
fallbackPhoto,
|
||||
personalPhoto,
|
||||
photos: newPhotos,
|
||||
count,
|
||||
nextOffset,
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -105,15 +124,13 @@ export function updatePeerPhotos<T extends GlobalState>(
|
||||
const currentPhotoArray = hasFallbackPhoto ? currentPhotos.photos.slice(0, -1) : currentPhotos.photos;
|
||||
|
||||
const photos = uniqueByField([...currentPhotoArray, ...newPhotos, fallbackPhoto].filter(Boolean), 'id');
|
||||
return updatePeer(global, peerId, {
|
||||
profilePhotos: {
|
||||
fallbackPhoto,
|
||||
personalPhoto,
|
||||
photos,
|
||||
count,
|
||||
nextOffset,
|
||||
isLoading: false,
|
||||
},
|
||||
return replacePeerPhotos(global, peerId, {
|
||||
fallbackPhoto,
|
||||
personalPhoto,
|
||||
photos,
|
||||
count,
|
||||
nextOffset,
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -124,7 +141,8 @@ export function deletePeerPhoto<T extends GlobalState>(
|
||||
isFromActionMessage?: boolean,
|
||||
) {
|
||||
const peer = selectPeer(global, peerId);
|
||||
if (!peer || !peer.profilePhotos) {
|
||||
const profilePhotos = selectPeerPhotos(global, peerId);
|
||||
if (!peer || !profilePhotos) {
|
||||
return global;
|
||||
}
|
||||
const isChannel = 'title' in peer && isChatChannel(peer);
|
||||
@ -133,7 +151,7 @@ export function deletePeerPhoto<T extends GlobalState>(
|
||||
const chatFullInfo = selectChatFullInfo(global, peerId);
|
||||
|
||||
const isAvatar = peer.avatarPhotoId === photoId && (!isChannel || isFromActionMessage);
|
||||
const nextAvatarPhoto = isAvatar ? peer.profilePhotos.photos[1] : undefined;
|
||||
const nextAvatarPhoto = isAvatar ? profilePhotos.photos[1] : undefined;
|
||||
|
||||
if (userFullInfo) {
|
||||
const newFallbackPhoto = userFullInfo.fallbackPhoto?.id === photoId ? undefined : userFullInfo.fallbackPhoto;
|
||||
@ -156,13 +174,17 @@ export function deletePeerPhoto<T extends GlobalState>(
|
||||
const avatarPhotoId = isAvatar ? nextAvatarPhoto?.id : peer.avatarPhotoId;
|
||||
const shouldKeepInPhotos = isAvatar && 'title' in peer && isChatChannel(peer);
|
||||
const photos = shouldKeepInPhotos
|
||||
? peer.profilePhotos.photos.filter((photo) => photo.id !== photoId) : peer.profilePhotos.photos.slice();
|
||||
return updatePeer(global, peerId, {
|
||||
? profilePhotos.photos.filter((photo) => photo.id !== photoId) : profilePhotos.photos.slice();
|
||||
|
||||
global = updatePeer(global, peerId, {
|
||||
avatarPhotoId,
|
||||
profilePhotos: avatarPhotoId ? {
|
||||
...peer.profilePhotos,
|
||||
photos,
|
||||
count: peer.profilePhotos.count - 1,
|
||||
} : undefined,
|
||||
});
|
||||
|
||||
global = replacePeerPhotos(global, peerId, avatarPhotoId ? {
|
||||
...profilePhotos,
|
||||
photos,
|
||||
count: profilePhotos.count - 1,
|
||||
} : undefined);
|
||||
|
||||
return global;
|
||||
}
|
||||
@ -19,7 +19,7 @@ import {
|
||||
selectIsChatWithSelf,
|
||||
selectPeer, selectPeerStories, selectPeerStory, selectTabState, selectUser,
|
||||
} from '../selectors';
|
||||
import { updatePeer } from './general';
|
||||
import { updatePeer } from './peers';
|
||||
import { updateTabState } from './tabs';
|
||||
|
||||
export function addStories<T extends GlobalState>(global: T, newStoriesByPeerId: Record<string, ApiPeerStories>): T {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type {
|
||||
ApiMissingInvitedUser, ApiUser, ApiUserFullInfo, ApiUserStatus,
|
||||
ApiMissingInvitedUser, ApiUser, ApiUserCommonChats, ApiUserFullInfo, ApiUserStatus,
|
||||
} from '../../api/types';
|
||||
import type { GlobalState, TabArgs, TabState } from '../types';
|
||||
|
||||
@ -240,6 +240,21 @@ export function updateUserFullInfo<T extends GlobalState>(
|
||||
};
|
||||
}
|
||||
|
||||
export function updateUserCommonChats<T extends GlobalState>(
|
||||
global: T, userId: string, commonChats: ApiUserCommonChats,
|
||||
): T {
|
||||
return {
|
||||
...global,
|
||||
users: {
|
||||
...global.users,
|
||||
commonChatsById: {
|
||||
...global.users.commonChatsById,
|
||||
[userId]: commonChats,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// @optimization Allows to avoid redundant updates which cause a lot of renders
|
||||
export function addUserStatuses<T extends GlobalState>(global: T, newById: Record<string, ApiUserStatus>): T {
|
||||
const { statusesById } = global.users;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type {
|
||||
ApiChat, ApiChatFullInfo, ApiChatType, ApiPeer,
|
||||
ApiChat, ApiChatFullInfo, ApiChatType,
|
||||
} from '../../api/types';
|
||||
import type { ChatListType, GlobalState, TabArgs } from '../types';
|
||||
import { MAIN_THREAD_ID } from '../../api/types';
|
||||
@ -24,10 +24,6 @@ import {
|
||||
selectBot, selectIsCurrentUserPremium, selectUser, selectUserFullInfo,
|
||||
} from './users';
|
||||
|
||||
export function selectPeer<T extends GlobalState>(global: T, peerId: string): ApiPeer | undefined {
|
||||
return selectUser(global, peerId) || selectChat(global, peerId);
|
||||
}
|
||||
|
||||
export function selectChat<T extends GlobalState>(global: T, chatId: string): ApiChat | undefined {
|
||||
return global.chats.byId[chatId];
|
||||
}
|
||||
|
||||
@ -11,3 +11,4 @@ export * from './settings';
|
||||
export * from './statistics';
|
||||
export * from './stories';
|
||||
export * from './tabs';
|
||||
export * from './peers';
|
||||
|
||||
@ -64,9 +64,9 @@ import {
|
||||
selectChatFullInfo,
|
||||
selectChatLastMessageId,
|
||||
selectIsChatWithSelf,
|
||||
selectPeer,
|
||||
selectRequestedChatTranslationLanguage,
|
||||
} from './chats';
|
||||
import { selectPeer } from './peers';
|
||||
import { selectPeerStory } from './stories';
|
||||
import { selectIsStickerFavorite } from './symbols';
|
||||
import { selectTabState } from './tabs';
|
||||
|
||||
13
src/global/selectors/peers.ts
Normal file
13
src/global/selectors/peers.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import type { ApiPeer } from '../../api/types';
|
||||
import type { GlobalState } from '../types';
|
||||
|
||||
import { selectChat } from './chats';
|
||||
import { selectUser } from './users';
|
||||
|
||||
export function selectPeer<T extends GlobalState>(global: T, peerId: string): ApiPeer | undefined {
|
||||
return selectUser(global, peerId) || selectChat(global, peerId);
|
||||
}
|
||||
|
||||
export function selectPeerPhotos<T extends GlobalState>(global: T, peerId: string) {
|
||||
return global.profilePhotosById[peerId];
|
||||
}
|
||||
@ -2,7 +2,7 @@ import type { ApiPeerStories, ApiTypeStory } from '../../api/types';
|
||||
import type { GlobalState, TabArgs } from '../types';
|
||||
|
||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||
import { selectPeer } from './chats';
|
||||
import { selectPeer } from './peers';
|
||||
import { selectTabState } from './tabs';
|
||||
|
||||
export function selectCurrentViewedStory<T extends GlobalState>(
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type {
|
||||
ApiUser, ApiUserFullInfo, ApiUserStatus,
|
||||
ApiUser, ApiUserCommonChats, ApiUserFullInfo, ApiUserStatus,
|
||||
} from '../../api/types';
|
||||
import type { GlobalState } from '../types';
|
||||
|
||||
@ -17,6 +17,12 @@ export function selectUserFullInfo<T extends GlobalState>(global: T, userId: str
|
||||
return global.users.fullInfoById[userId];
|
||||
}
|
||||
|
||||
export function selectUserCommonChats<T extends GlobalState>(
|
||||
global: T, userId: string,
|
||||
): ApiUserCommonChats | undefined {
|
||||
return global.users.commonChatsById[userId];
|
||||
}
|
||||
|
||||
export function selectIsUserBlocked<T extends GlobalState>(global: T, userId: string) {
|
||||
return selectUserFullInfo(global, userId)?.isBlocked;
|
||||
}
|
||||
|
||||
@ -47,6 +47,7 @@ import type {
|
||||
ApiPaymentFormNativeParams,
|
||||
ApiPaymentSavedInfo,
|
||||
ApiPeerColors,
|
||||
ApiPeerPhotos,
|
||||
ApiPeerStories,
|
||||
ApiPhoneCall,
|
||||
ApiPhoto,
|
||||
@ -80,6 +81,7 @@ import type {
|
||||
ApiUpdateAuthorizationStateType,
|
||||
ApiUpdateConnectionStateType,
|
||||
ApiUser,
|
||||
ApiUserCommonChats,
|
||||
ApiUserFullInfo,
|
||||
ApiUserStatus,
|
||||
ApiVideo,
|
||||
@ -933,7 +935,9 @@ export type GlobalState = {
|
||||
// Obtained from GetFullUser / UserFullInfo
|
||||
fullInfoById: Record<string, ApiUserFullInfo>;
|
||||
previewMediaByBotId: Record<string, ApiBotPreviewMedia[]>;
|
||||
commonChatsById: Record<string, ApiUserCommonChats>;
|
||||
};
|
||||
profilePhotosById: Record<string, ApiPeerPhotos>;
|
||||
|
||||
chats: {
|
||||
// TODO Replace with `Partial<Record>` to properly handle missing keys
|
||||
@ -2672,7 +2676,9 @@ export interface ActionPayloads {
|
||||
deleteContact: { userId: string };
|
||||
loadUser: { userId: string };
|
||||
setUserSearchQuery: { query?: string } & WithTabId;
|
||||
loadCommonChats: WithTabId | undefined;
|
||||
loadCommonChats: {
|
||||
userId: string;
|
||||
};
|
||||
reportSpam: { chatId: string };
|
||||
loadFullUser: { userId: string; withPhotos?: boolean };
|
||||
openAddContactDialog: { userId?: string } & WithTabId;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user