Merge branch 'checkpoint' into onion-paths

pull/1665/head
Warrick Corfe-Tan 4 years ago
commit 18566aeff6

@ -139,10 +139,10 @@
<!-- DIALOGS-->
<!-- <script type='text/javascript' src='js/views/update_group_dialog_view.js'></script> -->
<script type='text/javascript' src='js/views/invite_contacts_dialog_view.js'></script>
<script type='text/javascript' src='js/views/admin_leave_closed_group_dialog_view.js'></script>
<!-- <script type='text/javascript' src='js/views/invite_contacts_dialog_view.js'></script> -->
<!-- <script type='text/javascript' src='js/views/admin_leave_closed_group_dialog_view.js'></script> -->
<script type='text/javascript' src='js/views/user_details_dialog_view.js'></script>
<!-- <script type='text/javascript' src='js/views/user_details_dialog_view.js'></script> -->
<script type='text/javascript' src='js/views/session_id_reset_view.js'></script>
<!-- CRYPTO -->

@ -419,40 +419,40 @@
window.setMediaPermissions(!value);
};
Whisper.events.on('updateGroupName', async groupConvo => {
if (appView) {
appView.showUpdateGroupNameDialog(groupConvo);
}
});
Whisper.events.on('updateGroupMembers', async groupConvo => {
if (appView) {
appView.showUpdateGroupMembersDialog(groupConvo);
}
});
Whisper.events.on('inviteContacts', async groupConvo => {
if (appView) {
appView.showInviteContactsDialog(groupConvo);
}
});
Whisper.events.on('addModerators', async groupConvo => {
if (appView) {
appView.showAddModeratorsDialog(groupConvo);
}
});
Whisper.events.on('removeModerators', async groupConvo => {
if (appView) {
appView.showRemoveModeratorsDialog(groupConvo);
}
});
Whisper.events.on('leaveClosedGroup', async groupConvo => {
if (appView) {
appView.showLeaveGroupDialog(groupConvo);
}
});
// Whisper.events.on('updateGroupName', async groupConvo => {
// if (appView) {
// appView.showUpdateGroupNameDialog(groupConvo);
// }
// });
// Whisper.events.on('updateGroupMembers', async groupConvo => {
// if (appView) {
// appView.showUpdateGroupMembersDialog(groupConvo);
// }
// });
// Whisper.events.on('inviteContacts', async groupConvo => {
// if (appView) {
// appView.showInviteContactsDialog(groupConvo);
// }
// });
// Whisper.events.on('addModerators', async groupConvo => {
// if (appView) {
// appView.showAddModeratorsDialog(groupConvo);
// }
// });
// Whisper.events.on('removeModerators', async groupConvo => {
// if (appView) {
// appView.showRemoveModeratorsDialog(groupConvo);
// }
// });
// Whisper.events.on('leaveClosedGroup', async groupConvo => {
// if (appView) {
// appView.showLeaveGroupDialog(groupConvo);
// }
// });
Whisper.Notifications.on('click', (id, messageId) => {
window.showWindow();
@ -471,28 +471,28 @@
});
});
Whisper.events.on('onShowUserDetails', async ({ userPubKey }) => {
const conversation = await window
.getConversationController()
.getOrCreateAndWait(userPubKey, 'private');
const avatarPath = conversation.getAvatarPath();
const profile = conversation.getLokiProfile();
const displayName = profile && profile.displayName;
if (appView) {
appView.showUserDetailsDialog({
profileName: displayName,
pubkey: userPubKey,
avatarPath,
onStartConversation: () => {
window.inboxStore.dispatch(
window.actionsCreators.openConversationExternal(conversation.id)
);
},
});
}
});
// Whisper.events.on('onShowUserDetails', async ({ userPubKey }) => {
// const conversation = await window
// .getConversationController()
// .getOrCreateAndWait(userPubKey, 'private');
// const avatarPath = conversation.getAvatarPath();
// const profile = conversation.getLokiProfile();
// const displayName = profile && profile.displayName;
// if (appView) {
// appView.showUserDetailsDialog({
// profileName: displayName,
// pubkey: userPubKey,
// avatarPath,
// onStartConversation: () => {
// window.inboxStore.dispatch(
// window.actionsCreators.openConversationExternal(conversation.id)
// );
// },
// });
// }
// });
Whisper.events.on('password-updated', () => {

@ -117,79 +117,79 @@
this.el.prepend(resetSessionIDDialog.el);
},
showUserDetailsDialog(options) {
// eslint-disable-next-line no-param-reassign
options.theme = this.getThemeObject();
const dialog = new Whisper.UserDetailsDialogView(options);
this.el.prepend(dialog.el);
},
// showUserDetailsDialog(options) {
// // eslint-disable-next-line no-param-reassign
// options.theme = this.getThemeObject();
// const dialog = new Whisper.UserDetailsDialogView(options);
// this.el.prepend(dialog.el);
// },
getThemeObject() {
const themeSettings = storage.get('theme-setting') || 'light';
const theme = themeSettings === 'light' ? window.lightTheme : window.darkTheme;
return theme;
},
showUpdateGroupNameDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.UpdateGroupNameDialogView(groupConvo);
this.el.append(dialog.el);
},
showUpdateGroupMembersDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.UpdateGroupMembersDialogView(groupConvo);
this.el.append(dialog.el);
},
showLeaveGroupDialog(groupConvo) {
if (!groupConvo.isGroup()) {
throw new Error('showLeaveGroupDialog() called with a non group convo.');
}
const title = i18n('leaveGroup');
const message = i18n('leaveGroupConfirmation');
const ourPK = window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache();
const isAdmin = (groupConvo.get('groupAdmins') || []).includes(ourPK);
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 (!isClosedGroup || (isClosedGroup && !isAdmin)) {
window.confirmationDialog({
title,
message,
resolve: () => groupConvo.leaveClosedGroup(),
theme: this.getThemeObject(),
});
} else {
// we are the admin on a closed group. We have to warn the user about the group Deletion
this.showAdminLeaveClosedGroupDialog(groupConvo);
}
},
showInviteContactsDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.InviteContactsDialogView(groupConvo);
this.el.append(dialog.el);
},
showAdminLeaveClosedGroupDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.AdminLeaveClosedGroupDialog(groupConvo);
this.el.append(dialog.el);
},
showAddModeratorsDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.AddModeratorsDialogView(groupConvo);
this.el.append(dialog.el);
},
showRemoveModeratorsDialog(groupConvo) {
// eslint-disable-next-line no-param-reassign
groupConvo.theme = this.getThemeObject();
const dialog = new Whisper.RemoveModeratorsDialogView(groupConvo);
this.el.append(dialog.el);
},
// showUpdateGroupNameDialog(groupConvo) {
// // eslint-disable-next-line no-param-reassign
// groupConvo.theme = this.getThemeObject();
// const dialog = new Whisper.UpdateGroupNameDialogView(groupConvo);
// this.el.append(dialog.el);
// },
// showUpdateGroupMembersDialog(groupConvo) {
// // eslint-disable-next-line no-param-reassign
// groupConvo.theme = this.getThemeObject();
// const dialog = new Whisper.UpdateGroupMembersDialogView(groupConvo);
// this.el.append(dialog.el);
// },
// showLeaveGroupDialog(groupConvo) {
// if (!groupConvo.isGroup()) {
// throw new Error('showLeaveGroupDialog() called with a non group convo.');
// }
// const title = i18n('leaveGroup');
// const message = i18n('leaveGroupConfirmation');
// const ourPK = window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache();
// const isAdmin = (groupConvo.get('groupAdmins') || []).includes(ourPK);
// 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 (!isClosedGroup || (isClosedGroup && !isAdmin)) {
// window.confirmationDialog({
// title,
// message,
// resolve: () => groupConvo.leaveClosedGroup(),
// theme: this.getThemeObject(),
// });
// } else {
// // we are the admin on a closed group. We have to warn the user about the group Deletion
// this.showAdminLeaveClosedGroupDialog(groupConvo);
// }
// },
// showInviteContactsDialog(groupConvo) {
// // eslint-disable-next-line no-param-reassign
// groupConvo.theme = this.getThemeObject();
// const dialog = new Whisper.InviteContactsDialogView(groupConvo);
// this.el.append(dialog.el);
// },
// showAdminLeaveClosedGroupDialog(groupConvo) {
// // eslint-disable-next-line no-param-reassign
// groupConvo.theme = this.getThemeObject();
// const dialog = new Whisper.AdminLeaveClosedGroupDialog(groupConvo);
// this.el.append(dialog.el);
// },
// showAddModeratorsDialog(groupConvo) {
// // eslint-disable-next-line no-param-reassign
// groupConvo.theme = this.getThemeObject();
// const dialog = new Whisper.AddModeratorsDialogView(groupConvo);
// this.el.append(dialog.el);
// },
// showRemoveModeratorsDialog(groupConvo) {
// // eslint-disable-next-line no-param-reassign
// groupConvo.theme = this.getThemeObject();
// const dialog = new Whisper.RemoveModeratorsDialogView(groupConvo);
// this.el.append(dialog.el);
// },
});
})();

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

