fix: mod and admin actions on message context menu for communities

pull/2793/head
Audric Ackermann 2 years ago
parent d970887caa
commit 461b192f37

@ -24,6 +24,13 @@ import {
} from '../../../../state/ducks/conversations';
import { StateType } from '../../../../state/reducer';
import { getMessageContextMenuProps } from '../../../../state/selectors/conversations';
import {
useSelectedConversationKey,
useSelectedIsBlocked,
useSelectedIsPublic,
useSelectedWeAreAdmin,
useSelectedWeAreModerator,
} from '../../../../state/selectors/selectedConversation';
import { saveAttachmentToDisk } from '../../../../util/attachmentsUtil';
import { Reactions } from '../../../../util/reactions';
import { SessionContextMenuContainer } from '../../../SessionContextMenuContainer';
@ -34,18 +41,13 @@ export type MessageContextMenuSelectorProps = Pick<
MessageRenderingProps,
| 'attachments'
| 'sender'
| 'convoId'
| 'direction'
| 'status'
| 'isDeletable'
| 'isPublic'
| 'isOpenGroupV2'
| 'weAreAdmin'
| 'isSenderAdmin'
| 'text'
| 'serverTimestamp'
| 'timestamp'
| 'isBlocked'
| 'isDeletableForEveryone'
>;
@ -80,27 +82,31 @@ export const MessageContextMenu = (props: Props) => {
const dispatch = useDispatch();
const { hideAll } = useContextMenu();
const isSelectedBlocked = useSelectedIsBlocked();
const convoId = useSelectedConversationKey();
const isPublic = useSelectedIsPublic();
const weAreModerator = useSelectedWeAreModerator();
const weAreAdmin = useSelectedWeAreAdmin();
const showAdminActions = weAreAdmin || weAreModerator;
const selected = useSelector((state: StateType) => getMessageContextMenuProps(state, messageId));
if (!selected) {
if (!selected || !convoId) {
return null;
}
const {
attachments,
sender,
convoId,
direction,
status,
isDeletable,
isDeletableForEveryone,
isPublic,
weAreAdmin,
isSenderAdmin,
text,
serverTimestamp,
timestamp,
isBlocked,
} = selected;
const isOutgoing = direction === 'outgoing';
@ -157,12 +163,12 @@ export const MessageContextMenu = (props: Props) => {
}, [sender, convoId]);
const onReply = useCallback(() => {
if (isBlocked) {
if (isSelectedBlocked) {
pushUnblockToSend();
return;
}
void replyToMessage(messageId);
}, [isBlocked, messageId]);
}, [isSelectedBlocked, messageId]);
const saveAttachment = useCallback(
(e: any) => {
@ -330,14 +336,12 @@ export const MessageContextMenu = (props: Props) => {
<Item onClick={onDeleteForEveryone}>{unsendMessageText}</Item>
</>
) : null}
{weAreAdmin && isPublic ? <Item onClick={onBan}>{window.i18n('banUser')}</Item> : null}
{weAreAdmin && isPublic ? (
<Item onClick={onUnban}>{window.i18n('unbanUser')}</Item>
) : null}
{weAreAdmin && isPublic && !isSenderAdmin ? (
{showAdminActions ? <Item onClick={onBan}>{window.i18n('banUser')}</Item> : null}
{showAdminActions ? <Item onClick={onUnban}>{window.i18n('unbanUser')}</Item> : null}
{showAdminActions && !isSenderAdmin ? (
<Item onClick={addModerator}>{window.i18n('addAsModerator')}</Item>
) : null}
{weAreAdmin && isPublic && isSenderAdmin ? (
{showAdminActions && isSenderAdmin ? (
<Item onClick={removeModerator}>{window.i18n('removeFromModerators')}</Item>
) : null}
</Menu>

@ -3,7 +3,7 @@ import React, { ReactElement, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { Data } from '../../data/data';
import { useMessageReactsPropsById, useWeAreModerator } from '../../hooks/useParamSelector';
import { useMessageReactsPropsById } from '../../hooks/useParamSelector';
import { isUsAnySogsFromCache } from '../../session/apis/open_group_api/sogsv3/knownBlindedkeys';
import { UserUtils } from '../../session/utils';
import {
@ -11,7 +11,10 @@ import {
updateReactListModal,
updateUserDetailsModal,
} from '../../state/ducks/modalDialog';
import { useSelectedIsPublic } from '../../state/selectors/selectedConversation';
import {
useSelectedIsPublic,
useSelectedWeAreModerator,
} from '../../state/selectors/selectedConversation';
import { SortedReactionList } from '../../types/Reaction';
import { nativeEmojiData } from '../../util/emoji';
import { Reactions } from '../../util/reactions';
@ -229,7 +232,7 @@ export const ReactListModal = (props: Props): ReactElement => {
const msgProps = useMessageReactsPropsById(messageId);
const isPublic = useSelectedIsPublic();
const weAreModerator = useWeAreModerator(msgProps?.convoId);
const weAreModerator = useSelectedWeAreModerator();
const me = UserUtils.getOurPubKeyStrFromCache();
// tslint:disable: cyclomatic-complexity

@ -146,11 +146,6 @@ export function useWeAreAdmin(convoId?: string) {
return Boolean(convoProps && convoProps.weAreAdmin);
}
export function useWeAreModerator(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && (convoProps.weAreAdmin || convoProps.weAreModerator));
}
export function useExpireTimer(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return convoProps && convoProps.expireTimer;

@ -269,7 +269,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const avatarPath = this.getAvatarPath();
const isPrivate = this.isPrivate();
const weAreAdmin = this.isAdmin(ourNumber);
const weAreModerator = this.isModerator(ourNumber); // only used for sogs
const currentNotificationSetting = this.get('triggerNotificationsFor');
const priorityFromDb = this.get('priority');
@ -310,10 +309,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
toRet.weAreAdmin = true;
}
if (weAreModerator) {
toRet.weAreModerator = true;
}
if (isPublic) {
toRet.isPublic = true;
}

@ -237,7 +237,6 @@ export interface ReduxConversationType {
isPublic?: boolean;
isPrivate?: boolean; // !isPrivate means isGroup (group or community)
weAreAdmin?: boolean;
weAreModerator?: boolean;
unreadCount?: number;
mentionedUs?: boolean;
isSelected?: boolean;

@ -86,10 +86,11 @@ function setCanWriteOutsideRedux(convoId: string, canWrite: boolean) {
}
/**
* Update the redux slice for that community's moderators list
* if we are a moderator that room and the room is blinded, this update needs to contain our unblinded pubkey, NOT the blinded one.
*
* @param convoId the convoId of the room to set the moderators
* @param moderators the updated list of moderators
* Note: if we are a moderator that room and the room is blinded, this update needs to contain our unblinded pubkey, NOT the blinded one
*/
function setModeratorsOutsideRedux(convoId: string, moderators: Array<string>) {
const currentMods = getModeratorsOutsideRedux(convoId);

@ -888,6 +888,10 @@ export const useMessageIsDeleted = (messageId: string): boolean => {
return props?.propsForMessage.isDeleted || false;
};
/**
* TODO probably not something which should be memoized with createSelector as we rememoize it for each message (and override the previous one). Not sure what is the right way to do a lookup. But maybe something like having the messages as a record<id, message> and do a simple lookup to grab the details.
* And the the sorting would be done in a memoized selector
*/
export const getMessageContextMenuProps = createSelector(getMessagePropsByMessageId, (props):
| MessageContextMenuSelectorProps
| undefined => {
@ -898,18 +902,13 @@ export const getMessageContextMenuProps = createSelector(getMessagePropsByMessag
const msgProps: MessageContextMenuSelectorProps = pick(props.propsForMessage, [
'attachments',
'sender',
'convoId',
'direction',
'status',
'isDeletable',
'isPublic',
'isOpenGroupV2',
'weAreAdmin',
'isSenderAdmin',
'text',
'serverTimestamp',
'timestamp',
'isBlocked',
'isDeletableForEveryone',
]);

@ -1,9 +1,11 @@
import { isString } from 'lodash';
import { useSelector } from 'react-redux';
import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversationAttributes';
import { PubKey } from '../../session/types';
import { UserUtils } from '../../session/utils';
import { ReduxConversationType } from '../ducks/conversations';
import { StateType } from '../reducer';
import { getCanWrite, getSubscriberCount } from './sogsRoomInfo';
import { PubKey } from '../../session/types';
import { getCanWrite, getModerators, getSubscriberCount } from './sogsRoomInfo';
/**
* Returns the formatted text for notification setting.
@ -257,3 +259,18 @@ export function useSelectedNicknameOrProfileNameOrShortenedPubkey() {
export function useSelectedWeAreAdmin() {
return useSelector((state: StateType) => getSelectedConversation(state)?.weAreAdmin || false);
}
/**
* Only for communities.
* @returns true if the selected convo is a community and we are one of the moderators
*/
export function useSelectedWeAreModerator() {
// TODO might be something to memoize let's see
const isPublic = useSelectedIsPublic();
const selectedConvoKey = useSelectedConversationKey();
const us = UserUtils.getOurPubKeyStrFromCache();
const mods = useSelector((state: StateType) => getModerators(state, selectedConvoKey));
const weAreModerator = mods.includes(us);
return isPublic && isString(selectedConvoKey) && weAreModerator;
}

Loading…
Cancel
Save