separate update group name and group members dialog

(add and remove members are separated)
pull/842/head
Audric Ackermann 5 years ago
parent 4fb178c092
commit ff10637a5a
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -5,7 +5,6 @@
Session integrates directly with [Loki Service Nodes](https://lokidocs.com/ServiceNodes/SNOverview/), which are a set of distributed, decentralized and Sybil resistant nodes. Service Nodes act as servers which store messages offline, and a set of nodes which allow for onion routing functionality obfuscating users IP Addresses. For a full understanding of how Session works, read the [Session Whitepaper](https://getsession.org/whitepaper). Session integrates directly with [Loki Service Nodes](https://lokidocs.com/ServiceNodes/SNOverview/), which are a set of distributed, decentralized and Sybil resistant nodes. Service Nodes act as servers which store messages offline, and a set of nodes which allow for onion routing functionality obfuscating users IP Addresses. For a full understanding of how Session works, read the [Session Whitepaper](https://getsession.org/whitepaper).
![DesktopSession](https://i.imgur.com/ZnHvYjo.jpg) ![DesktopSession](https://i.imgur.com/ZnHvYjo.jpg)
## Want to Contribute? Found a Bug or Have a feature request? ## Want to Contribute? Found a Bug or Have a feature request?
Please search for any [existing issues](https://github.com/loki-project/session-desktop/issues) that describe your bugs in order to avoid duplicate submissions. Submissions can be made by making a pull request to our development branch. If you don't know where to start contributing , try reading the Github issues page for ideas. Please search for any [existing issues](https://github.com/loki-project/session-desktop/issues) that describe your bugs in order to avoid duplicate submissions. Submissions can be made by making a pull request to our development branch. If you don't know where to start contributing , try reading the Github issues page for ideas.

@ -2204,12 +2204,16 @@
"message": "Edit Profile", "message": "Edit Profile",
"description": "Button action that the user can click to edit their profile" "description": "Button action that the user can click to edit their profile"
}, },
"editGroupName": {
"message": "Edit group name",
"description": "Button action that the user can click to edit a group name"
},
"createGroupDialogTitle": { "createGroupDialogTitle": {
"message": "Creating a Private Group Chat", "message": "Creating a Closed Group",
"description": "Title for the dialog box used to create a new private group" "description": "Title for the dialog box used to create a new private group"
}, },
"updateGroupDialogTitle": { "updateGroupDialogTitle": {
"message": "Updating a Private Group Chat", "message": "Updating a Closed Group",
"description": "description":
"Title for the dialog box used to update an existing private group" "Title for the dialog box used to update an existing private group"
}, },
@ -2529,6 +2533,9 @@
"noFriendsToAdd": { "noFriendsToAdd": {
"message": "No friends to add" "message": "No friends to add"
}, },
"noMembersInThisGroup": {
"message": "No other members in this group"
},
"noModeratorsToRemove": { "noModeratorsToRemove": {
"message": "no moderators to remove" "message": "no moderators to remove"
}, },

@ -1135,9 +1135,14 @@
} }
}); });
Whisper.events.on('updateGroup', async groupConvo => { Whisper.events.on('updateGroupName', async groupConvo => {
if (appView) { if (appView) {
appView.showUpdateGroupDialog(groupConvo); appView.showUpdateGroupNameDialog(groupConvo);
}
});
Whisper.events.on('updateGroupMembers', async groupConvo => {
if (appView) {
appView.showUpdateGroupMembersDialog(groupConvo);
} }
}); });