@ -5,6 +5,10 @@ import { SessionModal } from './session/SessionModal';
import { SessionButton, SessionButtonColor, SessionButtonType } from './session/SessionButton';
import { SessionIdEditable } from './session/SessionIdEditable';
import { DefaultTheme } from 'styled-components';
import { ConversationController } from '../session/conversations';
import { ConversationTypeEnum } from '../models/conversation';
import { Session } from 'electron';
import { SessionWrapperModal } from './session/SessionWrapperModal';
interface Props {
i18n: any;
@ -12,7 +16,7 @@ interface Props {
avatarPath: string;
pubkey: string;
onClose: any;
onStartConversation: any;
// onStartConversation: any;
theme: DefaultTheme;
}
@ -35,7 +39,7 @@ export class UserDetailsDialog extends React.Component<Props, State> {
const { i18n } = this.props;
return (
<SessionModal
<SessionWrapperModal
title={this.props.profileName}
onClose={this.closeDialog}
theme={this.props.theme}
@ -43,6 +47,8 @@ export class UserDetailsDialog extends React.Component<Props, State> {
<div className="avatar-center">
<div className="avatar-center-inner">{this.renderAvatar()}</div>
</div>
<div className="spacer-md"></div>
<SessionIdEditable editable={false} text={this.props.pubkey} />
<div className="session-modal__button-group__center">
@ -53,7 +59,7 @@ export class UserDetailsDialog extends React.Component<Props, State> {
onClick={this.onClickStartConversation}
/>
</div>
</SessionModal>
</SessionWrapperModal>
);
}
@ -95,8 +101,14 @@ export class UserDetailsDialog extends React.Component<Props, State> {
this.props.onClose();
}
private onClickStartConversation() {
this.props.onStartConversation();
private async onClickStartConversation() {
// this.props.onStartConversation();
const conversation = await ConversationController.getInstance().getOrCreateAndWait(this.props.pubkey, ConversationTypeEnum.PRIVATE);
window.inboxStore?.dispatch(
window.actionsCreators.openConversationExternal(conversation.id)
);
this.closeDialog();
}
}

@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import { SessionModal } from '../session/SessionModal';
import { SessionButton, SessionButtonColor } from '../session/SessionButton';
@ -10,11 +10,12 @@ import { initiateGroupUpdate } from '../../session/group';
import { ConversationModel, ConversationTypeEnum } from '../../models/conversation';
import { getCompleteUrlForV2ConvoId } from '../../interactions/conversation';
import _ from 'lodash';
import autoBind from 'auto-bind';
import { VALIDATION } from '../../session/constants';
import { SessionWrapperModal } from '../session/SessionWrapperModal';
interface Props {
contactList: Array<any>;
chatName: string;
// contactList: Array<any>;
onClose: any;
theme: DefaultTheme;
convo: ConversationModel;
@ -24,22 +25,38 @@ interface State {
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 nickname = d.getNickname();
const name = nickname
? nickname
: lokiProfile
? lokiProfile.displayName
: window.i18n('anonymous');
? lokiProfile.displayName
: window.i18n('anonymous');
// TODO: should take existing members into account
const existingMember = false;
@ -48,58 +65,58 @@ class InviteContactsDialogInner extends React.Component<Props, State> {
id: d.id,
authorPhoneNumber: d.id,
authorProfileName: name,
authorAvatarPath: d?.getAvatarPath(),
authorAvatarPath: d?.getAvatarPath() || '',
selected: false,
authorName: name,
checkmarked: false,
existingMember,
};
});
})
)
this.state = {
contactList: contacts,
};
window.addEventListener('keyup', this.onKeyUp);
const closeDialog = () => {
window.removeEventListener('keyup', onKeyUp);
onClose();
}
public render() {
const titleText = `${window.i18n('addingContacts')} ${this.props.chatName}`;
const cancelText = window.i18n('cancel');
const okText = window.i18n('ok');
const hasContacts = this.state.contactList.length !== 0;
return (
<SessionModal title={titleText} onClose={this.closeDialog} theme={this.props.theme}>
<div className="spacer-lg" />
<div className="contact-selection-list">{this.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={this.closeDialog} />
<SessionButton
text={okText}
disabled={!hasContacts}
onClick={this.onClickOK}
buttonColor={SessionButtonColor.Green}
/>
</div>
</SessionModal>
);
const onClickOK = () => {
const selectedContacts = contactList.filter((d: ContactType) => d.checkmarked).map((d: ContactType) => d.id);
if (selectedContacts.length > 0) {
if (isPublicConvo) {
void submitForOpenGroup(selectedContacts);
} else {
void submitForClosedGroup(selectedContacts);
}
}
closeDialog();
}
private async submitForOpenGroup(pubkeys: Array<string>) {
const { convo } = this.props;
const onKeyUp = (event: any) => {
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()) {
const v1 = convo.toOpenGroupV1();
const groupInvitation = {
@ -137,8 +154,7 @@ class InviteContactsDialogInner extends React.Component<Props, State> {
}
}
private async submitForClosedGroup(pubkeys: Array<string>) {
const { convo } = this.props;
const submitForClosedGroup = async (pubkeys: Array<string>) => {
// closed group chats
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) {
if (this.props.convo.isPublic()) {
void this.submitForOpenGroup(selectedContacts);
} 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);
const renderMemberList = () => {
const members = contactList;
const selectedContacts = contactList.filter((d: ContactType) => d.checkmarked).map((d: ContactType) => d.id);
return members.map((member: ContactType, index: number) => (
<SessionMemberListItem
@ -203,50 +206,56 @@ class InviteContactsDialogInner extends React.Component<Props, State> {
index={index}
isSelected={selectedContacts.some(m => m === member.id)}
onSelect={(selectedMember: ContactType) => {
this.onMemberClicked(selectedMember);
onMemberClicked(selectedMember);
}}
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 updatedContacts = this.state.contactList.map(member => {
const onMemberClicked = (clickedMember: ContactType) => {
const updatedContacts = contactList.map((member: ContactType) => {
if (member.id === clickedMember.id) {
return { ...member, checkmarked: !member.checkmarked };
} else {
return member;
}
});
this.setState(state => {
return {
...state,
contactList: updatedContacts,
};
});
setContactList(updatedContacts);
}
private closeDialog() {
window.removeEventListener('keyup', this.onKeyUp);
this.props.onClose();
}
return (
<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;

@ -71,10 +71,10 @@ import { useTheme, withTheme } from 'styled-components';
import { MessageMetadata } from './message/MessageMetadata';
import { PubKey } from '../../session/types';
import { ToastUtils, UserUtils } from '../../session/utils';
import { ConversationController } from '../../session/conversations';
import { MessageRegularProps } from '../../models/messageType';
import { useEncryptedFileFetch } from '../../hooks/useEncryptedFileFetch';
import { addSenderAsModerator, removeSenderFromModerator } from '../../interactions/message';
import { UserDetailsDialog } from '../UserDetailsDialog';
// Same as MIN_WIDTH in ImageGrid.tsx
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
@ -467,8 +467,8 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
conversationType,
direction,
isPublic,
onShowUserDetails,
firstMessageOfSeries,
updateSessionConversationModal
} = this.props;
if (collapseMetadata || conversationType !== 'group' || direction === 'outgoing') {
@ -480,15 +480,24 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
return <div style={{ marginInlineEnd: '60px' }} />;
}
const onAvatarClick = () => {
updateSessionConversationModal(<UserDetailsDialog
i18n={window.i18n}
profileName={userName}
avatarPath={authorAvatarPath || ''}
pubkey={authorPhoneNumber}
onClose={() => updateSessionConversationModal(null)}
theme={this.props.theme}
/>)
}
return (
<div className="module-message__author-avatar">
<Avatar
avatarPath={authorAvatarPath}
name={userName}
size={AvatarSize.S}
onAvatarClick={() => {
onShowUserDetails(authorPhoneNumber);
}}
onAvatarClick={onAvatarClick}
pubkey={authorPhoneNumber}
/>
{isPublic && isAdmin && (

@ -85,9 +85,17 @@ class UpdateGroupNameDialogInner extends React.Component<Props, State> {
onClose={() => this.closeDialog()}
theme={this.props.theme}
>
<div className="spacer-md" />
<p className={errorMessageClasses}>{errorMsg}</p>
<div className="spacer-md" />
{ this.state.errorDisplayed ?
<>
<div className="spacer-md" />
<p className={errorMessageClasses}>{errorMsg}</p>
<div className="spacer-md" />
</>
:
null
}
{this.renderAvatar()}
<div className="spacer-md" />
@ -95,7 +103,7 @@ class UpdateGroupNameDialogInner extends React.Component<Props, State> {
type="text"
className="profile-name-input"
value={this.state.groupName}
placeholder={this.props.i18n('groupNamePlaceholder')}
placeholder={window.i18n('groupNamePlaceholder')}
onChange={this.onGroupNameChanged}
tabIndex={0}
required={true}

@ -38,6 +38,7 @@ import { UpdateGroupNameDialog } from '../../conversation/UpdateGroupNameDialog'
import { UpdateGroupMembersDialog } from '../../conversation/UpdateGroupMembersDialog';
import { getOurNumber } from '../../../state/selectors/user';
import { useSelector } from 'react-redux';
import { InviteContactsDialog } from '../../conversation/InviteContactsDialog';
@ -450,9 +451,22 @@ export class SessionConversation extends React.Component<Props, State> {
onDownloadAttachment: this.saveAttachment,
messageContainerRef: this.messageContainerRef,
onDeleteSelectedMessages: this.deleteSelectedMessages,
updateSessionConversationModal: this.updateSessionConversationModal
};
}
/**
* Setting this to a JSX element that will be rendered if non-null.
* @param update Value to set the modal state to
*/
private updateSessionConversationModal (update: JSX.Element | null) {
this.setState({
...this.state,
modal: update
})
}
public getRightPanelProps() {
const { selectedConversationKey } = this.props;
const conversation = ConversationController.getInstance().getOrThrow(selectedConversationKey);
@ -508,9 +522,10 @@ export class SessionConversation extends React.Component<Props, State> {
let isAdmin = true;
let titleText;
titleText = window.i18n('updateGroupDialogTitle', groupName);
if (isPublic) {
// fix the title
titleText = window.i18n('updateGroupDialogTitle', groupName);
// I'd much prefer to integrate mods with groupAdmins
// but lets discuss first...
isAdmin = conversation.isAdmin(window.storage.get('primaryDevicePubKey'));
@ -692,7 +707,16 @@ export class SessionConversation extends React.Component<Props, State> {
// warrick: delete old code
},
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: () => {
window.Whisper.events.trigger('leaveClosedGroup', conversation);
@ -706,7 +730,7 @@ export class SessionConversation extends React.Component<Props, State> {
convo={conversation}
onClose={() => this.setState({ ...this.state, modal: null })}
theme={this.props.theme}
></AddModeratorsDialog>)
/>)
})
},
@ -719,7 +743,7 @@ export class SessionConversation extends React.Component<Props, State> {
convo={conversation}
onClose={() => this.setState({ ...this.state, modal: null })}
theme={this.props.theme}
></RemoveModeratorsDialog>)
/>)
})
},
onShowLightBox: (lightBoxOptions = {}) => {

@ -47,6 +47,7 @@ interface Props {
onClickAttachment: (attachment: any, message: any) => void;
onDownloadAttachment: ({ attachment }: { attachment: any }) => void;
onDeleteSelectedMessages: () => Promise<void>;
updateSessionConversationModal: (modal: JSX.Element | null) => any;
}
export class SessionMessagesList extends React.Component<Props, State> {
@ -320,6 +321,8 @@ export class SessionMessagesList extends React.Component<Props, State> {
};
}
messageProps.updateSessionConversationModal = this.props.updateSessionConversationModal
return <Message {...messageProps} key={messageProps.id} />;
}

@ -228,6 +228,8 @@ export interface MessageRegularProps {
onCopyPubKey?: () => void;
onBanUser?: () => void;
onUnbanUser?: () => void;
// setModal?: any;
updateSessionConversationModal: (modal: JSX.Element | null) => any;
onShowDetail: () => void;
onShowUserDetails: (userPubKey: string) => void;

Loading…
Cancel
Save