From 3476b54d43ed401d2749f42ed02168d5084775e4 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 18 Jan 2021 15:29:31 +1100 Subject: [PATCH] fix add/remove moderators dialog and open groups name avatar dialog --- js/models/conversations.d.ts | 2 +- js/models/conversations.js | 3 ++ js/views/moderators_add_dialog_view.js | 21 ++++++----- stylesheets/_modal.scss | 3 ++ ts/components/EditProfileDialog.tsx | 4 +-- .../conversation/ConversationHeader.tsx | 2 +- .../conversation/ModeratorsAddDialog.tsx | 36 ++++++++++++------- .../conversation/ModeratorsRemoveDialog.tsx | 25 +++++++++---- .../conversation/UpdateGroupNameDialog.tsx | 5 ++- ts/components/session/SessionInput.tsx | 1 - .../session/SessionPasswordModal.tsx | 8 +++-- .../conversation/SessionConversation.tsx | 17 ++++++--- .../conversation/SessionRightPanel.tsx | 30 ++++++++++++---- .../session/menu/ConversationHeaderMenu.tsx | 10 +++--- ts/components/session/menu/Menu.tsx | 24 ++++++------- 15 files changed, 124 insertions(+), 67 deletions(-) diff --git a/js/models/conversations.d.ts b/js/models/conversations.d.ts index eed53b9de..082bfc856 100644 --- a/js/models/conversations.d.ts +++ b/js/models/conversations.d.ts @@ -65,7 +65,7 @@ export interface ConversationModel isRss: () => boolean; isBlocked: () => boolean; isClosable: () => boolean; - isModerator: (id?: string) => boolean; + isModerator: (id: string) => boolean; throttledBumpTyping: () => void; messageCollection: Backbone.Collection; diff --git a/js/models/conversations.js b/js/models/conversations.js index 03861a967..56f78dab6 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -1827,6 +1827,9 @@ if (!this.isPublic()) { return false; } + if (!pubKey) { + throw new Error('isModerator() pubKey is falsy'); + } const moderators = this.get('moderators'); return Array.isArray(moderators) && moderators.includes(pubKey); }, diff --git a/js/views/moderators_add_dialog_view.js b/js/views/moderators_add_dialog_view.js index d2d777dce..f9da33531 100644 --- a/js/views/moderators_add_dialog_view.js +++ b/js/views/moderators_add_dialog_view.js @@ -21,17 +21,20 @@ const modPubKeys = await this.channelAPI.getModerators(); // private contacts (not you) that aren't already moderators - const contacts = convo.filter( - d => - !!d && - d.isPrivate() && - !d.isBlocked() && - !d.isMe() && - !modPubKeys.includes(d.id) - ); + const contacts = window + .getConversationController() + .getConversations() + .filter( + d => + !!d && + d.isPrivate() && + !d.isBlocked() && + !d.isMe() && + !modPubKeys.includes(d.id) + ); this.contacts = contacts; - this.this.theme = convo.theme; + this.theme = convo.theme; this.$el.focus(); this.render(); diff --git a/stylesheets/_modal.scss b/stylesheets/_modal.scss index d0bab63db..ab3bcf8eb 100644 --- a/stylesheets/_modal.scss +++ b/stylesheets/_modal.scss @@ -33,6 +33,9 @@ .content { max-width: 100% !important; } + .contact-selection-list { + width: 100%; + } .buttons { margin: 8px; diff --git a/ts/components/EditProfileDialog.tsx b/ts/components/EditProfileDialog.tsx index a58f3fda8..6fabff939 100644 --- a/ts/components/EditProfileDialog.tsx +++ b/ts/components/EditProfileDialog.tsx @@ -256,7 +256,7 @@ export class EditProfileDialog extends React.Component { private renderAvatar() { const { avatar, profileName } = this.state; const { pubkey } = this.props; - const userName = name || profileName || pubkey; + const userName = profileName || pubkey; return ( @@ -264,8 +264,6 @@ export class EditProfileDialog extends React.Component { } private onNameEdited(event: any) { - event.persist(); - const newName = event.target.value.replace(window.displayNameRegex, ''); this.setState(state => { diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx index b8f5c7c1e..59abe4e00 100644 --- a/ts/components/conversation/ConversationHeader.tsx +++ b/ts/components/conversation/ConversationHeader.tsx @@ -44,7 +44,7 @@ interface Props { isPrivate: boolean; isPublic: boolean; isRss: boolean; - amMod: boolean; + isAdmin: boolean; // We might not always have the full list of members, // e.g. for open groups where we could have thousands diff --git a/ts/components/conversation/ModeratorsAddDialog.tsx b/ts/components/conversation/ModeratorsAddDialog.tsx index 37335fc49..bf4d0c0ec 100644 --- a/ts/components/conversation/ModeratorsAddDialog.tsx +++ b/ts/components/conversation/ModeratorsAddDialog.tsx @@ -1,14 +1,17 @@ import React from 'react'; import { Contact, MemberList } from './MemberList'; import { cleanSearchTerm } from '../../util/cleanSearchTerm'; -import { DefaultTheme } from 'styled-components'; +import { + SessionButton, + SessionButtonColor, + SessionButtonType, +} from '../session/SessionButton'; interface Props { contactList: Array; chatName: string; onSubmit: any; onClose: any; - // theme: DefaultTheme; } interface State { @@ -136,9 +139,12 @@ export class AddModeratorsDialog extends React.Component { dir="auto" onChange={this.updateSearchBound} /> - +

