Closed group joining completed w/o backend

pull/790/head
Vincent 5 years ago
parent 4fd2126fbe
commit b341ceaf76

@ -1440,7 +1440,8 @@
"description": "Header for notification settings" "description": "Header for notification settings"
}, },
"readReceiptSettingDescription": { "readReceiptSettingDescription": {
"message": "See and share when messages have been read (enables read receipts in all sessions).", "message":
"See and share when messages have been read (enables read receipts in all sessions).",
"description": "Description of the read receipts setting" "description": "Description of the read receipts setting"
}, },
"readReceiptSettingTitle": { "readReceiptSettingTitle": {
@ -2728,7 +2729,8 @@
"message": "Create Closed Group" "message": "Create Closed Group"
}, },
"createClosedGroupDescription": { "createClosedGroupDescription": {
"message": "Closed groups are end-to-end encrypted group chats for up to 10 members. They provide the same privacy protections as one-on-one sessions." "message":
"Closed groups are end-to-end encrypted group chats for up to 10 members. They provide the same privacy protections as one-on-one sessions."
}, },
"createClosedGroupNamePrompt": { "createClosedGroupNamePrompt": {
"message": "Group Name" "message": "Group Name"

@ -987,7 +987,6 @@
return toastID; return toastID;
}; };
window.getFriendsFromContacts = contacts => { window.getFriendsFromContacts = contacts => {
// To call from TypeScript, input / output are both // To call from TypeScript, input / output are both
// of type Array<ConversationType> // of type Array<ConversationType>
@ -998,7 +997,7 @@
); );
} }
return friendList; return friendList;
} };
// Get memberlist. This function is not accurate >> // Get memberlist. This function is not accurate >>
// window.getMemberList = window.lokiPublicChatAPI.getListOfMembers(); // window.getMemberList = window.lokiPublicChatAPI.getListOfMembers();

@ -496,7 +496,9 @@ class LokiAppDotNetServerAPI {
)); ));
} else { } else {
// disable check for .loki // disable check for .loki
process.env.NODE_TLS_REJECT_UNAUTHORIZED = endpoint.match(/\.loki\//) ? 0 : 1; process.env.NODE_TLS_REJECT_UNAUTHORIZED = endpoint.match(/\.loki\//)
? 0
: 1;
result = await nodeFetch(url, fetchOptions); result = await nodeFetch(url, fetchOptions);
// always make sure this check is enabled // always make sure this check is enabled
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1; process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
@ -505,7 +507,12 @@ class LokiAppDotNetServerAPI {
} }
} catch (e) { } catch (e) {
if (txtResponse) { if (txtResponse) {
log.info(`serverRequest ${mode} error`, e.code, e.message, `json: ${txtResponse}`); log.info(
`serverRequest ${mode} error`,
e.code,
e.message,
`json: ${txtResponse}`
);
} else { } else {
log.info(`serverRequest ${mode} error`, e.code, e.message); log.info(`serverRequest ${mode} error`, e.code, e.message);
} }

@ -1683,15 +1683,13 @@ input {
} }
} }
.group-member-list { .group-member-list {
&__container { &__container {
padding: 2px 0px; padding: 2px 0px;
width: 100%; width: 100%;
max-height: 400px; max-height: 400px;
overflow-y: auto; overflow-y: auto;
box-shadow: box-shadow: inset 0px 14px 7px -15px $session-color-dark-grey,
inset 0px 14px 7px -15px $session-color-dark-grey,
inset 0px -14px 7px -15px $session-color-dark-grey; inset 0px -14px 7px -15px $session-color-dark-grey;
} }
@ -1699,7 +1697,6 @@ input {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
} }
.create-group-name-input { .create-group-name-input {
@ -1710,12 +1707,11 @@ input {
padding-bottom: 0px !important; padding-bottom: 0px !important;
} }
} }
} }
.session-member-item { .session-member-item {
font-family: "SF Pro Text"; cursor: pointer;
font-family: 'SF Pro Text';
padding: 0px $session-margin-sm; padding: 0px $session-margin-sm;
height: 50px; height: 50px;
display: flex; display: flex;
@ -1726,17 +1722,17 @@ input {
background-color: $session-shade-4; background-color: $session-shade-4;
} }
&__checkmark { &__checkmark {
opacity: 0; opacity: 0;
transition: $session-transition-duration; transition: $session-transition-duration;
&.selected{ &.selected {
opacity: 1; opacity: 1;
} }
} }
&__info, &__checkmark{ &__info,
&__checkmark {
display: flex; display: flex;
align-items: center; align-items: center;
} }

@ -271,8 +271,8 @@ $session-compose-margin: 20px;
position: relative; position: relative;
height: 1px; height: 1px;
opacity: 0.3; opacity: 0.3;
margin-top: -10px; margin-top: 2px;
margin-bottom: 50px; margin-bottom: 40px;
} }
.exit { .exit {
@ -291,10 +291,9 @@ $session-compose-margin: 20px;
} }
.session-description-long { .session-description-long {
<<<<<<<headfont-size: $session-font-sm; font-size: $session-font-sm;
line-height: $session-font-h3; line-height: $session-font-h3;
=======font-size: 13px; margin: 0px 20px;
>>>>>>>9732c4f4d074c1024f308cf7369fc535c26724b4margin: 0px 20px;
font-family: 'SF Pro Display'; font-family: 'SF Pro Display';
} }

