invite contacts dialog functioning.

pull/1665/head^2
Warrick Corfe-Tan 4 years ago
parent 59b02a5ed4
commit 8c0bec7a97

@ -419,34 +419,34 @@
window.setMediaPermissions(!value); window.setMediaPermissions(!value);
}; };
Whisper.events.on('updateGroupName', async groupConvo => { // Whisper.events.on('updateGroupName', async groupConvo => {
if (appView) { // if (appView) {
appView.showUpdateGroupNameDialog(groupConvo); // appView.showUpdateGroupNameDialog(groupConvo);
} // }
}); // });
Whisper.events.on('updateGroupMembers', async groupConvo => { // Whisper.events.on('updateGroupMembers', async groupConvo => {
if (appView) { // if (appView) {
appView.showUpdateGroupMembersDialog(groupConvo); // appView.showUpdateGroupMembersDialog(groupConvo);
} // }
}); // });
Whisper.events.on('inviteContacts', async groupConvo => { // Whisper.events.on('inviteContacts', async groupConvo => {
if (appView) { // if (appView) {
appView.showInviteContactsDialog(groupConvo); // appView.showInviteContactsDialog(groupConvo);
} // }
}); // });
Whisper.events.on('addModerators', async groupConvo => { // Whisper.events.on('addModerators', async groupConvo => {
if (appView) { // if (appView) {
appView.showAddModeratorsDialog(groupConvo); // appView.showAddModeratorsDialog(groupConvo);
} // }
}); // });
Whisper.events.on('removeModerators', async groupConvo => { // Whisper.events.on('removeModerators', async groupConvo => {
if (appView) { // if (appView) {
appView.showRemoveModeratorsDialog(groupConvo); // appView.showRemoveModeratorsDialog(groupConvo);
} // }
}); // });
Whisper.events.on('leaveClosedGroup', async groupConvo => { Whisper.events.on('leaveClosedGroup', async groupConvo => {
if (appView) { if (appView) {

@ -128,68 +128,68 @@
const theme = themeSettings === 'light' ? window.lightTheme : window.darkTheme; const theme = themeSettings === 'light' ? window.lightTheme : window.darkTheme;
return theme; return theme;
}, },
showUpdateGroupNameDialog(groupConvo) { // showUpdateGroupNameDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign // // eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject(); // groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.UpdateGroupNameDialogView(groupConvo); // const dialog = new Whisper.UpdateGroupNameDialogView(groupConvo);
this.el.append(dialog.el); // this.el.append(dialog.el);
}, // },
showUpdateGroupMembersDialog(groupConvo) { // showUpdateGroupMembersDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign // // eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject(); // groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.UpdateGroupMembersDialogView(groupConvo); // const dialog = new Whisper.UpdateGroupMembersDialogView(groupConvo);
this.el.append(dialog.el); // this.el.append(dialog.el);
}, // },
showLeaveGroupDialog(groupConvo) { // showLeaveGroupDialog(groupConvo) {
if (!groupConvo.isGroup()) { // if (!groupConvo.isGroup()) {
throw new Error('showLeaveGroupDialog() called with a non group convo.'); // throw new Error('showLeaveGroupDialog() called with a non group convo.');
} // }
const title = i18n('leaveGroup'); // const title = i18n('leaveGroup');
const message = i18n('leaveGroupConfirmation'); // const message = i18n('leaveGroupConfirmation');
const ourPK = window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache(); // const ourPK = window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache();
const isAdmin = (groupConvo.get('groupAdmins') || []).includes(ourPK); // const isAdmin = (groupConvo.get('groupAdmins') || []).includes(ourPK);
const isClosedGroup = groupConvo.get('is_medium_group') || false; // const isClosedGroup = groupConvo.get('is_medium_group') || false;
// if this is not a closed group, or we are not admin, we can just show a confirmation dialog // // if this is not a closed group, or we are not admin, we can just show a confirmation dialog
if (!isClosedGroup || (isClosedGroup && !isAdmin)) { // if (!isClosedGroup || (isClosedGroup && !isAdmin)) {
window.confirmationDialog({ // window.confirmationDialog({
title, // title,
message, // message,
resolve: () => groupConvo.leaveClosedGroup(), // resolve: () => groupConvo.leaveClosedGroup(),
theme: this.getThemeObject(), // theme: this.getThemeObject(),
}); // });
} else { // } else {
// we are the admin on a closed group. We have to warn the user about the group Deletion // // we are the admin on a closed group. We have to warn the user about the group Deletion
this.showAdminLeaveClosedGroupDialog(groupConvo); // this.showAdminLeaveClosedGroupDialog(groupConvo);
} // }
}, // },
showInviteContactsDialog(groupConvo) { // showInviteContactsDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign // // eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject(); // groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.InviteContactsDialogView(groupConvo); // const dialog = new Whisper.InviteContactsDialogView(groupConvo);
this.el.append(dialog.el); // this.el.append(dialog.el);
}, // },
showAdminLeaveClosedGroupDialog(groupConvo) { // showAdminLeaveClosedGroupDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign // // eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject(); // groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.AdminLeaveClosedGroupDialog(groupConvo); // const dialog = new Whisper.AdminLeaveClosedGroupDialog(groupConvo);
this.el.append(dialog.el); // this.el.append(dialog.el);
}, // },
showAddModeratorsDialog(groupConvo) { // showAddModeratorsDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign // // eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject(); // groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.AddModeratorsDialogView(groupConvo); // const dialog = new Whisper.AddModeratorsDialogView(groupConvo);
this.el.append(dialog.el); // this.el.append(dialog.el);
}, // },
showRemoveModeratorsDialog(groupConvo) { // showRemoveModeratorsDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign // // eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject(); // groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.RemoveModeratorsDialogView(groupConvo); // const dialog = new Whisper.RemoveModeratorsDialogView(groupConvo);
this.el.append(dialog.el); // this.el.append(dialog.el);
}, // },
}); });
})(); })();

