Message: Show admin and owner marks (#2156)
This commit is contained in:
parent
365a021dda
commit
5c510a91a4
@ -274,10 +274,14 @@ export function buildChatMember(
|
||||
|
||||
return {
|
||||
userId,
|
||||
inviterId: 'inviterId' in member ? buildApiPeerId(member.inviterId as BigInt.BigInteger, 'user') : undefined,
|
||||
inviterId: 'inviterId' in member && member.inviterId
|
||||
? buildApiPeerId(member.inviterId as BigInt.BigInteger, 'user')
|
||||
: undefined,
|
||||
joinedDate: 'date' in member ? member.date : undefined,
|
||||
kickedByUserId: 'kickedBy' in member ? buildApiPeerId(member.kickedBy, 'user') : undefined,
|
||||
promotedByUserId: 'promotedBy' in member ? buildApiPeerId(member.promotedBy, 'user') : undefined,
|
||||
kickedByUserId: 'kickedBy' in member && member.kickedBy ? buildApiPeerId(member.kickedBy, 'user') : undefined,
|
||||
promotedByUserId: 'promotedBy' in member && member.promotedBy
|
||||
? buildApiPeerId(member.promotedBy, 'user')
|
||||
: undefined,
|
||||
bannedRights: 'bannedRights' in member ? omitVirtualClassFields(member.bannedRights) : undefined,
|
||||
adminRights: 'adminRights' in member ? omitVirtualClassFields(member.adminRights) : undefined,
|
||||
customTitle: 'rank' in member ? member.rank : undefined,
|
||||
|
||||
@ -210,7 +210,7 @@ export function buildApiMessageWithChatId(chatId: string, mtpMessage: UniversalM
|
||||
...(shouldHideKeyboardButtons && { shouldHideKeyboardButtons }),
|
||||
...(mtpMessage.viaBotId && { viaBotId: buildApiPeerId(mtpMessage.viaBotId, 'user') }),
|
||||
...(replies?.comments && { threadInfo: buildThreadInfo(replies, mtpMessage.id, chatId) }),
|
||||
...(postAuthor && { adminTitle: postAuthor }),
|
||||
...(postAuthor && { postAuthorTitle: postAuthor }),
|
||||
isProtected,
|
||||
isForwardingAllowed,
|
||||
};
|
||||
@ -399,7 +399,7 @@ function buildApiMessageForwardInfo(fwdFrom: GramJs.MessageFwdHeader, isChatWith
|
||||
fromMessageId: fwdFrom.savedFromMsgId || fwdFrom.channelPost,
|
||||
senderUserId: fromId,
|
||||
hiddenUserName: fwdFrom.fromName,
|
||||
adminTitle: fwdFrom.postAuthor,
|
||||
postAuthorTitle: fwdFrom.postAuthor,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -385,7 +385,7 @@ async function getFullChatInfo(chatId: string): Promise<FullChatData | undefined
|
||||
...(chatPhoto instanceof GramJs.Photo && { profilePhoto: buildApiPhoto(chatPhoto) }),
|
||||
about,
|
||||
members,
|
||||
adminMembers,
|
||||
adminMembersById: adminMembers ? buildCollectionByKey(adminMembers, 'userId') : undefined,
|
||||
canViewMembers: true,
|
||||
botCommands,
|
||||
...(exportedInvite instanceof GramJs.ChatInviteExported && {
|
||||
@ -463,7 +463,7 @@ async function getFullChannelInfo(
|
||||
canViewParticipants && adminRights && await fetchMembers(id, accessHash, 'kicked')
|
||||
) || {};
|
||||
const { members: adminMembers, users: adminUsers, userStatusesById: adminStatusesById } = (
|
||||
canViewParticipants && adminRights && await fetchMembers(id, accessHash, 'admin')
|
||||
canViewParticipants && await fetchMembers(id, accessHash, 'admin')
|
||||
) || {};
|
||||
const botCommands = botInfo ? buildApiChatBotCommands(botInfo) : undefined;
|
||||
|
||||
@ -506,7 +506,7 @@ async function getFullChannelInfo(
|
||||
isPreHistoryHidden: hiddenPrehistory,
|
||||
members,
|
||||
kickedMembers,
|
||||
adminMembers,
|
||||
adminMembersById: adminMembers ? buildCollectionByKey(adminMembers, 'userId') : undefined,
|
||||
groupCallId: call ? String(call.id) : undefined,
|
||||
linkedChatId: linkedChatId ? buildApiPeerId(linkedChatId, 'chat') : undefined,
|
||||
botCommands,
|
||||
|
||||
@ -86,7 +86,7 @@ export interface ApiChatFullInfo {
|
||||
onlineCount?: number;
|
||||
members?: ApiChatMember[];
|
||||
kickedMembers?: ApiChatMember[];
|
||||
adminMembers?: ApiChatMember[];
|
||||
adminMembersById?: Record<string, ApiChatMember>;
|
||||
canViewMembers?: boolean;
|
||||
isPreHistoryHidden?: boolean;
|
||||
inviteLink?: string;
|
||||
|
||||
@ -293,7 +293,7 @@ export interface ApiMessageForwardInfo {
|
||||
senderUserId?: string;
|
||||
fromMessageId?: number;
|
||||
hiddenUserName?: string;
|
||||
adminTitle?: string;
|
||||
postAuthorTitle?: string;
|
||||
}
|
||||
|
||||
export type ApiMessageEntityDefault = {
|
||||
@ -408,7 +408,7 @@ export interface ApiMessage {
|
||||
isKeyboardSingleUse?: boolean;
|
||||
viaBotId?: string;
|
||||
threadInfo?: ApiThreadInfo;
|
||||
adminTitle?: string;
|
||||
postAuthorTitle?: string;
|
||||
isScheduled?: boolean;
|
||||
shouldHideKeyboardButtons?: boolean;
|
||||
isFromScheduled?: boolean;
|
||||
|
||||
@ -2,7 +2,9 @@ import React, { useEffect, useCallback, memo } from '../../lib/teact/teact';
|
||||
import { getActions, withGlobal } from '../../global';
|
||||
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import type { ApiUser, ApiTypingStatus, ApiUserStatus } from '../../api/types';
|
||||
import type {
|
||||
ApiUser, ApiTypingStatus, ApiUserStatus, ApiChatMember,
|
||||
} from '../../api/types';
|
||||
import type { GlobalState } from '../../global/types';
|
||||
import type { AnimationLevel } from '../../types';
|
||||
import { MediaViewerOrigin } from '../../types';
|
||||
@ -34,6 +36,7 @@ type OwnProps = {
|
||||
emojiStatusSize?: number;
|
||||
noStatusOrTyping?: boolean;
|
||||
noRtl?: boolean;
|
||||
adminMember?: ApiChatMember;
|
||||
};
|
||||
|
||||
type StateProps =
|
||||
@ -67,6 +70,7 @@ const PrivateChatInfo: FC<OwnProps & StateProps> = ({
|
||||
animationLevel,
|
||||
lastSyncTime,
|
||||
serverTimeOffset,
|
||||
adminMember,
|
||||
}) => {
|
||||
const {
|
||||
loadFullUser,
|
||||
@ -131,6 +135,10 @@ const PrivateChatInfo: FC<OwnProps & StateProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
const customTitle = adminMember
|
||||
? adminMember.customTitle || lang(adminMember.isOwner ? 'GroupInfo.LabelOwner' : 'GroupInfo.LabelAdmin')
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div className="ChatInfo" dir={!noRtl && lang.isRtl ? 'rtl' : undefined}>
|
||||
<Avatar
|
||||
@ -143,12 +151,15 @@ const PrivateChatInfo: FC<OwnProps & StateProps> = ({
|
||||
animationLevel={animationLevel}
|
||||
/>
|
||||
<div className="info">
|
||||
<FullNameTitle
|
||||
peer={user}
|
||||
withEmojiStatus
|
||||
emojiStatusSize={emojiStatusSize}
|
||||
isSavedMessages={isSavedMessages}
|
||||
/>
|
||||
<div className="info-name-title">
|
||||
<FullNameTitle
|
||||
peer={user}
|
||||
withEmojiStatus
|
||||
emojiStatusSize={emojiStatusSize}
|
||||
isSavedMessages={isSavedMessages}
|
||||
/>
|
||||
{customTitle && <span className="custom-title">{customTitle}</span>}
|
||||
</div>
|
||||
{(status || (!isSavedMessages && !noStatusOrTyping)) && renderStatusOrTyping()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -45,7 +45,7 @@ import {
|
||||
selectTheme,
|
||||
} from '../../global/selectors';
|
||||
import {
|
||||
getCanPostInChat, getMessageSendingRestrictionReason, isChatChannel, isChatSuperGroup, isUserId,
|
||||
getCanPostInChat, getMessageSendingRestrictionReason, isChatChannel, isChatGroup, isChatSuperGroup, isUserId,
|
||||
} from '../../global/helpers';
|
||||
import captureEscKeyListener from '../../util/captureEscKeyListener';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
@ -108,6 +108,7 @@ type StateProps = {
|
||||
canSubscribe?: boolean;
|
||||
canStartBot?: boolean;
|
||||
canRestartBot?: boolean;
|
||||
shouldLoadFullChat?: boolean;
|
||||
activeEmojiInteractions?: ActiveEmojiInteraction[];
|
||||
shouldJoinToSend?: boolean;
|
||||
shouldSendJoinRequest?: boolean;
|
||||
@ -154,6 +155,7 @@ const MiddleColumn: FC<StateProps> = ({
|
||||
activeEmojiInteractions,
|
||||
shouldJoinToSend,
|
||||
shouldSendJoinRequest,
|
||||
shouldLoadFullChat,
|
||||
lastSyncTime,
|
||||
}) => {
|
||||
const {
|
||||
@ -168,6 +170,7 @@ const MiddleColumn: FC<StateProps> = ({
|
||||
sendBotCommand,
|
||||
restartBot,
|
||||
showNotification,
|
||||
loadFullChat,
|
||||
} = getActions();
|
||||
|
||||
const { width: windowWidth } = useWindowSize();
|
||||
@ -264,6 +267,12 @@ const MiddleColumn: FC<StateProps> = ({
|
||||
}
|
||||
}, [chatId, isPrivate, areChatSettingsLoaded, lastSyncTime, loadChatSettings]);
|
||||
|
||||
useEffect(() => {
|
||||
if (chatId && shouldLoadFullChat && isReady) {
|
||||
loadFullChat({ chatId });
|
||||
}
|
||||
}, [shouldLoadFullChat, chatId, isReady, loadFullChat]);
|
||||
|
||||
const handleDragEnter = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
||||
if (IS_TOUCH_ENV) {
|
||||
return;
|
||||
@ -616,6 +625,7 @@ export default memo(withGlobal(
|
||||
const shouldSendJoinRequest = Boolean(chat?.isNotJoined && chat.isJoinRequest);
|
||||
const canRestartBot = Boolean(bot && selectIsUserBlocked(global, bot.id));
|
||||
const canStartBot = !canRestartBot && isBotNotStarted;
|
||||
const shouldLoadFullChat = Boolean(chat && isChatGroup(chat) && !chat.fullInfo && lastSyncTime);
|
||||
|
||||
return {
|
||||
...state,
|
||||
@ -645,6 +655,7 @@ export default memo(withGlobal(
|
||||
canRestartBot,
|
||||
shouldJoinToSend,
|
||||
shouldSendJoinRequest,
|
||||
shouldLoadFullChat,
|
||||
};
|
||||
},
|
||||
)(MiddleColumn));
|
||||
|
||||
@ -280,7 +280,6 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
addRecentEmoji,
|
||||
sendInlineBotResult,
|
||||
loadSendAs,
|
||||
loadFullChat,
|
||||
resetOpenChatWithDraft,
|
||||
callAttachBot,
|
||||
openLimitReachedModal,
|
||||
@ -334,12 +333,6 @@ const Composer: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
}, [chat, chatId, isReady, lastSyncTime, loadSendAs, sendAsPeerIds]);
|
||||
|
||||
useEffect(() => {
|
||||
if (chatId && chat && lastSyncTime && !chat.fullInfo && isReady && isChatSuperGroup(chat)) {
|
||||
loadFullChat({ chatId });
|
||||
}
|
||||
}, [chat, chatId, isReady, lastSyncTime, loadFullChat]);
|
||||
|
||||
const shouldAnimateSendAsButtonRef = useRef(false);
|
||||
useOnChange(([prevChatId, prevSendAsPeerIds]) => {
|
||||
// We only animate send-as button if `sendAsPeerIds` was missing when opening the chat
|
||||
|
||||
@ -17,6 +17,7 @@ import type {
|
||||
ApiChat,
|
||||
ApiThreadInfo,
|
||||
ApiAvailableReaction,
|
||||
ApiChatMember,
|
||||
} from '../../../api/types';
|
||||
import type {
|
||||
AnimationLevel, FocusDirection, IAlbum, ISettings,
|
||||
@ -74,7 +75,9 @@ import {
|
||||
areReactionsEmpty,
|
||||
getMessageHtmlId,
|
||||
isGeoLiveExpired,
|
||||
getMessageSingleCustomEmoji, hasMessageText,
|
||||
getMessageSingleCustomEmoji,
|
||||
hasMessageText,
|
||||
isChatGroup,
|
||||
} from '../../../global/helpers';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import useEnsureMessage from '../../../hooks/useEnsureMessage';
|
||||
@ -183,6 +186,7 @@ type StateProps = {
|
||||
isChatWithSelf?: boolean;
|
||||
isRepliesChat?: boolean;
|
||||
isChannel?: boolean;
|
||||
isGroup?: boolean;
|
||||
canReply?: boolean;
|
||||
lastSyncTime?: number;
|
||||
serverTimeOffset: number;
|
||||
@ -211,6 +215,7 @@ type StateProps = {
|
||||
isTranscriptionError?: boolean;
|
||||
isPremium: boolean;
|
||||
animationLevel: AnimationLevel;
|
||||
senderAdminMember?: ApiChatMember;
|
||||
};
|
||||
|
||||
type MetaPosition =
|
||||
@ -275,6 +280,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
isChatWithSelf,
|
||||
isRepliesChat,
|
||||
isChannel,
|
||||
isGroup,
|
||||
canReply,
|
||||
lastSyncTime,
|
||||
serverTimeOffset,
|
||||
@ -301,6 +307,7 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
hasUnreadReaction,
|
||||
memoFirstUnreadIdRef,
|
||||
animationLevel,
|
||||
senderAdminMember,
|
||||
}) => {
|
||||
const {
|
||||
toggleMessageSelection,
|
||||
@ -615,7 +622,9 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
style = `width: ${calculatedWidth + extraPadding}px`;
|
||||
}
|
||||
|
||||
const signature = (isChannel && message.adminTitle) || (!asForwarded && forwardInfo?.adminTitle) || undefined;
|
||||
const signature = (isChannel && message.postAuthorTitle)
|
||||
|| (!asForwarded && forwardInfo?.postAuthorTitle)
|
||||
|| undefined;
|
||||
const metaSafeAuthorWidth = useMemo(() => {
|
||||
return signature ? calculateAuthorWidth(signature) : undefined;
|
||||
}, [signature]);
|
||||
@ -984,13 +993,23 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
)}
|
||||
{forwardInfo?.isLinkedChannelPost ? (
|
||||
<span className="admin-title" dir="auto">{lang('DiscussChannel')}</span>
|
||||
) : message.adminTitle && !isChannel ? (
|
||||
<span className="admin-title" dir="auto">{message.adminTitle}</span>
|
||||
) : message.forwardInfo?.postAuthorTitle && isGroup && asForwarded ? (
|
||||
<span className="admin-title" dir="auto">{message.forwardInfo?.postAuthorTitle}</span>
|
||||
) : message.postAuthorTitle && isGroup && !asForwarded ? (
|
||||
<span className="admin-title" dir="auto">{message.postAuthorTitle}</span>
|
||||
) : senderAdminMember && !asForwarded ? (
|
||||
<span className="admin-title" dir="auto">
|
||||
{senderAdminMember.customTitle || lang(
|
||||
senderAdminMember.isOwner ? 'GroupInfo.LabelOwner' : 'GroupInfo.LabelAdmin',
|
||||
)}
|
||||
</span>
|
||||
) : undefined}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const forwardAuthor = isGroup && asForwarded ? message.postAuthorTitle : undefined;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
@ -1040,7 +1059,10 @@ const Message: FC<OwnProps & StateProps> = ({
|
||||
dir="auto"
|
||||
>
|
||||
{asForwarded && !isInDocumentGroupNotFirst && (
|
||||
<div className="message-title">{lang('ForwardedMessage')}</div>
|
||||
<div className="message-title">
|
||||
{lang('ForwardedMessage')}
|
||||
{forwardAuthor && <span className="admin-title" dir="auto">{forwardAuthor}</span>}
|
||||
</div>
|
||||
)}
|
||||
{renderContent()}
|
||||
{!isInDocumentGroupNotLast && metaPosition === 'standalone' && renderReactionsAndMeta()}
|
||||
@ -1124,13 +1146,18 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isChatWithSelf = selectIsChatWithSelf(global, chatId);
|
||||
const isRepliesChat = isChatWithRepliesBot(chatId);
|
||||
const isChannel = chat && isChatChannel(chat);
|
||||
const isGroup = chat && isChatGroup(chat);
|
||||
const chatUsername = chat?.username;
|
||||
|
||||
const isForwarding = forwardMessages.messageIds && forwardMessages.messageIds.includes(id);
|
||||
const forceSenderName = !isChatWithSelf && isAnonymousOwnMessage(message);
|
||||
const canShowSender = withSenderName || withAvatar || forceSenderName;
|
||||
const sender = selectSender(global, message);
|
||||
const originSender = selectForwardedSender(global, message);
|
||||
const botSender = viaBotId ? selectUser(global, viaBotId) : undefined;
|
||||
const senderAdminMember = sender?.id && isGroup
|
||||
? chat.fullInfo?.adminMembersById?.[sender?.id]
|
||||
: undefined;
|
||||
|
||||
const threadTopMessageId = threadId ? selectThreadTopMessageId(global, chatId, threadId) : undefined;
|
||||
const isThreadTop = message.id === threadTopMessageId;
|
||||
@ -1152,8 +1179,6 @@ export default memo(withGlobal<OwnProps>(
|
||||
direction: focusDirection, noHighlight: noFocusHighlight, isResizingContainer,
|
||||
} = (isFocused && focusedMessage) || {};
|
||||
|
||||
const isForwarding = forwardMessages.messageIds && forwardMessages.messageIds.includes(id);
|
||||
|
||||
const { query: highlight } = selectCurrentTextSearch(global) || {};
|
||||
|
||||
const singleEmoji = getMessageSingleRegularEmoji(message);
|
||||
@ -1206,6 +1231,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
isChatWithSelf,
|
||||
isRepliesChat,
|
||||
isChannel,
|
||||
isGroup,
|
||||
canReply,
|
||||
lastSyncTime,
|
||||
serverTimeOffset,
|
||||
@ -1239,6 +1265,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
transcribedText: transcriptionId !== undefined ? global.transcriptions[transcriptionId]?.text : undefined,
|
||||
isPremium: selectIsCurrentUserPremium(global),
|
||||
animationLevel: global.settings.byKey.animationLevel,
|
||||
senderAdminMember,
|
||||
};
|
||||
},
|
||||
)(Message));
|
||||
|
||||
@ -85,6 +85,7 @@ type StateProps = {
|
||||
canAddMembers?: boolean;
|
||||
canDeleteMembers?: boolean;
|
||||
members?: ApiChatMember[];
|
||||
adminMembersById?: Record<string, ApiChatMember>;
|
||||
commonChatIds?: string[];
|
||||
chatsById: Record<string, ApiChat>;
|
||||
usersById: Record<string, ApiUser>;
|
||||
@ -126,6 +127,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
canDeleteMembers,
|
||||
commonChatIds,
|
||||
members,
|
||||
adminMembersById,
|
||||
usersById,
|
||||
userStatusesById,
|
||||
chatsById,
|
||||
@ -416,7 +418,7 @@ const Profile: FC<OwnProps & StateProps> = ({
|
||||
onClick={() => handleMemberClick(id)}
|
||||
contextActions={getMemberContextAction(id)}
|
||||
>
|
||||
<PrivateChatInfo userId={id} forceShowSelf />
|
||||
<PrivateChatInfo userId={id} adminMember={adminMembersById?.[id]} forceShowSelf />
|
||||
</ListItem>
|
||||
))
|
||||
) : resultType === 'commonChats' ? (
|
||||
@ -524,6 +526,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isChannel = chat && isChatChannel(chat);
|
||||
const hasMembersTab = isGroup || (isChannel && isChatAdmin(chat!));
|
||||
const members = chat?.fullInfo?.members;
|
||||
const adminMembersById = chat?.fullInfo?.adminMembersById;
|
||||
const areMembersHidden = hasMembersTab && chat
|
||||
&& (chat.isForbidden || (chat.fullInfo && !chat.fullInfo.canViewMembers));
|
||||
const canAddMembers = hasMembersTab && chat
|
||||
@ -562,7 +565,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
userStatusesById,
|
||||
chatsById,
|
||||
isChatProtected: chat?.isProtected,
|
||||
...(hasMembersTab && members && { members }),
|
||||
...(hasMembersTab && members && { members, adminMembersById }),
|
||||
...(hasCommonChatsTab && user && { commonChatIds: user.commonChats?.ids }),
|
||||
};
|
||||
},
|
||||
|
||||
@ -108,7 +108,7 @@ const ManageChannel: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
}, [progress]);
|
||||
|
||||
const adminsCount = (chat?.fullInfo?.adminMembers?.length) || 0;
|
||||
const adminsCount = Object.keys(chat.fullInfo?.adminMembersById || {}).length;
|
||||
const removedUsersCount = (chat?.fullInfo?.kickedMembers?.length) || 0;
|
||||
|
||||
const handleClickEditType = useCallback(() => {
|
||||
|
||||
@ -49,11 +49,11 @@ const ManageChatAdministrators: FC<OwnProps & StateProps> = ({
|
||||
}, [onScreenSelect]);
|
||||
|
||||
const adminMembers = useMemo(() => {
|
||||
if (!chat.fullInfo || !chat.fullInfo.adminMembers) {
|
||||
if (!chat.fullInfo?.adminMembersById) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return chat.fullInfo.adminMembers.sort((a, b) => {
|
||||
return Object.values(chat.fullInfo.adminMembersById).sort((a, b) => {
|
||||
if (a.isOwner) {
|
||||
return -1;
|
||||
} else if (b.isOwner) {
|
||||
|
||||
@ -236,7 +236,9 @@ const ManageGroup: FC<OwnProps & StateProps> = ({
|
||||
return totalCount;
|
||||
}, [chat]);
|
||||
|
||||
const adminsCount = (chat.fullInfo?.adminMembers?.length) || 0;
|
||||
const adminsCount = useMemo(() => {
|
||||
return Object.keys(chat.fullInfo?.adminMembersById || {}).length;
|
||||
}, [chat.fullInfo?.adminMembersById]);
|
||||
|
||||
const handleDeleteGroup = useCallback(() => {
|
||||
if (isBasicGroup) {
|
||||
|
||||
@ -70,7 +70,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
||||
});
|
||||
|
||||
const selectedChatMember = useMemo(() => {
|
||||
const selectedAdminMember = chat.fullInfo?.adminMembers?.find(({ userId }) => userId === selectedUserId);
|
||||
const selectedAdminMember = selectedUserId ? chat.fullInfo?.adminMembersById?.[selectedUserId] : undefined;
|
||||
|
||||
// If `selectedAdminMember` variable is filled with a value, then we have already saved the administrator,
|
||||
// so now we need to return to the list of administrators
|
||||
@ -91,7 +91,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
||||
}
|
||||
|
||||
return selectedAdminMember;
|
||||
}, [chat.fullInfo?.adminMembers, defaultRights, isNewAdmin, lang, selectedUserId]);
|
||||
}, [chat.fullInfo?.adminMembersById, defaultRights, isNewAdmin, lang, selectedUserId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (chat?.fullInfo && selectedUserId && !selectedChatMember) {
|
||||
|
||||
@ -37,7 +37,7 @@ type OwnProps = {
|
||||
type StateProps = {
|
||||
userStatusesById: Record<string, ApiUserStatus>;
|
||||
members?: ApiChatMember[];
|
||||
adminMembers?: ApiChatMember[];
|
||||
adminMembersById?: Record<string, ApiChatMember>;
|
||||
isChannel?: boolean;
|
||||
localContactIds?: string[];
|
||||
searchQuery?: string;
|
||||
@ -52,7 +52,7 @@ type StateProps = {
|
||||
const ManageGroupMembers: FC<OwnProps & StateProps> = ({
|
||||
noAdmins,
|
||||
members,
|
||||
adminMembers,
|
||||
adminMembersById,
|
||||
userStatusesById,
|
||||
isChannel,
|
||||
isActive,
|
||||
@ -78,8 +78,8 @@ const ManageGroupMembers: FC<OwnProps & StateProps> = ({
|
||||
const [deletingUserId, setDeletingUserId] = useState<string | undefined>();
|
||||
|
||||
const adminIds = useMemo(() => {
|
||||
return noAdmins ? adminMembers?.map(({ userId }) => userId) || [] : [];
|
||||
}, [adminMembers, noAdmins]);
|
||||
return noAdmins && adminMembersById ? Object.keys(adminMembersById) : [];
|
||||
}, [adminMembersById, noAdmins]);
|
||||
|
||||
const memberIds = useMemo(() => {
|
||||
// No need for expensive global updates on users, so we avoid them
|
||||
@ -233,7 +233,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const chat = selectChat(global, chatId);
|
||||
const { statusesById: userStatusesById } = global.users;
|
||||
const members = chat?.fullInfo?.members;
|
||||
const adminMembers = chat?.fullInfo?.adminMembers;
|
||||
const adminMembersById = chat?.fullInfo?.adminMembersById;
|
||||
const isChannel = chat && isChatChannel(chat);
|
||||
const { userIds: localContactIds } = global.contactList || {};
|
||||
|
||||
@ -248,7 +248,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
return {
|
||||
members,
|
||||
adminMembers,
|
||||
adminMembersById,
|
||||
userStatusesById,
|
||||
isChannel,
|
||||
localContactIds,
|
||||
|
||||
@ -30,11 +30,11 @@ const ManageGroupRecentActions: FC<OwnProps & StateProps> = ({ chat, onClose, is
|
||||
});
|
||||
|
||||
const adminMembers = useMemo(() => {
|
||||
if (!chat || !chat.fullInfo || !chat.fullInfo.adminMembers) {
|
||||
if (!chat?.fullInfo?.adminMembersById) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return chat.fullInfo.adminMembers.sort((a, b) => {
|
||||
return Object.values(chat.fullInfo.adminMembersById).sort((a, b) => {
|
||||
if (a.isOwner) {
|
||||
return -1;
|
||||
} else if (b.isOwner) {
|
||||
|
||||
@ -165,6 +165,11 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.info-name-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info-row,
|
||||
.title,
|
||||
.subtitle {
|
||||
@ -211,6 +216,17 @@
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.custom-title {
|
||||
padding-inline-start: 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-secondary);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
margin-inline-start: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status,
|
||||
.typing-status {
|
||||
font-size: 0.875rem;
|
||||
|
||||
@ -3,7 +3,7 @@ import {
|
||||
} from '../../index';
|
||||
|
||||
import type {
|
||||
ApiChat, ApiUser, ApiChatFolder, ApiError,
|
||||
ApiChat, ApiUser, ApiChatFolder, ApiError, ApiChatMember,
|
||||
} from '../../../api/types';
|
||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||
import { NewChatMembersProgress, ChatCreationProgress, ManagementProgress } from '../../../types';
|
||||
@ -867,24 +867,31 @@ addActionHandler('updateChatAdmin', async (global, actions, payload) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const { adminMembers } = chatAfterUpdate.fullInfo;
|
||||
const { adminMembersById } = chatAfterUpdate.fullInfo;
|
||||
const isDismissed = !Object.keys(adminRights).length;
|
||||
let newAdminMembersById: Record<string, ApiChatMember> | undefined;
|
||||
if (adminMembersById) {
|
||||
if (isDismissed) {
|
||||
const { [userId]: remove, ...rest } = adminMembersById;
|
||||
newAdminMembersById = rest;
|
||||
} else {
|
||||
newAdminMembersById = {
|
||||
...adminMembersById,
|
||||
[userId]: {
|
||||
...adminMembersById[userId],
|
||||
adminRights,
|
||||
customTitle,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
global = getGlobal();
|
||||
|
||||
setGlobal(updateChat(global, chatId, {
|
||||
fullInfo: {
|
||||
...chatAfterUpdate.fullInfo,
|
||||
...(adminMembers && isDismissed && {
|
||||
adminMembers: adminMembers.filter((m) => m.userId !== userId),
|
||||
}),
|
||||
...(adminMembers && !isDismissed && {
|
||||
adminMembers: adminMembers.map((m) => (
|
||||
m.userId === userId
|
||||
? { ...m, adminRights, customTitle }
|
||||
: m
|
||||
)),
|
||||
}),
|
||||
...(newAdminMembersById && { adminMembersById: newAdminMembersById }),
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
@ -3,7 +3,7 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||
|
||||
import { ARCHIVED_FOLDER_ID, MAX_ACTIVE_PINNED_CHATS } from '../../../config';
|
||||
import { pick } from '../../../util/iteratees';
|
||||
import { buildCollectionByKey, pick } from '../../../util/iteratees';
|
||||
import { closeMessageNotifications, notifyAboutMessage } from '../../../util/notifications';
|
||||
import {
|
||||
updateChat,
|
||||
@ -326,7 +326,7 @@ addActionHandler('apiUpdate', (global, actions, update) => {
|
||||
fullInfo: {
|
||||
...targetChat.fullInfo,
|
||||
members,
|
||||
adminMembers,
|
||||
adminMembersById: buildCollectionByKey(adminMembers, 'userId'),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ import type { GlobalState } from '../types';
|
||||
import type { ApiChat, ApiChatMember, ApiPhoto } from '../../api/types';
|
||||
|
||||
import { ARCHIVED_FOLDER_ID } from '../../config';
|
||||
import { areSortedArraysEqual, omit } from '../../util/iteratees';
|
||||
import { areSortedArraysEqual, buildCollectionByKey, omit } from '../../util/iteratees';
|
||||
import { selectChatListType } from '../selectors';
|
||||
|
||||
export function replaceChatListIds(
|
||||
@ -242,6 +242,7 @@ export function addChatMembers(global: GlobalState, chat: ApiChat, membersToAdd:
|
||||
fullInfo: {
|
||||
...chat.fullInfo,
|
||||
members: updatedMembers,
|
||||
adminMembersById: buildCollectionByKey(updatedMembers, 'userId'),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user