From friends:

@@ -152,13 +158,19 @@ export class AddModeratorsDialog extends React.Component {
{hasContacts ? null :

{i18n('noContactsToAdd')}

} -
- - +
+ +
); diff --git a/ts/components/conversation/ModeratorsRemoveDialog.tsx b/ts/components/conversation/ModeratorsRemoveDialog.tsx index 75f20d8d6..74df7d400 100644 --- a/ts/components/conversation/ModeratorsRemoveDialog.tsx +++ b/ts/components/conversation/ModeratorsRemoveDialog.tsx @@ -1,4 +1,9 @@ import React from 'react'; +import { + SessionButton, + SessionButtonColor, + SessionButtonType, +} from '../session/SessionButton'; import { Contact, MemberList } from './MemberList'; interface Props { @@ -69,13 +74,19 @@ export class RemoveModeratorsDialog extends React.Component { {hasMods ? null :

{i18n('noModeratorsToRemove')}

} -
- - +
+ +
); diff --git a/ts/components/conversation/UpdateGroupNameDialog.tsx b/ts/components/conversation/UpdateGroupNameDialog.tsx index dcc8cfb1b..e92445135 100644 --- a/ts/components/conversation/UpdateGroupNameDialog.tsx +++ b/ts/components/conversation/UpdateGroupNameDialog.tsx @@ -157,12 +157,11 @@ class UpdateGroupNameDialogInner extends React.Component { } private onGroupNameChanged(event: any) { - event.persist(); - + const groupName = event.target.value; this.setState(state => { return { ...state, - groupName: event.target.value, + groupName, }; }); } diff --git a/ts/components/session/SessionInput.tsx b/ts/components/session/SessionInput.tsx index 00e151d18..212236689 100644 --- a/ts/components/session/SessionInput.tsx +++ b/ts/components/session/SessionInput.tsx @@ -72,7 +72,6 @@ export class SessionInput extends React.PureComponent { this.updateInputValue(e); }} onKeyPress={event => { - event.persist(); if (event.key === 'Enter' && this.props.onEnterPressed) { this.props.onEnterPressed(); } diff --git a/ts/components/session/SessionPasswordModal.tsx b/ts/components/session/SessionPasswordModal.tsx index 7496e1a03..52cceeff1 100644 --- a/ts/components/session/SessionPasswordModal.tsx +++ b/ts/components/session/SessionPasswordModal.tsx @@ -285,14 +285,18 @@ class SessionPasswordModalInner extends React.Component { if (event.key === 'Enter') { return this.setPassword(this.props.onOk); } - this.setState({ currentPasswordEntered: event.target.value }); + const currentPasswordEntered = event.target.value; + + this.setState({ currentPasswordEntered }); } private async onPasswordConfirmInput(event: any) { if (event.key === 'Enter') { return this.setPassword(this.props.onOk); } - this.setState({ currentPasswordConfirmEntered: event.target.value }); + const currentPasswordConfirmEntered = event.target.value; + + this.setState({ currentPasswordConfirmEntered }); } } diff --git a/ts/components/session/conversation/SessionConversation.tsx b/ts/components/session/conversation/SessionConversation.tsx index 2607ae168..33fe02905 100644 --- a/ts/components/session/conversation/SessionConversation.tsx +++ b/ts/components/session/conversation/SessionConversation.tsx @@ -444,7 +444,7 @@ export class SessionConversation extends React.Component { isPrivate: conversation.isPrivate(), isPublic: conversation.isPublic(), isRss: conversation.isRss(), - amMod: conversation.isModerator( + isAdmin: conversation.isModerator( window.storage.get('primaryDevicePubKey') ), members, @@ -484,7 +484,7 @@ export class SessionConversation extends React.Component { }, onUpdateGroupName: () => { - conversation.onUpdateGroupName(); + window.Whisper.events.trigger('updateGroupName', conversation); }, onBlockUser: () => { @@ -549,12 +549,14 @@ export class SessionConversation extends React.Component { const conversation = ConversationController.getInstance().getOrThrow( conversationKey ); + const ourPrimary = window.storage.get('primaryDevicePubKey'); - const ourPK = window.textsecure.storage.user.getNumber(); const members = conversation.get('members') || []; const isAdmin = conversation.isMediumGroup() ? true - : conversation.get('groupAdmins')?.includes(ourPK); + : conversation.isPublic() + ? conversation.isModerator(ourPrimary) + : false; return { id: conversation.id, @@ -563,7 +565,6 @@ export class SessionConversation extends React.Component { phoneNumber: conversation.getNumber(), profileName: conversation.getProfileName(), avatarPath: conversation.getAvatarPath(), - amMod: conversation.isModerator(), isKickedFromGroup: conversation.get('isKickedFromGroup'), left: conversation.get('left'), isGroup: !conversation.isPrivate(), @@ -601,7 +602,13 @@ export class SessionConversation extends React.Component { onLeaveGroup: () => { window.Whisper.events.trigger('leaveGroup', conversation); }, + onAddModerators: () => { + window.Whisper.events.trigger('addModerators', conversation); + }, + onRemoveModerators: () => { + window.Whisper.events.trigger('removeModerators', conversation); + }, onShowLightBox: (lightBoxOptions = {}) => { this.setState({ lightBoxOptions }); }, diff --git a/ts/components/session/conversation/SessionRightPanel.tsx b/ts/components/session/conversation/SessionRightPanel.tsx index ce70bd3de..a488b32a6 100644 --- a/ts/components/session/conversation/SessionRightPanel.tsx +++ b/ts/components/session/conversation/SessionRightPanel.tsx @@ -29,7 +29,6 @@ interface Props { timerOptions: Array; isPublic: boolean; isAdmin: boolean; - amMod: boolean; isKickedFromGroup: boolean; left: boolean; isBlocked: boolean; @@ -40,6 +39,8 @@ interface Props { onInviteContacts: () => void; onLeaveGroup: () => void; onUpdateGroupName: () => void; + onAddModerators: () => void; + onRemoveModerators: () => void; onUpdateGroupMembers: () => void; onShowLightBox: (options: any) => void; onSetDisappearingMessages: (seconds: number) => void; @@ -247,7 +248,6 @@ class SessionRightPanel extends React.Component { left, isPublic, isAdmin, - amMod, isBlocked, isGroup, } = this.props; @@ -273,10 +273,9 @@ class SessionRightPanel extends React.Component { }; }); - const showUpdateGroupNameButton = - isPublic && !commonNoShow - ? amMod && !commonNoShow - : isAdmin && !commonNoShow; + const showUpdateGroupNameButton = isAdmin && !commonNoShow; + const showAddRemoveModeratorsButton = isAdmin && !commonNoShow && isPublic; + const showUpdateGroupMembersButton = !isPublic && !commonNoShow && isAdmin; return ( @@ -305,6 +304,25 @@ class SessionRightPanel extends React.Component { {isPublic ? window.i18n('editGroup') : window.i18n('editGroupName')} )} + {showAddRemoveModeratorsButton && ( + <> +
+ {window.i18n('addModerators')} +
+
+ {window.i18n('removeModerators')} +
+ + )} + {showUpdateGroupMembersButton && (
; isPrivate: boolean; isBlocked: boolean; @@ -54,7 +54,7 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { isRss, isGroup, isKickedFromGroup, - amMod, + isAdmin, timerOptions, isBlocked, isPrivate, @@ -115,19 +115,19 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { {getCopyMenuItem(isPublic, isRss, isGroup, onCopyPublicKey, window.i18n)} {getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n)} {getAddModeratorsMenuItem( - amMod, + isAdmin, isKickedFromGroup, onAddModerators, window.i18n )} {getRemoveModeratorsMenuItem( - amMod, + isAdmin, isKickedFromGroup, onRemoveModerators, window.i18n )} {getUpdateGroupNameMenuItem( - amMod, + isAdmin, isKickedFromGroup, left, onUpdateGroupName, diff --git a/ts/components/session/menu/Menu.tsx b/ts/components/session/menu/Menu.tsx index 052ef399a..8ae690853 100644 --- a/ts/components/session/menu/Menu.tsx +++ b/ts/components/session/menu/Menu.tsx @@ -75,25 +75,25 @@ function showDeleteContact( } function showAddModerators( - amMod: boolean, + isAdmin: boolean, isKickedFromGroup: boolean ): boolean { - return !isKickedFromGroup && amMod; + return !isKickedFromGroup && isAdmin; } function showRemoveModerators( - amMod: boolean, + isAdmin: boolean, isKickedFromGroup: boolean ): boolean { - return !isKickedFromGroup && amMod; + return !isKickedFromGroup && isAdmin; } function showUpdateGroupName( - amMod: boolean, + isAdmin: boolean, isKickedFromGroup: boolean, left: boolean ): boolean { - return !isKickedFromGroup && !left && amMod; + return !isKickedFromGroup && !left && isAdmin; } function showLeaveGroup( @@ -174,7 +174,7 @@ export function getLeaveGroupMenuItem( } export function getUpdateGroupNameMenuItem( - amMod: boolean | undefined, + isAdmin: boolean | undefined, isKickedFromGroup: boolean | undefined, left: boolean | undefined, action: any, @@ -182,7 +182,7 @@ export function getUpdateGroupNameMenuItem( ): JSX.Element | null { if ( showUpdateGroupName( - Boolean(amMod), + Boolean(isAdmin), Boolean(isKickedFromGroup), Boolean(left) ) @@ -193,24 +193,24 @@ export function getUpdateGroupNameMenuItem( } export function getRemoveModeratorsMenuItem( - amMod: boolean | undefined, + isAdmin: boolean | undefined, isKickedFromGroup: boolean | undefined, action: any, i18n: LocalizerType ): JSX.Element | null { - if (showRemoveModerators(Boolean(amMod), Boolean(isKickedFromGroup))) { + if (showRemoveModerators(Boolean(isAdmin), Boolean(isKickedFromGroup))) { return {i18n('removeModerators')}; } return null; } export function getAddModeratorsMenuItem( - amMod: boolean | undefined, + isAdmin: boolean | undefined, isKickedFromGroup: boolean | undefined, action: any, i18n: LocalizerType ): JSX.Element | null { - if (showAddModerators(Boolean(amMod), Boolean(isKickedFromGroup))) { + if (showAddModerators(Boolean(isAdmin), Boolean(isKickedFromGroup))) { return {i18n('addModerators')}; } return null;