@ -34,8 +34,8 @@ const {
ConversationHeader, ConversationHeader,
} = require('../../ts/components/conversation/ConversationHeader'); } = require('../../ts/components/conversation/ConversationHeader');
const { const {
SessionChannelSettings, SessionGroupSettings,
} = require('../../ts/components/session/SessionChannelSettings'); } = require('../../ts/components/session/SessionGroupSettings');
const { const {
EmbeddedContact, EmbeddedContact,
} = require('../../ts/components/conversation/EmbeddedContact'); } = require('../../ts/components/conversation/EmbeddedContact');
@ -93,8 +93,11 @@ const {
} = require('../../ts/components/session/SessionRegistrationView'); } = require('../../ts/components/session/SessionRegistrationView');
const { const {
UpdateGroupDialog, UpdateGroupNameDialog,
} = require('../../ts/components/conversation/UpdateGroupDialog'); } = require('../../ts/components/conversation/UpdateGroupNameDialog');
const {
UpdateGroupMembersDialog,
} = require('../../ts/components/conversation/UpdateGroupMembersDialog');
const { const {
InviteFriendsDialog, InviteFriendsDialog,
} = require('../../ts/components/conversation/InviteFriendsDialog'); } = require('../../ts/components/conversation/InviteFriendsDialog');
@ -278,7 +281,7 @@ exports.setup = (options = {}) => {
ContactListItem, ContactListItem,
ContactName, ContactName,
ConversationHeader, ConversationHeader,
SessionChannelSettings, SessionGroupSettings,
SettingsView, SettingsView,
EmbeddedContact, EmbeddedContact,
Emojify, Emojify,
@ -293,7 +296,8 @@ exports.setup = (options = {}) => {
DevicePairingDialog, DevicePairingDialog,
SessionRegistrationView, SessionRegistrationView,
ConfirmDialog, ConfirmDialog,
UpdateGroupDialog, UpdateGroupNameDialog,
UpdateGroupMembersDialog,
InviteFriendsDialog, InviteFriendsDialog,
AddModeratorsDialog, AddModeratorsDialog,
RemoveModeratorsDialog, RemoveModeratorsDialog,

@ -228,10 +228,15 @@
const dialog = new Whisper.CreateGroupDialogView(); const dialog = new Whisper.CreateGroupDialogView();
this.el.append(dialog.el); this.el.append(dialog.el);
}, },
showUpdateGroupDialog(groupConvo) { showUpdateGroupNameDialog(groupConvo) {
const dialog = new Whisper.UpdateGroupDialogView(groupConvo); const dialog = new Whisper.UpdateGroupNameDialogView(groupConvo);
this.el.prepend(dialog.el); this.el.append(dialog.el);
}, },
showUpdateGroupMembersDialog(groupConvo) {
const dialog = new Whisper.UpdateGroupMembersDialogView(groupConvo);
this.el.append(dialog.el);
},
showSessionRestoreConfirmation(options) { showSessionRestoreConfirmation(options) {
const dialog = new Whisper.ConfirmSessionResetView(options); const dialog = new Whisper.ConfirmSessionResetView(options);
this.el.append(dialog.el); this.el.append(dialog.el);

@ -244,11 +244,6 @@
onMoveToInbox: () => { onMoveToInbox: () => {
this.model.setArchived(false); this.model.setArchived(false);
}, },
onUpdateGroup: () => {
window.Whisper.events.trigger('updateGroup', this.model);
},
onLeaveGroup: () => { onLeaveGroup: () => {
window.Whisper.events.trigger('leaveGroup', this.model); window.Whisper.events.trigger('leaveGroup', this.model);
}, },
@ -276,7 +271,8 @@
}, },
}; };
}; };
const getGroupSettingsProp = () => { const getGroupSettingsProps = () => {
const ourPK = window.textsecure.storage.user.getNumber();
const members = this.model.get('members') || []; const members = this.model.get('members') || [];
return { return {
@ -288,6 +284,7 @@
avatarPath: this.model.getAvatarPath(), avatarPath: this.model.getAvatarPath(),
isGroup: !this.model.isPrivate(), isGroup: !this.model.isPrivate(),
isPublic: this.model.isPublic(), isPublic: this.model.isPublic(),
isAdmin: this.model.get('groupAdmins').includes(ourPK),
isRss: this.model.isRss(), isRss: this.model.isRss(),
memberCount: members.length, memberCount: members.length,
@ -303,8 +300,11 @@
this.$('.conversation-content-right').hide(); this.$('.conversation-content-right').hide();
}, },
onUpdateGroup: () => { onUpdateGroupName: () => {
window.Whisper.events.trigger('updateGroup', this.model); window.Whisper.events.trigger('updateGroupName', this.model);
},
onUpdateGroupMembers: () => {
window.Whisper.events.trigger('updateGroupMembers', this.model);
}, },
onLeaveGroup: () => { onLeaveGroup: () => {
@ -344,12 +344,15 @@
if (!this.groupSettings) { if (!this.groupSettings) {
this.groupSettings = new Whisper.ReactWrapperView({ this.groupSettings = new Whisper.ReactWrapperView({
className: 'group-settings', className: 'group-settings',
Component: window.Signal.Components.SessionChannelSettings, Component: window.Signal.Components.SessionGroupSettings,
props: getGroupSettingsProp(this.model), props: getGroupSettingsProps(this.model),
}); });
this.$('.conversation-content-right').append(this.groupSettings.el); this.$('.conversation-content-right').append(this.groupSettings.el);
this.updateGroupSettingsPanel = () =>
this.groupSettings.update(getGroupSettingsProps(this.model));
this.listenTo(this.model, 'change', this.updateGroupSettingsPanel);
} else { } else {
this.groupSettings.update(getGroupSettingsProp(this.model)); this.groupSettings.update(getGroupSettingsProps(this.model));
} }
this.$('.conversation-content-right').show(); this.$('.conversation-content-right').show();
}; };

@ -47,13 +47,13 @@
}, },
}); });
Whisper.UpdateGroupDialogView = Whisper.View.extend({ Whisper.UpdateGroupNameDialogView = Whisper.View.extend({
className: 'loki-dialog modal', className: 'loki-dialog modal',
initialize(groupConvo) { initialize(groupConvo) {
this.groupName = groupConvo.get('name'); this.groupName = groupConvo.get('name');
this.conversation = groupConvo; this.conversation = groupConvo;
this.titleText = `${i18n('updateGroupDialogTitle')}: ${this.groupName}`; this.titleText = i18n('updateGroupDialogTitle');
this.okText = i18n('ok'); this.okText = i18n('ok');
this.cancelText = i18n('cancel'); this.cancelText = i18n('cancel');
this.close = this.close.bind(this); this.close = this.close.bind(this);
@ -106,7 +106,90 @@
render() { render() {
this.dialogView = new Whisper.ReactWrapperView({ this.dialogView = new Whisper.ReactWrapperView({
className: 'create-group-dialog', className: 'create-group-dialog',
Component: window.Signal.Components.UpdateGroupDialog, Component: window.Signal.Components.UpdateGroupNameDialog,
props: {
titleText: this.titleText,
groupName: this.groupName,
okText: this.okText,
isPublic: this.isPublic,
cancelText: this.cancelText,
existingMembers: this.existingMembers,
isAdmin: this.isAdmin,
onClose: this.close,
onSubmit: this.onSubmit,
},
});
this.$el.append(this.dialogView.el);
return this;
},
onSubmit(newGroupName, members) {
const groupId = this.conversation.get('id');
window.doUpdateGroup(groupId, newGroupName, members);
},
close() {
this.remove();
},
});
Whisper.UpdateGroupMembersDialogView = Whisper.View.extend({
className: 'loki-dialog modal',
initialize(groupConvo) {
this.groupName = groupConvo.get('name');
this.conversation = groupConvo;
this.titleText = i18n('updateGroupDialogTitle');
this.okText = i18n('ok');
this.cancelText = i18n('cancel');
this.close = this.close.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.isPublic = groupConvo.isPublic();
const ourPK = textsecure.storage.user.getNumber();
this.isAdmin = groupConvo.get('groupAdmins').includes(ourPK);
const convos = window.getConversations().models.filter(d => !!d);
let existingMembers = groupConvo.get('members') || [];
// Show a contact if they are our friend or if they are a member
const friendsAndMembers = convos.filter(
d => existingMembers.includes(d.id) && d.isPrivate() && !d.isMe()
);
this.friendsAndMembers = _.uniq(friendsAndMembers, true, d => d.id);
// at least make sure it's an array
if (!Array.isArray(existingMembers)) {
existingMembers = [];
}
this.existingMembers = existingMembers;
// public chat settings overrides
if (this.isPublic) {
// fix the title
this.titleText = `${i18n('updatePublicGroupDialogTitle')}: ${
this.groupName
}`;
// I'd much prefer to integrate mods with groupAdmins
// but lets discuss first...
this.isAdmin = groupConvo.isModerator(
window.storage.get('primaryDevicePubKey')
);
// zero out friendList for now
this.friendsAndMembers = [];
this.existingMembers = [];
}
this.$el.focus();
this.render();
},
render() {
this.dialogView = new Whisper.ReactWrapperView({
className: 'create-group-dialog',
Component: window.Signal.Components.UpdateGroupMembersDialog,
props: { props: {
titleText: this.titleText, titleText: this.titleText,
groupName: this.groupName, groupName: this.groupName,
@ -124,12 +207,12 @@
this.$el.append(this.dialogView.el); this.$el.append(this.dialogView.el);
return this; return this;
}, },
onSubmit(newGroupName, newMembers) { onSubmit(groupName, newMembers) {
const ourPK = textsecure.storage.user.getNumber(); const ourPK = textsecure.storage.user.getNumber();
const allMembers = window.Lodash.concat(newMembers, [ourPK]); const allMembers = window.Lodash.concat(newMembers, [ourPK]);
const groupId = this.conversation.get('id'); const groupId = this.conversation.get('id');
window.doUpdateGroup(groupId, newGroupName, allMembers); window.doUpdateGroup(groupId, groupName, allMembers);
}, },
close() { close() {
this.remove(); this.remove();

@ -1,4 +1,4 @@
/* global Whisper */ /* global Whisper, _ */
// eslint-disable-next-line func-names // eslint-disable-next-line func-names
(function() { (function() {
@ -22,6 +22,8 @@
this.chatName = convo.get('name'); this.chatName = convo.get('name');
this.chatServer = convo.get('server'); this.chatServer = convo.get('server');
this.channelId = convo.get('channelId'); this.channelId = convo.get('channelId');
this.isPublic = !!convo.cachedProps.isPublic;
this.convo = convo;
this.$el.focus(); this.$el.focus();
this.render(); this.render();
@ -45,14 +47,56 @@
this.remove(); this.remove();
}, },
submit(pubkeys) { submit(pubkeys) {
window.sendGroupInvitations( // public group chats
{ if (this.isPublic) {
address: this.chatServer, window.sendGroupInvitations(
name: this.chatName, {
channelId: this.channelId, address: this.chatServer,
}, name: this.chatName,
pubkeys channelId: this.channelId,
); },
pubkeys
);
} else {
// private group chats
const ourPK = window.textsecure.storage.user.getNumber();
let existingMembers = this.convo.get('members') || [];
// at least make sure it's an array
if (!Array.isArray(existingMembers)) {
existingMembers = [];
}
existingMembers = existingMembers.filter(d => !!d);
const newMembers = pubkeys.filter(d => !existingMembers.includes(d));
if (newMembers.length > 0) {
// Do not trigger an update if there is too many members
if (
newMembers.length + existingMembers.length >
window.SMALL_GROUP_SIZE_LIMIT
) {
const msg = `${window.i18n('maxGroupMembersError')} ${
window.SMALL_GROUP_SIZE_LIMIT
}`;
window.pushToast({
title: msg,
type: 'error',
id: 'tooManyMembers',
});
return;
}
const allMembers = window.Lodash.concat(existingMembers, newMembers, [
ourPK,
]);
const uniqMembers = _.uniq(allMembers, true, d => d);
const groupId = this.convo.get('id');
const groupName = this.convo.get('name');
window.doUpdateGroup(groupId, groupName, uniqMembers);
}
}
}, },
}); });
})(); })();

@ -794,6 +794,15 @@ label {
} }
} }
.create-group-dialog .session-modal__body {
display: flex;
flex-direction: column;
.friend-selection-list {
width: unset;
}
}
.session-confirm { .session-confirm {
&-wrapper { &-wrapper {
.session-modal__body .session-modal__centered { .session-modal__body .session-modal__centered {

@ -32,7 +32,6 @@ interface Props {
phoneNumber: string; phoneNumber: string;
profileName?: string; profileName?: string;
color: string;
avatarPath?: string; avatarPath?: string;
isVerified: boolean; isVerified: boolean;
@ -88,7 +87,6 @@ interface Props {
onCopyPublicKey: () => void; onCopyPublicKey: () => void;
onUpdateGroup: () => void;
onLeaveGroup: () => void; onLeaveGroup: () => void;
onAddModerators: () => void; onAddModerators: () => void;
onRemoveModerators: () => void; onRemoveModerators: () => void;
@ -206,7 +204,6 @@ export class ConversationHeader extends React.Component<Props> {
public renderAvatar() { public renderAvatar() {
const { const {
avatarPath, avatarPath,
color,
i18n, i18n,
isGroup, isGroup,
isMe, isMe,
@ -223,7 +220,6 @@ export class ConversationHeader extends React.Component<Props> {
<span className="module-conversation-header__avatar"> <span className="module-conversation-header__avatar">
<Avatar <Avatar
avatarPath={avatarPath} avatarPath={avatarPath}
color={color}
conversationType={conversationType} conversationType={conversationType}
i18n={i18n} i18n={i18n}
noteToSelf={isMe} noteToSelf={isMe}
@ -305,7 +301,6 @@ export class ConversationHeader extends React.Component<Props> {
onDeleteMessages, onDeleteMessages,
onDeleteContact, onDeleteContact,
onCopyPublicKey, onCopyPublicKey,
onUpdateGroup,
onLeaveGroup, onLeaveGroup,
onAddModerators, onAddModerators,
onRemoveModerators, onRemoveModerators,
@ -323,9 +318,6 @@ export class ConversationHeader extends React.Component<Props> {
<MenuItem onClick={onCopyPublicKey}>{copyIdLabel}</MenuItem> <MenuItem onClick={onCopyPublicKey}>{copyIdLabel}</MenuItem>
) : null} ) : null}
<MenuItem onClick={onDeleteMessages}>{i18n('deleteMessages')}</MenuItem> <MenuItem onClick={onDeleteMessages}>{i18n('deleteMessages')}</MenuItem>
{isPrivateGroup || amMod ? (
<MenuItem onClick={onUpdateGroup}>{i18n('updateGroup')}</MenuItem>
) : null}
{amMod ? ( {amMod ? (
<MenuItem onClick={onAddModerators}>{i18n('addModerators')}</MenuItem> <MenuItem onClick={onAddModerators}>{i18n('addModerators')}</MenuItem>
) : null} ) : null}

@ -2,7 +2,8 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Contact, MemberList } from './MemberList'; import { Contact, MemberList } from './MemberList';
import { SessionModal } from './../session/SessionModal'; import { SessionModal } from '../session/SessionModal';
import { SessionButton } from '../session/SessionButton';
interface Props { interface Props {
titleText: string; titleText: string;
@ -21,12 +22,11 @@ interface Props {
interface State { interface State {
friendList: Array<Contact>; friendList: Array<Contact>;
groupName: string;
errorDisplayed: boolean; errorDisplayed: boolean;
errorMessage: string; errorMessage: string;
} }
export class UpdateGroupDialog extends React.Component<Props, State> { export class UpdateGroupMembersDialog extends React.Component<Props, State> {
constructor(props: any) { constructor(props: any) {
super(props); super(props);
@ -57,7 +57,6 @@ export class UpdateGroupDialog extends React.Component<Props, State> {
this.state = { this.state = {
friendList: friends, friendList: friends,
groupName: this.props.groupName,
errorDisplayed: false, errorDisplayed: false,
errorMessage: 'placeholder', errorMessage: 'placeholder',
}; };
@ -70,13 +69,7 @@ export class UpdateGroupDialog extends React.Component<Props, State> {
d => d.id d => d.id
); );
if (!this.state.groupName.trim()) { this.props.onSubmit(this.props.groupName, members);
this.onShowError(this.props.i18n('emptyGroupNameError'));
return;
}
this.props.onSubmit(this.state.groupName, members);
this.closeDialog(); this.closeDialog();
} }
@ -111,25 +104,16 @@ export class UpdateGroupDialog extends React.Component<Props, State> {
); );
return ( return (
<SessionModal title={titleText} onClose={() => null} onOk={() => null}> <SessionModal
title={titleText}
// tslint:disable-next-line: no-void-expression
onClose={() => this.closeDialog()}
onOk={() => null}
>
<div className="spacer-md" /> <div className="spacer-md" />
<p className={errorMessageClasses}>{errorMsg}</p> <p className={errorMessageClasses}>{errorMsg}</p>
<div className="spacer-md" /> <div className="spacer-md" />
<input
type="text"
id="group-name"
className="group-name"
placeholder={this.props.i18n('groupNamePlaceholder')}
value={this.state.groupName}
disabled={!this.props.isAdmin}
onChange={this.onGroupNameChanged}
tabIndex={0}
required={true}
aria-required={true}
autoFocus={true}
/>
<div className="friend-selection-list"> <div className="friend-selection-list">
<MemberList <MemberList
members={this.state.friendList} members={this.state.friendList}
@ -139,15 +123,13 @@ export class UpdateGroupDialog extends React.Component<Props, State> {
/> />
</div> </div>
<p className={noFriendsClasses}>{`(${this.props.i18n( <p className={noFriendsClasses}>{`(${this.props.i18n(
'noFriendsToAdd' 'noMembersInThisGroup'
)})`}</p> )})`}</p>
<div className="buttons">
<button className="cancel" tabIndex={0} onClick={this.closeDialog}> <div className="session-modal__button-group">
{cancelText} <SessionButton text={okText} onClick={this.onClickOK} />
</button>
<button className="ok" tabIndex={0} onClick={this.onClickOK}> <SessionButton text={cancelText} onClick={this.closeDialog} />
{okText}
</button>
</div> </div>
</SessionModal> </SessionModal>
); );

@ -0,0 +1,148 @@
import React from 'react';
import classNames from 'classnames';
import { SessionModal } from '../session/SessionModal';
import { SessionButton } from '../session/SessionButton';
interface Props {
titleText: string;
groupName: string;
okText: string;
cancelText: string;
isAdmin: boolean;
i18n: any;
onSubmit: any;
onClose: any;
existingMembers: Array<String>;
}
interface State {
groupName: string;
errorDisplayed: boolean;
errorMessage: string;
}
export class UpdateGroupNameDialog extends React.Component<Props, State> {
constructor(props: any) {
super(props);
this.onClickOK = this.onClickOK.bind(this);
this.onKeyUp = this.onKeyUp.bind(this);
this.closeDialog = this.closeDialog.bind(this);
this.onGroupNameChanged = this.onGroupNameChanged.bind(this);
this.state = {
groupName: this.props.groupName,
errorDisplayed: false,
errorMessage: 'placeholder',
};
window.addEventListener('keyup', this.onKeyUp);
}
public onClickOK() {
if (!this.state.groupName.trim()) {
this.onShowError(this.props.i18n('emptyGroupNameError'));
return;
}
this.props.onSubmit(this.state.groupName, this.props.existingMembers);
this.closeDialog();
}
public render() {
const okText = this.props.okText;
const cancelText = this.props.cancelText;
let titleText;
titleText = `${this.props.titleText}`;
const errorMsg = this.state.errorMessage;
const errorMessageClasses = classNames(
'error-message',
this.state.errorDisplayed ? 'error-shown' : 'error-faded'
);
return (
<SessionModal
title={titleText}
// tslint:disable-next-line: no-void-expression
onClose={() => this.closeDialog()}
onOk={() => null}
>
<div className="spacer-md" />
<p className={errorMessageClasses}>{errorMsg}</p>
<div className="spacer-md" />
<input
type="text"
className="profile-name-input"
value={this.state.groupName}
placeholder={this.props.i18n('groupNamePlaceholder')}
onChange={this.onGroupNameChanged}
tabIndex={0}
required={true}
aria-required={true}
autoFocus={true}
disabled={!this.props.isAdmin}
/>
<div className="session-modal__button-group">
<SessionButton text={okText} onClick={this.onClickOK} />
<SessionButton text={cancelText} onClick={this.closeDialog} />
</div>
</SessionModal>
);
}
private onShowError(msg: string) {
if (this.state.errorDisplayed) {
return;
}
this.setState({
errorDisplayed: true,
errorMessage: msg,
});
setTimeout(() => {
this.setState({
errorDisplayed: false,
});
}, 3000);
}
private onKeyUp(event: any) {
switch (event.key) {
case 'Enter':
this.onClickOK();
break;
case 'Esc':
case 'Escape':
this.closeDialog();
break;
default:
}
}
private closeDialog() {
window.removeEventListener('keyup', this.onKeyUp);
this.props.onClose();
}
private onGroupNameChanged(event: any) {
event.persist();
this.setState(state => {
return {
...state,
groupName: event.target.value,
};
});
}
}

@ -19,15 +19,18 @@ interface Props {
avatarPath: string; avatarPath: string;
timerOptions: Array<TimerOption>; timerOptions: Array<TimerOption>;
isPublic: boolean; isPublic: boolean;
isAdmin: boolean;
onGoBack: () => void; onGoBack: () => void;
onInviteFriends: () => void; onInviteFriends: () => void;
onLeaveGroup: () => void; onLeaveGroup: () => void;
onUpdateGroupName: () => void;
onUpdateGroupMembers: () => void;
onShowLightBox: (options: any) => void; onShowLightBox: (options: any) => void;
onSetDisappearingMessages: (seconds: number) => void; onSetDisappearingMessages: (seconds: number) => void;
} }
export class SessionChannelSettings extends React.Component<Props, any> { export class SessionGroupSettings extends React.Component<Props, any> {
public constructor(props: Props) { public constructor(props: Props) {
super(props); super(props);
@ -207,6 +210,7 @@ export class SessionChannelSettings extends React.Component<Props, any> {
timerOptions, timerOptions,
onLeaveGroup, onLeaveGroup,
isPublic, isPublic,
isAdmin,
} = this.props; } = this.props;
const { documents, media, onItemClick } = this.state; const { documents, media, onItemClick } = this.state;
const showMemberCount = !!(memberCount && memberCount > 0); const showMemberCount = !!(memberCount && memberCount > 0);
@ -231,7 +235,7 @@ export class SessionChannelSettings extends React.Component<Props, any> {
{showMemberCount && ( {showMemberCount && (
<> <>
<div className="spacer-lg" /> <div className="spacer-lg" />
<div className="text-subtle"> <div role="button" className="text-subtle">
{window.i18n('members', memberCount)} {window.i18n('members', memberCount)}
</div> </div>
<div className="spacer-lg" /> <div className="spacer-lg" />
@ -241,7 +245,26 @@ export class SessionChannelSettings extends React.Component<Props, any> {
className="description" className="description"
placeholder={window.i18n('description')} placeholder={window.i18n('description')}
/> />
{!isPublic && (
<>
{isAdmin && (
<div
className="group-settings-item"
role="button"
onClick={this.props.onUpdateGroupName}
>
{window.i18n('editGroupName')}
</div>
)}
<div
className="group-settings-item"
role="button"
onClick={this.props.onUpdateGroupMembers}
>
{window.i18n('showMembers')}
</div>
</>
)}
<div className="group-settings-item"> <div className="group-settings-item">
{window.i18n('notifications')} {window.i18n('notifications')}
</div> </div>
@ -269,8 +292,16 @@ export class SessionChannelSettings extends React.Component<Props, any> {
} }
private renderHeader() { private renderHeader() {
const { id, onGoBack, onInviteFriends, avatarPath } = this.props; const {
const shouldShowInviteFriends = !this.props.isPublic; id,
onGoBack,
onInviteFriends,
avatarPath,
isAdmin,
isPublic,
} = this.props;
const showInviteFriends = isPublic || isAdmin;
return ( return (
<div className="group-settings-header"> <div className="group-settings-header">
@ -286,9 +317,8 @@ export class SessionChannelSettings extends React.Component<Props, any> {
conversationType="group" conversationType="group"
size={80} size={80}
/> />
<div className="invite-friends-container"> <div className="invite-friends-container">
{shouldShowInviteFriends && ( {showInviteFriends && (
<SessionIconButton <SessionIconButton
iconType={SessionIconType.AddUser} iconType={SessionIconType.AddUser}
iconSize={SessionIconSize.Medium} iconSize={SessionIconSize.Medium}
Loading…
Cancel
Save