@ -96,7 +96,7 @@ export class CreateGroupDialog extends React.Component<Props, State> {
return ( return (
<SessionModal title={titleText} onClose={() => null} onOk={() => null}> <SessionModal title={titleText} onClose={() => null} onOk={() => null}>
<div className="spacer-lg"></div> <div className="spacer-lg" />
<p className={errorMessageClasses}>{this.state.errorMessage}</p> <p className={errorMessageClasses}>{this.state.errorMessage}</p>
<input <input
@ -120,7 +120,7 @@ export class CreateGroupDialog extends React.Component<Props, State> {
/> />
</div> </div>
<div className="spacer-lg"></div> <div className="spacer-lg" />
<div className="buttons"> <div className="buttons">
<button className="cancel" tabIndex={0} onClick={this.closeDialog}> <button className="cancel" tabIndex={0} onClick={this.closeDialog}>

@ -32,9 +32,6 @@ export class InviteFriendsDialog extends React.Component<Props, State> {
let friends = this.props.friendList; let friends = this.props.friendList;
console.log("Contacts from invitefriendsDialog before filter::");
console.log(friends);
friends = friends.map(d => { friends = friends.map(d => {
const lokiProfile = d.getLokiProfile(); const lokiProfile = d.getLokiProfile();
const name = lokiProfile ? lokiProfile.displayName : 'Anonymous'; const name = lokiProfile ? lokiProfile.displayName : 'Anonymous';
@ -54,9 +51,6 @@ export class InviteFriendsDialog extends React.Component<Props, State> {
}; };
}); });
console.log("Ideal friends list from inviteDialog");
console.log(friends);
this.state = { this.state = {
friendList: friends, friendList: friends,
}; };
@ -77,7 +71,7 @@ export class InviteFriendsDialog extends React.Component<Props, State> {
onOk={() => null} onOk={() => null}
onClose={this.closeDialog} onClose={this.closeDialog}
> >
<div className="spacer-lg"></div> <div className="spacer-lg" />
<div className="friend-selection-list"> <div className="friend-selection-list">
<MemberList <MemberList
@ -95,7 +89,7 @@ export class InviteFriendsDialog extends React.Component<Props, State> {
</> </>
)} )}
<div className="spacer-lg"></div> <div className="spacer-lg" />
<div className="session-modal__button-group"> <div className="session-modal__button-group">
<SessionButton text={cancelText} onClick={this.closeDialog} /> <SessionButton text={cancelText} onClick={this.closeDialog} />

@ -274,7 +274,6 @@ export class LeftPaneChannelSection extends React.Component<Props, State> {
this.setState({ this.setState({
groupAddType: undefined, groupAddType: undefined,
}); });
break;
} }
} }
@ -286,7 +285,9 @@ export class LeftPaneChannelSection extends React.Component<Props, State> {
<SessionClosableOverlay <SessionClosableOverlay
overlayMode={SessionGroupType.Open} overlayMode={SessionGroupType.Open}
onChangeSessionID={this.handleOnPasteUrl} onChangeSessionID={this.handleOnPasteUrl}
onCloseClick={() => this.handleToggleOverlay(undefined)} onCloseClick={() => {
this.handleToggleOverlay(undefined);
}}
onButtonClick={this.handleJoinChannelButtonClick} onButtonClick={this.handleJoinChannelButtonClick}
searchTerm={searchTerm} searchTerm={searchTerm}
updateSearch={this.updateSearchBound} updateSearch={this.updateSearchBound}
@ -298,22 +299,22 @@ export class LeftPaneChannelSection extends React.Component<Props, State> {
<SessionClosableOverlay <SessionClosableOverlay
overlayMode={SessionGroupType.Closed} overlayMode={SessionGroupType.Closed}
onChangeSessionID={this.handleOnPasteUrl} onChangeSessionID={this.handleOnPasteUrl}
onCloseClick={() => this.handleToggleOverlay(undefined)} onCloseClick={() => {
onButtonClick={(groupName: string, groupMembers: Array<ContactType>) => this.handleToggleOverlay(undefined);
this.onCreateClosedGroup(groupName, groupMembers) }}
} onButtonClick={async (
groupName: string,
groupMembers: Array<ContactType>
) => this.onCreateClosedGroup(groupName, groupMembers)}
searchTerm={searchTerm} searchTerm={searchTerm}
updateSearch={this.updateSearchBound} updateSearch={this.updateSearchBound}
showSpinner={loading} showSpinner={loading}
/> />
); );
const renderElement = return groupType === SessionGroupType.Open
groupType === SessionGroupType.Open ? openGroupElement
? openGroupElement : closedGroupElement;
: closedGroupElement;
return renderElement;
} }
private renderBottomButtons(): JSX.Element { private renderBottomButtons(): JSX.Element {
@ -336,13 +337,17 @@ export class LeftPaneChannelSection extends React.Component<Props, State> {
text={joinOpenGroup} text={joinOpenGroup}
buttonType={SessionButtonType.SquareOutline} buttonType={SessionButtonType.SquareOutline}
buttonColor={SessionButtonColor.Green} buttonColor={SessionButtonColor.Green}
onClick={() => this.handleToggleOverlay(SessionGroupType.Open)} onClick={() => {
this.handleToggleOverlay(SessionGroupType.Open);
}}
/> />
<SessionButton <SessionButton
text={createClosedGroup} text={createClosedGroup}
buttonType={SessionButtonType.SquareOutline} buttonType={SessionButtonType.SquareOutline}
buttonColor={SessionButtonColor.White} buttonColor={SessionButtonColor.White}
onClick={() => this.handleToggleOverlay(SessionGroupType.Closed)} onClick={() => {
this.handleToggleOverlay(SessionGroupType.Closed);
}}
/> />
</div> </div>
); );
@ -381,11 +386,9 @@ export class LeftPaneChannelSection extends React.Component<Props, State> {
return false; return false;
} }
joinChannelStateManager( joinChannelStateManager(this, channelUrlPasted, () => {
this, this.handleToggleOverlay(SessionGroupType.Open);
channelUrlPasted, });
this.handleToggleOverlay(SessionGroupType.Open)
);
return true; return true;
} }