@ -1,58 +1,58 @@
/* global Whisper */ // /* global Whisper */
// eslint-disable-next-line func-names // // eslint-disable-next-line func-names
(function() { // (function() {
'use strict'; // 'use strict';
window.Whisper = window.Whisper || {}; // window.Whisper = window.Whisper || {};
Whisper.InviteContactsDialogView = Whisper.View.extend({ // Whisper.InviteContactsDialogView = Whisper.View.extend({
className: 'loki-dialog modal', // className: 'loki-dialog modal',
initialize(convo) { // initialize(convo) {
this.close = this.close.bind(this); // this.close = this.close.bind(this);
this.theme = convo.theme; // this.theme = convo.theme;
const convos = window.getConversationController().getConversations(); // const convos = window.getConversationController().getConversations();
this.contacts = convos.filter( // this.contacts = convos.filter(
d => !!d && !d.isBlocked() && d.isPrivate() && !d.isMe() && !!d.get('active_at') // d => !!d && !d.isBlocked() && d.isPrivate() && !d.isMe() && !!d.get('active_at')
); // );
if (!convo.isPublic()) { // if (!convo.isPublic()) {
// filter our zombies and current members from the list of contact we can add // // filter our zombies and current members from the list of contact we can add
const members = convo.get('members') || []; // const members = convo.get('members') || [];
const zombies = convo.get('zombies') || []; // const zombies = convo.get('zombies') || [];
this.contacts = this.contacts.filter( // this.contacts = this.contacts.filter(
d => !members.includes(d.id) && !zombies.includes(d.id) // d => !members.includes(d.id) && !zombies.includes(d.id)
); // );
} // }
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.isPublic(); // this.isPublic = !!convo.isPublic();
this.convo = convo; // this.convo = convo;
this.$el.focus(); // this.$el.focus();
this.render(); // this.render();
}, // },
render() { // render() {
const view = new Whisper.ReactWrapperView({ // const view = new Whisper.ReactWrapperView({
className: 'invite-friends-dialog', // className: 'invite-friends-dialog',
Component: window.Signal.Components.InviteContactsDialog, // Component: window.Signal.Components.InviteContactsDialog,
props: { // props: {
contactList: this.contacts, // contactList: this.contacts,
onClose: this.close, // onClose: this.close,
chatName: this.chatName, // chatName: this.chatName,
theme: this.theme, // theme: this.theme,
convo: this.convo, // convo: this.convo,
}, // },
}); // });
this.$el.append(view.el); // this.$el.append(view.el);
return this; // return this;
}, // },
close() { // close() {
this.remove(); // this.remove();
}, // },
}); // });
})(); // })();

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import { SessionModal } from '../session/SessionModal'; import { SessionModal } from '../session/SessionModal';
import { SessionButton, SessionButtonColor } from '../session/SessionButton'; import { SessionButton, SessionButtonColor } from '../session/SessionButton';
@ -10,11 +10,12 @@ import { initiateGroupUpdate } from '../../session/group';
import { ConversationModel, ConversationTypeEnum } from '../../models/conversation'; import { ConversationModel, ConversationTypeEnum } from '../../models/conversation';
import { getCompleteUrlForV2ConvoId } from '../../interactions/conversation'; import { getCompleteUrlForV2ConvoId } from '../../interactions/conversation';
import _ from 'lodash'; import _ from 'lodash';
import autoBind from 'auto-bind';
import { VALIDATION } from '../../session/constants'; import { VALIDATION } from '../../session/constants';
import { SessionWrapperModal } from '../session/SessionWrapperModal';
interface Props { interface Props {
contactList: Array<any>; // contactList: Array<any>;
chatName: string;
onClose: any; onClose: any;
theme: DefaultTheme; theme: DefaultTheme;
convo: ConversationModel; convo: ConversationModel;
@ -24,22 +25,38 @@ interface State {
contactList: Array<ContactType>; contactList: Array<ContactType>;
} }
class InviteContactsDialogInner extends React.Component<Props, State> {
constructor(props: any) {
super(props);
autoBind(this); const InviteContactsDialogInner = (props: Props) => {
const { convo, onClose, theme } = props;
let contacts = ConversationController.getInstance().getConversations().filter(
d => !!d && !d.isBlocked() && d.isPrivate() && !d.isMe() && !!d.get('active_at')
);
if (!convo.isPublic()) {
// filter our zombies and current members from the list of contact we can add
const members = convo.get('members') || [];
const zombies = convo.get('zombies') || [];
contacts = contacts.filter(
d => !members.includes(d.id) && !zombies.includes(d.id)
);
}
let contacts = this.props.contactList; const chatName = convo.get('name');
// const chatServer = convo.get('server');
// const channelId = convo.get('channelId');
const isPublicConvo = convo.isPublic();
contacts = contacts.map(d => { const [contactList, setContactList] = useState(
contacts.map((d: ConversationModel) => {
const lokiProfile = d.getLokiProfile(); const lokiProfile = d.getLokiProfile();
const nickname = d.getNickname(); const nickname = d.getNickname();
const name = nickname const name = nickname
? nickname ? nickname
: lokiProfile : lokiProfile
? lokiProfile.displayName ? lokiProfile.displayName
: window.i18n('anonymous'); : window.i18n('anonymous');
// TODO: should take existing members into account // TODO: should take existing members into account
const existingMember = false; const existingMember = false;
@ -48,58 +65,58 @@ class InviteContactsDialogInner extends React.Component<Props, State> {
id: d.id, id: d.id,
authorPhoneNumber: d.id, authorPhoneNumber: d.id,
authorProfileName: name, authorProfileName: name,
authorAvatarPath: d?.getAvatarPath(), authorAvatarPath: d?.getAvatarPath() || '',
selected: false, selected: false,
authorName: name, authorName: name,
checkmarked: false, checkmarked: false,
existingMember, existingMember,
}; };
}); })
)
this.state = {
contactList: contacts,
};
window.addEventListener('keyup', this.onKeyUp); const closeDialog = () => {
window.removeEventListener('keyup', onKeyUp);
onClose();
} }
public render() { const onClickOK = () => {
const titleText = `${window.i18n('addingContacts')} ${this.props.chatName}`; const selectedContacts = contactList.filter((d: ContactType) => d.checkmarked).map((d: ContactType) => d.id);
const cancelText = window.i18n('cancel');
const okText = window.i18n('ok'); if (selectedContacts.length > 0) {
if (isPublicConvo) {
const hasContacts = this.state.contactList.length !== 0; void submitForOpenGroup(selectedContacts);
} else {
return ( void submitForClosedGroup(selectedContacts);
<SessionModal title={titleText} onClose={this.closeDialog} theme={this.props.theme}> }
<div className="spacer-lg" /> }
<div className="contact-selection-list">{this.renderMemberList()}</div> closeDialog();
{hasContacts ? null : (
<>
<div className="spacer-lg" />
<p className="no-contacts">{window.i18n('noContactsToAdd')}</p>
<div className="spacer-lg" />
</>
)}
<div className="spacer-lg" />
<div className="session-modal__button-group">
<SessionButton text={cancelText} onClick={this.closeDialog} />
<SessionButton
text={okText}
disabled={!hasContacts}
onClick={this.onClickOK}
buttonColor={SessionButtonColor.Green}
/>
</div>
</SessionModal>
);
} }
private async submitForOpenGroup(pubkeys: Array<string>) { const onKeyUp = (event: any) => {
const { convo } = this.props; switch (event.key) {
case 'Enter':
onClickOK();
break;
case 'Esc':
case 'Escape':
closeDialog();
break;
default:
}
}
window.addEventListener('keyup', onKeyUp);
const titleText = `${window.i18n('addingContacts')} ${chatName}`;
const cancelText = window.i18n('cancel');
const okText = window.i18n('ok');
const hasContacts = contactList.length !== 0;
const submitForOpenGroup = async (pubkeys: Array<string>) => {
const { convo } = props;
if (convo.isOpenGroupV1()) { if (convo.isOpenGroupV1()) {
const v1 = convo.toOpenGroupV1(); const v1 = convo.toOpenGroupV1();
const groupInvitation = { const groupInvitation = {
@ -137,8 +154,7 @@ class InviteContactsDialogInner extends React.Component<Props, State> {
} }
} }
private async submitForClosedGroup(pubkeys: Array<string>) { const submitForClosedGroup = async (pubkeys: Array<string>) => {
const { convo } = this.props;
// closed group chats // closed group chats
const ourPK = UserUtils.getOurPubKeyStrFromCache(); const ourPK = UserUtils.getOurPubKeyStrFromCache();
@ -178,23 +194,10 @@ class InviteContactsDialogInner extends React.Component<Props, State> {
} }
} }
private onClickOK() {
const selectedContacts = this.state.contactList.filter(d => d.checkmarked).map(d => d.id);
if (selectedContacts.length > 0) { const renderMemberList = () => {
if (this.props.convo.isPublic()) { const members = contactList;
void this.submitForOpenGroup(selectedContacts); const selectedContacts = contactList.filter((d: ContactType) => d.checkmarked).map((d: ContactType) => d.id);
} else {
void this.submitForClosedGroup(selectedContacts);
}
}
this.closeDialog();
}
private renderMemberList() {
const members = this.state.contactList;
const selectedContacts = this.state.contactList.filter(d => d.checkmarked).map(d => d.id);
return members.map((member: ContactType, index: number) => ( return members.map((member: ContactType, index: number) => (
<SessionMemberListItem <SessionMemberListItem
@ -203,50 +206,56 @@ class InviteContactsDialogInner extends React.Component<Props, State> {
index={index} index={index}
isSelected={selectedContacts.some(m => m === member.id)} isSelected={selectedContacts.some(m => m === member.id)}
onSelect={(selectedMember: ContactType) => { onSelect={(selectedMember: ContactType) => {
this.onMemberClicked(selectedMember); onMemberClicked(selectedMember);
}} }}
onUnselect={(selectedMember: ContactType) => { onUnselect={(selectedMember: ContactType) => {
this.onMemberClicked(selectedMember); onMemberClicked(selectedMember);
}} }}
theme={this.props.theme} theme={theme}
/> />
)); ));
} }
private onKeyUp(event: any) {
switch (event.key) {
case 'Enter':
this.onClickOK();
break;
case 'Esc':
case 'Escape':
this.closeDialog();
break;
default:
}
}
private onMemberClicked(clickedMember: ContactType) { const onMemberClicked = (clickedMember: ContactType) => {
const updatedContacts = this.state.contactList.map(member => { const updatedContacts = contactList.map((member: ContactType) => {
if (member.id === clickedMember.id) { if (member.id === clickedMember.id) {
return { ...member, checkmarked: !member.checkmarked }; return { ...member, checkmarked: !member.checkmarked };
} else { } else {
return member; return member;
} }
}); });
setContactList(updatedContacts);
this.setState(state => {
return {
...state,
contactList: updatedContacts,
};
});
} }
private closeDialog() {
window.removeEventListener('keyup', this.onKeyUp); return (
this.props.onClose(); <SessionWrapperModal title={titleText} onClose={closeDialog} theme={props.theme}>
} <div className="spacer-lg" />
<div className="contact-selection-list">{renderMemberList()}</div>
{hasContacts ? null : (
<>
<div className="spacer-lg" />
<p className="no-contacts">{window.i18n('noContactsToAdd')}</p>
<div className="spacer-lg" />
</>
)}
<div className="spacer-lg" />
<div className="session-modal__button-group">
<SessionButton text={cancelText} onClick={closeDialog} />
<SessionButton
text={okText}
disabled={!hasContacts}
onClick={onClickOK}
buttonColor={SessionButtonColor.Green}
/>
</div>
</SessionWrapperModal>
);
} }
export const InviteContactsDialog = InviteContactsDialogInner; export const InviteContactsDialog = InviteContactsDialogInner;

@ -38,6 +38,7 @@ import { UpdateGroupNameDialog } from '../../conversation/UpdateGroupNameDialog'
import { UpdateGroupMembersDialog } from '../../conversation/UpdateGroupMembersDialog'; import { UpdateGroupMembersDialog } from '../../conversation/UpdateGroupMembersDialog';
import { getOurNumber } from '../../../state/selectors/user'; import { getOurNumber } from '../../../state/selectors/user';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { InviteContactsDialog } from '../../conversation/InviteContactsDialog';
@ -508,9 +509,10 @@ export class SessionConversation extends React.Component<Props, State> {
let isAdmin = true; let isAdmin = true;
let titleText; let titleText;
titleText = window.i18n('updateGroupDialogTitle', groupName);
if (isPublic) { if (isPublic) {
// fix the title // fix the title
titleText = window.i18n('updateGroupDialogTitle', groupName);
// I'd much prefer to integrate mods with groupAdmins // I'd much prefer to integrate mods with groupAdmins
// but lets discuss first... // but lets discuss first...
isAdmin = conversation.isAdmin(window.storage.get('primaryDevicePubKey')); isAdmin = conversation.isAdmin(window.storage.get('primaryDevicePubKey'));
@ -692,7 +694,16 @@ export class SessionConversation extends React.Component<Props, State> {
// warrick: delete old code // warrick: delete old code
}, },
onInviteContacts: () => { onInviteContacts: () => {
window.Whisper.events.trigger('inviteContacts', conversation); this.setState({
...this.state,
modal: (
<InviteContactsDialog
convo={conversation}
onClose={() => this.setState({ ...this.state, modal: null })}
theme={this.props.theme}
/>)
})
}, },
onLeaveGroup: () => { onLeaveGroup: () => {
window.Whisper.events.trigger('leaveClosedGroup', conversation); window.Whisper.events.trigger('leaveClosedGroup', conversation);
@ -706,7 +717,7 @@ export class SessionConversation extends React.Component<Props, State> {
convo={conversation} convo={conversation}
onClose={() => this.setState({ ...this.state, modal: null })} onClose={() => this.setState({ ...this.state, modal: null })}
theme={this.props.theme} theme={this.props.theme}
></AddModeratorsDialog>) />)
}) })
}, },
@ -719,7 +730,7 @@ export class SessionConversation extends React.Component<Props, State> {
convo={conversation} convo={conversation}
onClose={() => this.setState({ ...this.state, modal: null })} onClose={() => this.setState({ ...this.state, modal: null })}
theme={this.props.theme} theme={this.props.theme}
></RemoveModeratorsDialog>) />)
}) })
}, },
onShowLightBox: (lightBoxOptions = {}) => { onShowLightBox: (lightBoxOptions = {}) => {

Loading…
Cancel
Save