Management: Support promoting members to admins (#1629)
This commit is contained in:
parent
bad220ff29
commit
0b40f27ed9
@ -133,6 +133,8 @@ const RightColumn: FC<StateProps> = ({
|
|||||||
setIsPromotedByCurrentUser(undefined);
|
setIsPromotedByCurrentUser(undefined);
|
||||||
break;
|
break;
|
||||||
case ManagementScreens.ChatAdminRights:
|
case ManagementScreens.ChatAdminRights:
|
||||||
|
case ManagementScreens.ChatNewAdminRights:
|
||||||
|
case ManagementScreens.GroupAddAdmins:
|
||||||
case ManagementScreens.GroupRecentActions:
|
case ManagementScreens.GroupRecentActions:
|
||||||
setManagementScreen(ManagementScreens.ChatAdministrators);
|
setManagementScreen(ManagementScreens.ChatAdministrators);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -77,7 +77,9 @@ enum HeaderContent {
|
|||||||
ManageGroupUserPermissions,
|
ManageGroupUserPermissions,
|
||||||
ManageGroupRecentActions,
|
ManageGroupRecentActions,
|
||||||
ManageGroupAdminRights,
|
ManageGroupAdminRights,
|
||||||
|
ManageGroupNewAdminRights,
|
||||||
ManageGroupMembers,
|
ManageGroupMembers,
|
||||||
|
ManageGroupAddAdmins,
|
||||||
StickerSearch,
|
StickerSearch,
|
||||||
GifSearch,
|
GifSearch,
|
||||||
PollResults,
|
PollResults,
|
||||||
@ -187,8 +189,12 @@ const RightHeader: FC<OwnProps & StateProps> = ({
|
|||||||
HeaderContent.ManageGroupRecentActions
|
HeaderContent.ManageGroupRecentActions
|
||||||
) : managementScreen === ManagementScreens.ChatAdminRights ? (
|
) : managementScreen === ManagementScreens.ChatAdminRights ? (
|
||||||
HeaderContent.ManageGroupAdminRights
|
HeaderContent.ManageGroupAdminRights
|
||||||
|
) : managementScreen === ManagementScreens.ChatNewAdminRights ? (
|
||||||
|
HeaderContent.ManageGroupNewAdminRights
|
||||||
) : managementScreen === ManagementScreens.GroupMembers ? (
|
) : managementScreen === ManagementScreens.GroupMembers ? (
|
||||||
HeaderContent.ManageGroupMembers
|
HeaderContent.ManageGroupMembers
|
||||||
|
) : managementScreen === ManagementScreens.GroupAddAdmins ? (
|
||||||
|
HeaderContent.ManageGroupAddAdmins
|
||||||
) : undefined // Never reached
|
) : undefined // Never reached
|
||||||
) : undefined; // When column is closed
|
) : undefined; // When column is closed
|
||||||
|
|
||||||
@ -235,6 +241,8 @@ const RightHeader: FC<OwnProps & StateProps> = ({
|
|||||||
return <h3>{lang('Group.Info.AdminLog')}</h3>;
|
return <h3>{lang('Group.Info.AdminLog')}</h3>;
|
||||||
case HeaderContent.ManageGroupAdminRights:
|
case HeaderContent.ManageGroupAdminRights:
|
||||||
return <h3>{lang('EditAdminRights')}</h3>;
|
return <h3>{lang('EditAdminRights')}</h3>;
|
||||||
|
case HeaderContent.ManageGroupNewAdminRights:
|
||||||
|
return <h3>{lang('SetAsAdmin')}</h3>;
|
||||||
case HeaderContent.ManageGroupPermissions:
|
case HeaderContent.ManageGroupPermissions:
|
||||||
return <h3>{lang('ChannelPermissions')}</h3>;
|
return <h3>{lang('ChannelPermissions')}</h3>;
|
||||||
case HeaderContent.ManageGroupRemovedUsers:
|
case HeaderContent.ManageGroupRemovedUsers:
|
||||||
@ -243,6 +251,8 @@ const RightHeader: FC<OwnProps & StateProps> = ({
|
|||||||
return <h3>{lang('ChannelAddException')}</h3>;
|
return <h3>{lang('ChannelAddException')}</h3>;
|
||||||
case HeaderContent.ManageGroupUserPermissions:
|
case HeaderContent.ManageGroupUserPermissions:
|
||||||
return <h3>{lang('UserRestrictions')}</h3>;
|
return <h3>{lang('UserRestrictions')}</h3>;
|
||||||
|
case HeaderContent.ManageGroupAddAdmins:
|
||||||
|
return <h3>{lang('Channel.Management.AddModerator')}</h3>;
|
||||||
case HeaderContent.StickerSearch:
|
case HeaderContent.StickerSearch:
|
||||||
return (
|
return (
|
||||||
<SearchInput
|
<SearchInput
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useCallback, useMemo,
|
FC, memo, useCallback, useMemo,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { withGlobal } from '../../../lib/teact/teactn';
|
import { getGlobal, withGlobal } from '../../../lib/teact/teactn';
|
||||||
|
|
||||||
import { ManagementScreens } from '../../../types';
|
import { ManagementScreens } from '../../../types';
|
||||||
import { ApiChat, ApiChatMember, ApiUser } from '../../../api/types';
|
import { ApiChat, ApiChatMember } from '../../../api/types';
|
||||||
|
|
||||||
import { getUserFullName, isChatChannel } from '../../../modules/helpers';
|
import { getUserFullName, isChatChannel } from '../../../modules/helpers';
|
||||||
import { selectChat } from '../../../modules/selectors';
|
import { selectChat } from '../../../modules/selectors';
|
||||||
@ -13,6 +13,7 @@ import useHistoryBack from '../../../hooks/useHistoryBack';
|
|||||||
|
|
||||||
import ListItem from '../../ui/ListItem';
|
import ListItem from '../../ui/ListItem';
|
||||||
import PrivateChatInfo from '../../common/PrivateChatInfo';
|
import PrivateChatInfo from '../../common/PrivateChatInfo';
|
||||||
|
import FloatingActionButton from '../../ui/FloatingActionButton';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
@ -26,14 +27,12 @@ type StateProps = {
|
|||||||
chat: ApiChat;
|
chat: ApiChat;
|
||||||
currentUserId?: string;
|
currentUserId?: string;
|
||||||
isChannel: boolean;
|
isChannel: boolean;
|
||||||
usersById: Record<string, ApiUser>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ManageChatAdministrators: FC<OwnProps & StateProps> = ({
|
const ManageChatAdministrators: FC<OwnProps & StateProps> = ({
|
||||||
chat,
|
chat,
|
||||||
isChannel,
|
isChannel,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
usersById,
|
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
onChatMemberSelect,
|
onChatMemberSelect,
|
||||||
onClose,
|
onClose,
|
||||||
@ -68,11 +67,17 @@ const ManageChatAdministrators: FC<OwnProps & StateProps> = ({
|
|||||||
onScreenSelect(ManagementScreens.ChatAdminRights);
|
onScreenSelect(ManagementScreens.ChatAdminRights);
|
||||||
}, [currentUserId, onChatMemberSelect, onScreenSelect]);
|
}, [currentUserId, onChatMemberSelect, onScreenSelect]);
|
||||||
|
|
||||||
|
const handleAddAdminClick = useCallback(() => {
|
||||||
|
onScreenSelect(ManagementScreens.GroupAddAdmins);
|
||||||
|
}, [onScreenSelect]);
|
||||||
|
|
||||||
const getMemberStatus = useCallback((member: ApiChatMember) => {
|
const getMemberStatus = useCallback((member: ApiChatMember) => {
|
||||||
if (member.isOwner) {
|
if (member.isOwner) {
|
||||||
return lang('ChannelCreator');
|
return lang('ChannelCreator');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No need for expensive global updates on users, so we avoid them
|
||||||
|
const usersById = getGlobal().users.byId;
|
||||||
const promotedByUser = member.promotedByUserId ? usersById[member.promotedByUserId] : undefined;
|
const promotedByUser = member.promotedByUserId ? usersById[member.promotedByUserId] : undefined;
|
||||||
|
|
||||||
if (promotedByUser) {
|
if (promotedByUser) {
|
||||||
@ -80,7 +85,7 @@ const ManageChatAdministrators: FC<OwnProps & StateProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return lang('ChannelAdmin');
|
return lang('ChannelAdmin');
|
||||||
}, [lang, usersById]);
|
}, [lang]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Management">
|
<div className="Management">
|
||||||
@ -116,6 +121,14 @@ const ManageChatAdministrators: FC<OwnProps & StateProps> = ({
|
|||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
<FloatingActionButton
|
||||||
|
isShown
|
||||||
|
onClick={handleAddAdminClick}
|
||||||
|
ariaLabel={lang('Channel.Management.AddModerator')}
|
||||||
|
>
|
||||||
|
<i className="icon-add-user-filled" />
|
||||||
|
</FloatingActionButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -125,13 +138,11 @@ const ManageChatAdministrators: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { chatId }): StateProps => {
|
(global, { chatId }): StateProps => {
|
||||||
const chat = selectChat(global, chatId)!;
|
const chat = selectChat(global, chatId)!;
|
||||||
const { byId: usersById } = global.users;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chat,
|
chat,
|
||||||
currentUserId: global.currentUserId,
|
currentUserId: global.currentUserId,
|
||||||
isChannel: isChatChannel(chat),
|
isChannel: isChatChannel(chat),
|
||||||
usersById,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(ManageChatAdministrators));
|
)(ManageChatAdministrators));
|
||||||
|
|||||||
@ -24,6 +24,7 @@ type OwnProps = {
|
|||||||
chatId: string;
|
chatId: string;
|
||||||
selectedChatMemberId?: string;
|
selectedChatMemberId?: string;
|
||||||
isPromotedByCurrentUser?: boolean;
|
isPromotedByCurrentUser?: boolean;
|
||||||
|
isNewAdmin?: boolean;
|
||||||
onScreenSelect: (screen: ManagementScreens) => void;
|
onScreenSelect: (screen: ManagementScreens) => void;
|
||||||
onClose: NoneToVoidFunction;
|
onClose: NoneToVoidFunction;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
@ -35,12 +36,15 @@ type StateProps = {
|
|||||||
currentUserId?: string;
|
currentUserId?: string;
|
||||||
isChannel: boolean;
|
isChannel: boolean;
|
||||||
isFormFullyDisabled: boolean;
|
isFormFullyDisabled: boolean;
|
||||||
|
defaultRights?: ApiChatAdminRights;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CUSTOM_TITLE_MAX_LENGTH = 16;
|
const CUSTOM_TITLE_MAX_LENGTH = 16;
|
||||||
|
|
||||||
const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
||||||
|
isNewAdmin,
|
||||||
selectedChatMemberId,
|
selectedChatMemberId,
|
||||||
|
defaultRights,
|
||||||
onScreenSelect,
|
onScreenSelect,
|
||||||
chat,
|
chat,
|
||||||
usersById,
|
usersById,
|
||||||
@ -53,7 +57,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
const { updateChatAdmin } = getDispatch();
|
const { updateChatAdmin } = getDispatch();
|
||||||
|
|
||||||
const [permissions, setPermissions] = useState<ApiChatAdminRights>({});
|
const [permissions, setPermissions] = useState<ApiChatAdminRights>({});
|
||||||
const [isTouched, setIsTouched] = useState(false);
|
const [isTouched, setIsTouched] = useState(isNewAdmin);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isDismissConfirmationDialogOpen, openDismissConfirmationDialog, closeDismissConfirmationDialog] = useFlag();
|
const [isDismissConfirmationDialogOpen, openDismissConfirmationDialog, closeDismissConfirmationDialog] = useFlag();
|
||||||
const [customTitle, setCustomTitle] = useState('');
|
const [customTitle, setCustomTitle] = useState('');
|
||||||
@ -62,12 +66,18 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
useHistoryBack(isActive, onClose);
|
useHistoryBack(isActive, onClose);
|
||||||
|
|
||||||
const selectedChatMember = useMemo(() => {
|
const selectedChatMember = useMemo(() => {
|
||||||
if (!chat.fullInfo || !chat.fullInfo.adminMembers) {
|
const selectedAdminMember = chat.fullInfo?.adminMembers?.find(({ userId }) => userId === selectedChatMemberId);
|
||||||
return undefined;
|
|
||||||
|
if (isNewAdmin) {
|
||||||
|
// If selectedAdminMember is fullfilled, it means that we are editing an existing admin (after a user
|
||||||
|
// has been promoted as admin)
|
||||||
|
return selectedAdminMember
|
||||||
|
? undefined
|
||||||
|
: chat.fullInfo?.members?.find(({ userId }) => userId === selectedChatMemberId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return chat.fullInfo.adminMembers.find(({ userId }) => userId === selectedChatMemberId);
|
return selectedAdminMember;
|
||||||
}, [chat, selectedChatMemberId]);
|
}, [chat.fullInfo, isNewAdmin, selectedChatMemberId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (chat?.fullInfo && selectedChatMemberId && !selectedChatMember) {
|
if (chat?.fullInfo && selectedChatMemberId && !selectedChatMember) {
|
||||||
@ -76,11 +86,11 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
}, [chat, onScreenSelect, selectedChatMember, selectedChatMemberId]);
|
}, [chat, onScreenSelect, selectedChatMember, selectedChatMemberId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPermissions((selectedChatMember?.adminRights) || {});
|
setPermissions((isNewAdmin ? defaultRights : selectedChatMember?.adminRights) || {});
|
||||||
setCustomTitle(((selectedChatMember?.customTitle) || '').substr(0, CUSTOM_TITLE_MAX_LENGTH));
|
setCustomTitle(((isNewAdmin ? 'admin' : selectedChatMember?.customTitle) || '').substr(0, CUSTOM_TITLE_MAX_LENGTH));
|
||||||
setIsTouched(false);
|
setIsTouched(Boolean(isNewAdmin));
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, [selectedChatMember]);
|
}, [defaultRights, isNewAdmin, selectedChatMember]);
|
||||||
|
|
||||||
const handlePermissionChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
const handlePermissionChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name } = e.target;
|
const { name } = e.target;
|
||||||
@ -108,7 +118,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
adminRights: permissions,
|
adminRights: permissions,
|
||||||
customTitle,
|
customTitle,
|
||||||
});
|
});
|
||||||
}, [chat, selectedChatMemberId, permissions, customTitle, updateChatAdmin]);
|
}, [selectedChatMemberId, updateChatAdmin, chat.id, permissions, customTitle]);
|
||||||
|
|
||||||
const handleDismissAdmin = useCallback(() => {
|
const handleDismissAdmin = useCallback(() => {
|
||||||
if (!selectedChatMemberId) {
|
if (!selectedChatMemberId) {
|
||||||
@ -136,7 +146,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
}, [chat, isFormFullyDisabled]);
|
}, [chat, isFormFullyDisabled]);
|
||||||
|
|
||||||
const memberStatus = useMemo(() => {
|
const memberStatus = useMemo(() => {
|
||||||
if (!selectedChatMember) {
|
if (isNewAdmin || !selectedChatMember) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +163,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return lang('ChannelAdmin');
|
return lang('ChannelAdmin');
|
||||||
}, [selectedChatMember, usersById, lang]);
|
}, [isNewAdmin, selectedChatMember, usersById, lang]);
|
||||||
|
|
||||||
const handleCustomTitleChange = useCallback((e) => {
|
const handleCustomTitleChange = useCallback((e) => {
|
||||||
const { value } = e.target;
|
const { value } = e.target;
|
||||||
@ -307,7 +317,7 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{currentUserId !== selectedChatMemberId && !isFormFullyDisabled && (
|
{currentUserId !== selectedChatMemberId && !isFormFullyDisabled && !isNewAdmin && (
|
||||||
<ListItem icon="delete" ripple destructive onClick={openDismissConfirmationDialog}>
|
<ListItem icon="delete" ripple destructive onClick={openDismissConfirmationDialog}>
|
||||||
{lang('EditAdminRemoveAdmin')}
|
{lang('EditAdminRemoveAdmin')}
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@ -328,14 +338,16 @@ const ManageGroupAdminRights: FC<OwnProps & StateProps> = ({
|
|||||||
)}
|
)}
|
||||||
</FloatingActionButton>
|
</FloatingActionButton>
|
||||||
|
|
||||||
<ConfirmDialog
|
{!isNewAdmin && (
|
||||||
isOpen={isDismissConfirmationDialogOpen}
|
<ConfirmDialog
|
||||||
onClose={closeDismissConfirmationDialog}
|
isOpen={isDismissConfirmationDialogOpen}
|
||||||
text="Are you sure you want to dismiss this admin?"
|
onClose={closeDismissConfirmationDialog}
|
||||||
confirmLabel="Dismiss"
|
text="Are you sure you want to dismiss this admin?"
|
||||||
confirmHandler={handleDismissAdmin}
|
confirmLabel={lang('Channel.Admin.Dismiss')}
|
||||||
confirmIsDestructive
|
confirmHandler={handleDismissAdmin}
|
||||||
/>
|
confirmIsDestructive
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -354,6 +366,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
currentUserId,
|
currentUserId,
|
||||||
isChannel,
|
isChannel,
|
||||||
isFormFullyDisabled,
|
isFormFullyDisabled,
|
||||||
|
defaultRights: chat.adminRights,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
)(ManageGroupAdminRights));
|
)(ManageGroupAdminRights));
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, memo, useCallback, useMemo,
|
FC, memo, useCallback, useMemo,
|
||||||
} from '../../../lib/teact/teact';
|
} from '../../../lib/teact/teact';
|
||||||
import { getDispatch, withGlobal } from '../../../lib/teact/teactn';
|
import { getDispatch, getGlobal, withGlobal } from '../../../lib/teact/teactn';
|
||||||
|
|
||||||
|
import { ApiChatMember, ApiUserStatus } from '../../../api/types';
|
||||||
|
import { ManagementScreens } from '../../../types';
|
||||||
|
|
||||||
import { ApiChatMember, ApiUser, ApiUserStatus } from '../../../api/types';
|
|
||||||
import { selectChat } from '../../../modules/selectors';
|
import { selectChat } from '../../../modules/selectors';
|
||||||
import { sortUserIds, isChatChannel } from '../../../modules/helpers';
|
import { sortUserIds, isChatChannel } from '../../../modules/helpers';
|
||||||
import useHistoryBack from '../../../hooks/useHistoryBack';
|
import useHistoryBack from '../../../hooks/useHistoryBack';
|
||||||
@ -14,46 +16,62 @@ import ListItem from '../../ui/ListItem';
|
|||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
onClose: NoneToVoidFunction;
|
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
noAdmins?: boolean;
|
||||||
|
onClose: NoneToVoidFunction;
|
||||||
|
onScreenSelect?: (screen: ManagementScreens) => void;
|
||||||
|
onChatMemberSelect?: (memberId: string, isPromotedByCurrentUser?: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
usersById: Record<string, ApiUser>;
|
|
||||||
userStatusesById: Record<string, ApiUserStatus>;
|
userStatusesById: Record<string, ApiUserStatus>;
|
||||||
members?: ApiChatMember[];
|
members?: ApiChatMember[];
|
||||||
|
adminMembers?: ApiChatMember[];
|
||||||
isChannel?: boolean;
|
isChannel?: boolean;
|
||||||
serverTimeOffset: number;
|
serverTimeOffset: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ManageGroupMembers: FC<OwnProps & StateProps> = ({
|
const ManageGroupMembers: FC<OwnProps & StateProps> = ({
|
||||||
|
noAdmins,
|
||||||
members,
|
members,
|
||||||
usersById,
|
adminMembers,
|
||||||
userStatusesById,
|
userStatusesById,
|
||||||
isChannel,
|
isChannel,
|
||||||
onClose,
|
|
||||||
isActive,
|
isActive,
|
||||||
serverTimeOffset,
|
serverTimeOffset,
|
||||||
|
onClose,
|
||||||
|
onScreenSelect,
|
||||||
|
onChatMemberSelect,
|
||||||
}) => {
|
}) => {
|
||||||
const { openUserInfo } = getDispatch();
|
const { openUserInfo } = getDispatch();
|
||||||
|
|
||||||
const memberIds = useMemo(() => {
|
const memberIds = useMemo(() => {
|
||||||
|
// No need for expensive global updates on users, so we avoid them
|
||||||
|
const usersById = getGlobal().users.byId;
|
||||||
if (!members || !usersById) {
|
if (!members || !usersById) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
const adminIds = noAdmins ? adminMembers?.map(({ userId }) => userId) || [] : [];
|
||||||
|
|
||||||
return sortUserIds(
|
const userIds = sortUserIds(
|
||||||
members.map(({ userId }) => userId),
|
members.map(({ userId }) => userId),
|
||||||
usersById,
|
usersById,
|
||||||
userStatusesById,
|
userStatusesById,
|
||||||
undefined,
|
undefined,
|
||||||
serverTimeOffset,
|
serverTimeOffset,
|
||||||
);
|
);
|
||||||
}, [members, serverTimeOffset, usersById, userStatusesById]);
|
|
||||||
|
return noAdmins ? userIds.filter((userId) => !adminIds.includes(userId)) : userIds;
|
||||||
|
}, [members, noAdmins, adminMembers, userStatusesById, serverTimeOffset]);
|
||||||
|
|
||||||
const handleMemberClick = useCallback((id: string) => {
|
const handleMemberClick = useCallback((id: string) => {
|
||||||
openUserInfo({ id });
|
if (noAdmins) {
|
||||||
}, [openUserInfo]);
|
onChatMemberSelect!(id, false);
|
||||||
|
onScreenSelect!(ManagementScreens.ChatNewAdminRights);
|
||||||
|
} else {
|
||||||
|
openUserInfo({ id });
|
||||||
|
}
|
||||||
|
}, [noAdmins, onChatMemberSelect, onScreenSelect, openUserInfo]);
|
||||||
|
|
||||||
useHistoryBack(isActive, onClose);
|
useHistoryBack(isActive, onClose);
|
||||||
|
|
||||||
@ -88,13 +106,14 @@ const ManageGroupMembers: FC<OwnProps & StateProps> = ({
|
|||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { chatId }): StateProps => {
|
(global, { chatId }): StateProps => {
|
||||||
const chat = selectChat(global, chatId);
|
const chat = selectChat(global, chatId);
|
||||||
const { byId: usersById, statusesById: userStatusesById } = global.users;
|
const { statusesById: userStatusesById } = global.users;
|
||||||
const members = chat?.fullInfo?.members;
|
const members = chat?.fullInfo?.members;
|
||||||
|
const adminMembers = chat?.fullInfo?.adminMembers;
|
||||||
const isChannel = chat && isChatChannel(chat);
|
const isChannel = chat && isChatChannel(chat);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
members,
|
members,
|
||||||
usersById,
|
adminMembers,
|
||||||
userStatusesById,
|
userStatusesById,
|
||||||
isChannel,
|
isChannel,
|
||||||
serverTimeOffset: global.serverTimeOffset,
|
serverTimeOffset: global.serverTimeOffset,
|
||||||
|
|||||||
@ -73,6 +73,7 @@ const Management: FC<OwnProps & StateProps> = ({
|
|||||||
ManagementScreens.GroupUserPermissionsCreate,
|
ManagementScreens.GroupUserPermissionsCreate,
|
||||||
ManagementScreens.GroupUserPermissions,
|
ManagementScreens.GroupUserPermissions,
|
||||||
ManagementScreens.ChatAdminRights,
|
ManagementScreens.ChatAdminRights,
|
||||||
|
ManagementScreens.ChatNewAdminRights,
|
||||||
ManagementScreens.GroupRecentActions,
|
ManagementScreens.GroupRecentActions,
|
||||||
].includes(currentScreen)}
|
].includes(currentScreen)}
|
||||||
/>
|
/>
|
||||||
@ -90,6 +91,7 @@ const Management: FC<OwnProps & StateProps> = ({
|
|||||||
ManagementScreens.Discussion,
|
ManagementScreens.Discussion,
|
||||||
ManagementScreens.ChatPrivacyType,
|
ManagementScreens.ChatPrivacyType,
|
||||||
ManagementScreens.ChatAdminRights,
|
ManagementScreens.ChatAdminRights,
|
||||||
|
ManagementScreens.ChatNewAdminRights,
|
||||||
ManagementScreens.GroupRecentActions,
|
ManagementScreens.GroupRecentActions,
|
||||||
].includes(currentScreen)}
|
].includes(currentScreen)}
|
||||||
/>
|
/>
|
||||||
@ -175,6 +177,7 @@ const Management: FC<OwnProps & StateProps> = ({
|
|||||||
onChatMemberSelect={onChatMemberSelect}
|
onChatMemberSelect={onChatMemberSelect}
|
||||||
isActive={isActive || [
|
isActive={isActive || [
|
||||||
ManagementScreens.ChatAdminRights,
|
ManagementScreens.ChatAdminRights,
|
||||||
|
ManagementScreens.ChatNewAdminRights,
|
||||||
ManagementScreens.GroupRecentActions,
|
ManagementScreens.GroupRecentActions,
|
||||||
].includes(currentScreen)}
|
].includes(currentScreen)}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
@ -202,6 +205,19 @@ const Management: FC<OwnProps & StateProps> = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case ManagementScreens.ChatNewAdminRights:
|
||||||
|
return (
|
||||||
|
<ManageGroupAdminRights
|
||||||
|
chatId={chatId}
|
||||||
|
isNewAdmin
|
||||||
|
selectedChatMemberId={selectedChatMemberId}
|
||||||
|
isPromotedByCurrentUser={isPromotedByCurrentUser}
|
||||||
|
onScreenSelect={onScreenSelect}
|
||||||
|
isActive={isActive}
|
||||||
|
onClose={onClose}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
case ManagementScreens.ChannelSubscribers:
|
case ManagementScreens.ChannelSubscribers:
|
||||||
case ManagementScreens.GroupMembers:
|
case ManagementScreens.GroupMembers:
|
||||||
return (
|
return (
|
||||||
@ -211,6 +227,18 @@ const Management: FC<OwnProps & StateProps> = ({
|
|||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case ManagementScreens.GroupAddAdmins:
|
||||||
|
return (
|
||||||
|
<ManageGroupMembers
|
||||||
|
chatId={chatId}
|
||||||
|
noAdmins
|
||||||
|
isActive={isActive}
|
||||||
|
onClose={onClose}
|
||||||
|
onScreenSelect={onScreenSelect}
|
||||||
|
onChatMemberSelect={onChatMemberSelect}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined; // Never reached
|
return undefined; // Never reached
|
||||||
|
|||||||
@ -763,8 +763,8 @@ addReducer('updateChatAdmin', (global, actions, payload) => {
|
|||||||
chat, user, adminRights, customTitle,
|
chat, user, adminRights, customTitle,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const chatAfterUpdate = await callApi('fetchFullChat', chat);
|
||||||
const newGlobal = getGlobal();
|
const newGlobal = getGlobal();
|
||||||
const chatAfterUpdate = selectChat(newGlobal, chatId);
|
|
||||||
|
|
||||||
if (!chatAfterUpdate || !chatAfterUpdate.fullInfo) {
|
if (!chatAfterUpdate || !chatAfterUpdate.fullInfo) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -317,7 +317,9 @@ export enum ManagementScreens {
|
|||||||
ChatAdministrators,
|
ChatAdministrators,
|
||||||
GroupRecentActions,
|
GroupRecentActions,
|
||||||
ChatAdminRights,
|
ChatAdminRights,
|
||||||
|
ChatNewAdminRights,
|
||||||
GroupMembers,
|
GroupMembers,
|
||||||
|
GroupAddAdmins,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ManagementType = 'user' | 'group' | 'channel';
|
export type ManagementType = 'user' | 'group' | 'channel';
|
||||||
|
|||||||
@ -63,6 +63,11 @@ const READABLE_ERROR_MESSAGES: Record<string, string> = {
|
|||||||
USER_ALREADY_PARTICIPANT: 'You already in the group',
|
USER_ALREADY_PARTICIPANT: 'You already in the group',
|
||||||
SCHEDULE_DATE_INVALID: 'Invalid schedule date provided',
|
SCHEDULE_DATE_INVALID: 'Invalid schedule date provided',
|
||||||
WALLPAPER_DIMENSIONS_INVALID: 'The wallpaper dimensions are invalid, please select another file',
|
WALLPAPER_DIMENSIONS_INVALID: 'The wallpaper dimensions are invalid, please select another file',
|
||||||
|
ADMINS_TOO_MUCH: 'There are too many admins',
|
||||||
|
ADMIN_RANK_EMOJI_NOT_ALLOWED: 'An admin rank cannot contain emojis',
|
||||||
|
ADMIN_RANK_INVALID: 'The specified admin rank is invalid',
|
||||||
|
FRESH_CHANGE_ADMINS_FORBIDDEN: 'You were just elected admin, you can\'t add or modify other admins yet',
|
||||||
|
INPUT_USER_DEACTIVATED: 'The specified user was deleted',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SHIPPING_ERRORS: Record<string, ApiFieldError> = {
|
export const SHIPPING_ERRORS: Record<string, ApiFieldError> = {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user