@ -322,7 +322,7 @@ export class LeftPaneContactSection extends React.Component<Props, State> {
private renderList() { private renderList() {
const { sentFriendsRequest } = this.props; const { sentFriendsRequest } = this.props;
const friends = window.getFriendsFromContacts(this.props.friends); const friends = window.getFriendsFromContacts(this.props.friends);
const length = sentFriendsRequest.length + friends.length; const length = Number(sentFriendsRequest.length) + Number(friends.length);
const combined = [...sentFriendsRequest, ...friends]; const combined = [...sentFriendsRequest, ...friends];
const list = ( const list = (

@ -43,7 +43,6 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
this.inputRef = React.createRef(); this.inputRef = React.createRef();
this.onGroupNameChanged = this.onGroupNameChanged.bind(this); this.onGroupNameChanged = this.onGroupNameChanged.bind(this);
} }
public componentDidMount() { public componentDidMount() {
@ -52,18 +51,17 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
} }
} }
public getContacts() { public getContacts() {
const conversations = window.getConversations(); const conversations = window.getConversations();
let conversationList = conversations; let conversationList = conversations;
if (conversationList !== undefined) { if (conversationList !== undefined) {
conversationList = conversationList.filter((conv: any) => { conversationList = conversationList.filter((conv: any) => {
return !conv.isRss() && !conv.isPublic() && conv.attributes.lastMessage return !conv.isRss() && !conv.isPublic() && conv.attributes.lastMessage;
}); });
} }
let friends = conversationList.map((d: any) => { const friends = conversationList.map((d: any) => {
const lokiProfile = d.getLokiProfile(); const lokiProfile = d.getLokiProfile();
const name = lokiProfile ? lokiProfile.displayName : 'Anonymous'; const name = lokiProfile ? lokiProfile.displayName : 'Anonymous';
@ -154,41 +152,40 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
/> />
</div> </div>
<div className="spacer-md"></div> <div className="spacer-md" />
<h2>{title}</h2> <h2>{title}</h2>
<h3>{subtitle}</h3> <h3>
<div className="module-left-pane-overlay-border-container"> {subtitle}
<hr className="white" /> <hr className="green-border" />
<hr className="green" /> </h3>
</div> <hr className="white-border" />
{ (isOpenGroupView || isClosedGroupView) ?
( {isOpenGroupView || isClosedGroupView ? (
<div className="create-group-name-input"> <div className="create-group-name-input">
<SessionIdEditable
ref={this.inputRef}
editable={true}
placeholder={placeholder}
value={this.state.groupName}
maxLength={window.CONSTANTS.MAX_GROUPNAME_LENGTH}
onChange={this.onGroupNameChanged}
/>
</div>
) : (
<SessionIdEditable <SessionIdEditable
ref={this.inputRef} ref={this.inputRef}
editable={true} editable={true}
placeholder={placeholder} placeholder={placeholder}
onChange={onChangeSessionID} value={this.state.groupName}
maxLength={window.CONSTANTS.MAX_GROUPNAME_LENGTH}
onChange={this.onGroupNameChanged}
/> />
) </div>
} ) : (
<SessionIdEditable
ref={this.inputRef}
editable={true}
placeholder={placeholder}
onChange={onChangeSessionID}
/>
)}
{showSpinner && <SessionSpinner />} {showSpinner && <SessionSpinner />}
{isClosedGroupView && ( {isClosedGroupView && (
<> <>
<div className="spacer-lg"></div> <div className="spacer-lg" />
<div className="group-member-list__container"> <div className="group-member-list__container">
<div className="group-member-list__selection"> <div className="group-member-list__selection">
@ -196,7 +193,7 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
</div> </div>
</div> </div>
<div className="spacer-lg"></div> <div className="spacer-lg" />
</> </>
)} )}
@ -240,33 +237,36 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
const members = this.getContacts(); const members = this.getContacts();
const memberList = members.map((member: ContactType) => ( const memberList = members.map((member: ContactType) => (
<SessionMemberListItem <SessionMemberListItem
member={member} member={member}
isSelected={false} isSelected={false}
onSelect={(member: ContactType) => this.handleSelectMember(member)} onSelect={(selectedMember: ContactType) => {
onUnselect={(member: ContactType) => this.handleUnselectMember(member)} this.handleSelectMember(selectedMember);
/> }}
) onUnselect={(selectedMember: ContactType) => {
); this.handleUnselectMember(selectedMember);
}}
/>
));
return memberList; return memberList;
} }
private handleSelectMember(member: ContactType){ private handleSelectMember(member: ContactType) {
if (this.state.selectedMembers.includes(member)){ if (this.state.selectedMembers.includes(member)) {
return; return;
} }
this.setState({ this.setState({
selectedMembers: [...this.state.selectedMembers, member] selectedMembers: [...this.state.selectedMembers, member],
}); });
} }
private handleUnselectMember(member: ContactType){ private handleUnselectMember(member: ContactType) {
this.setState({ this.setState({
selectedMembers: this.state.selectedMembers.filter(selectedMember => { selectedMembers: this.state.selectedMembers.filter(selectedMember => {
return selectedMember !== member; return selectedMember !== member;
}) }),
}); });
} }

@ -28,7 +28,7 @@ export class SessionIdEditable extends React.PureComponent<Props> {
} }
public render() { public render() {
const { placeholder, editable, text, value, maxLength} = this.props; const { placeholder, editable, text, value, maxLength } = this.props;
return ( return (
<div <div

@ -2,31 +2,29 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Avatar } from '../Avatar'; import { Avatar } from '../Avatar';
import { SessionIcon, SessionIconType, SessionIconSize } from './icon'; import { SessionIcon, SessionIconSize, SessionIconType } from './icon';
export interface ContactType { export interface ContactType {
id: string; id: string;
selected: boolean; selected: boolean;
authorProfileName: string; authorProfileName: string;
authorPhoneNumber: string; authorPhoneNumber: string;
authorName: string; authorName: string;
authorColor: any; authorColor: any;
authorAvatarPath: string; authorAvatarPath: string;
checkmarked: boolean; checkmarked: boolean;
existingMember: boolean; existingMember: boolean;
} }
interface Props { interface Props {
member: ContactType; member: ContactType;
isSelected: boolean; isSelected: boolean;
onSelect?: any; onSelect?: any;
onUnselect?: any; onUnselect?: any;
} }
interface State { interface State {
isSelected: boolean; isSelected: boolean;
} }
export class SessionMemberListItem extends React.Component<Props, State> { export class SessionMemberListItem extends React.Component<Props, State> {
@ -38,7 +36,7 @@ export class SessionMemberListItem extends React.Component<Props, State> {
super(props); super(props);
this.state = { this.state = {
isSelected: this.props.isSelected, isSelected: this.props.isSelected,
}; };
this.handleSelectionAction = this.handleSelectionAction.bind(this); this.handleSelectionAction = this.handleSelectionAction.bind(this);
@ -55,23 +53,31 @@ export class SessionMemberListItem extends React.Component<Props, State> {
const shortPubkey = window.shortenPubkey(pubkey); const shortPubkey = window.shortenPubkey(pubkey);
return ( return (
<div <div
className={classNames('session-member-item', isSelected && 'selected')} className={classNames('session-member-item', isSelected && 'selected')}
onClick={this.handleSelectionAction} onClick={this.handleSelectionAction}
> role="button"
<div className="session-member-item__info"> >
<span className="session-member-item__avatar">{this.renderAvatar()}</span> <div className="session-member-item__info">
<span className="session-member-item__name">{name}</span> <span className="session-member-item__avatar">
<span className="session-member-item__pubkey">{shortPubkey}</span> {this.renderAvatar()}
</div> </span>
<span className={classNames('session-member-item__checkmark', isSelected && 'selected')}> <span className="session-member-item__name">{name}</span>
<SessionIcon <span className="session-member-item__pubkey">{shortPubkey}</span>
iconType={SessionIconType.Check}
iconSize={SessionIconSize.Medium}
iconColor={"#00f782"}
/>
</span>
</div> </div>
<span
className={classNames(
'session-member-item__checkmark',
isSelected && 'selected'
)}
>
<SessionIcon
iconType={SessionIconType.Check}
iconSize={SessionIconSize.Medium}
iconColor={'#00f782'}
/>
</span>
</div>
); );
} }
@ -92,32 +98,31 @@ export class SessionMemberListItem extends React.Component<Props, State> {
private handleSelectionAction() { private handleSelectionAction() {
if (this.state.isSelected) { if (this.state.isSelected) {
this.unselectMember(); this.unselectMember();
return;
return;
} }
this.selectMember(); this.selectMember();
} }
private selectMember() { private selectMember() {
this.setState({ this.setState({
isSelected: true, isSelected: true,
}); });
if (this.props.onSelect){ if (this.props.onSelect) {
this.props.onSelect(this.props.member); this.props.onSelect(this.props.member);
} }
} }
private unselectMember() { private unselectMember() {
this.setState({ this.setState({
isSelected: false, isSelected: false,
}); });
if (this.props.onUnselect){ if (this.props.onUnselect) {
this.props.onUnselect(this.props.member); this.props.onUnselect(this.props.member);
} }
} }
} }

Loading…
Cancel
Save