You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			291 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			291 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			TypeScript
		
	
import React from 'react';
 | 
						|
 | 
						|
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
 | 
						|
import { SessionIdEditable } from './SessionIdEditable';
 | 
						|
import { UserSearchDropdown } from './UserSearchDropdown';
 | 
						|
import { ContactType, SessionMemberListItem } from './SessionMemberListItem';
 | 
						|
import { ConversationType } from '../../state/ducks/conversations';
 | 
						|
import {
 | 
						|
  SessionButton,
 | 
						|
  SessionButtonColor,
 | 
						|
  SessionButtonType,
 | 
						|
} from './SessionButton';
 | 
						|
import { SessionSpinner } from './SessionSpinner';
 | 
						|
import { SessionGroupType } from './LeftPaneChannelSection';
 | 
						|
 | 
						|
interface Props {
 | 
						|
  overlayMode: 'message' | 'contact' | SessionGroupType;
 | 
						|
  onChangeSessionID: any;
 | 
						|
  onCloseClick: any;
 | 
						|
  onButtonClick: any;
 | 
						|
  contacts?: Array<ConversationType>;
 | 
						|
  searchTerm?: string;
 | 
						|
  searchResults?: any;
 | 
						|
  updateSearch?: any;
 | 
						|
  showSpinner?: boolean;
 | 
						|
}
 | 
						|
 | 
						|
interface State {
 | 
						|
  groupName: string;
 | 
						|
  selectedMembers: Array<ContactType>;
 | 
						|
}
 | 
						|
 | 
						|
export class SessionClosableOverlay extends React.Component<Props, State> {
 | 
						|
  private readonly inputRef: React.RefObject<SessionIdEditable>;
 | 
						|
 | 
						|
  public constructor(props: Props) {
 | 
						|
    super(props);
 | 
						|
 | 
						|
    this.state = {
 | 
						|
      groupName: '',
 | 
						|
      selectedMembers: [],
 | 
						|
    };
 | 
						|
 | 
						|
    this.inputRef = React.createRef();
 | 
						|
    this.onGroupNameChanged = this.onGroupNameChanged.bind(this);
 | 
						|
  }
 | 
						|
 | 
						|
  public componentDidMount() {
 | 
						|
    if (this.inputRef.current) {
 | 
						|
      this.inputRef.current.focus();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public getContacts() {
 | 
						|
    const conversations = window.getConversations() || [];
 | 
						|
 | 
						|
    const conversationList = conversations.filter((conversation: any) => {
 | 
						|
      return (
 | 
						|
        !conversation.isMe() &&
 | 
						|
        conversation.isPrivate() &&
 | 
						|
        !conversation.isSecondaryDevice() &&
 | 
						|
        conversation.isFriend()
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    return conversationList.map((d: any) => {
 | 
						|
      const lokiProfile = d.getLokiProfile();
 | 
						|
      const name = lokiProfile ? lokiProfile.displayName : 'Anonymous';
 | 
						|
 | 
						|
      // TODO: should take existing members into account
 | 
						|
      const existingMember = false;
 | 
						|
 | 
						|
      return {
 | 
						|
        id: d.id,
 | 
						|
        authorPhoneNumber: d.id,
 | 
						|
        authorProfileName: name,
 | 
						|
        selected: false,
 | 
						|
        authorName: name,
 | 
						|
        authorColor: d.getColor(),
 | 
						|
        checkmarked: false,
 | 
						|
        existingMember,
 | 
						|
      };
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  // tslint:disable-next-line max-func-body-length */
 | 
						|
  public render(): JSX.Element {
 | 
						|
    const {
 | 
						|
      overlayMode,
 | 
						|
      onCloseClick,
 | 
						|
      onChangeSessionID,
 | 
						|
      showSpinner,
 | 
						|
      searchTerm,
 | 
						|
      updateSearch,
 | 
						|
      searchResults,
 | 
						|
      onButtonClick,
 | 
						|
    } = this.props;
 | 
						|
 | 
						|
    const isAddContactView = overlayMode === 'contact';
 | 
						|
    const isMessageView = overlayMode === 'message';
 | 
						|
 | 
						|
    const isOpenGroupView = overlayMode === SessionGroupType.Open;
 | 
						|
    const isClosedGroupView = overlayMode === SessionGroupType.Closed;
 | 
						|
 | 
						|
    let title;
 | 
						|
    let buttonText;
 | 
						|
    let descriptionLong;
 | 
						|
    let subtitle;
 | 
						|
    let placeholder;
 | 
						|
    switch (overlayMode) {
 | 
						|
      case 'message':
 | 
						|
        title = window.i18n('newSession');
 | 
						|
        buttonText = window.i18n('next');
 | 
						|
        descriptionLong = window.i18n('usersCanShareTheir...');
 | 
						|
        subtitle = window.i18n('enterSessionID');
 | 
						|
        placeholder = window.i18n('pasteSessionIDRecipient');
 | 
						|
        break;
 | 
						|
      case 'contact':
 | 
						|
        title = window.i18n('addContact');
 | 
						|
        buttonText = window.i18n('next');
 | 
						|
        descriptionLong = window.i18n('usersCanShareTheir...');
 | 
						|
        subtitle = window.i18n('enterSessionID');
 | 
						|
        placeholder = window.i18n('pasteSessionIDRecipient');
 | 
						|
        break;
 | 
						|
      case 'open-group':
 | 
						|
        title = window.i18n('addChannel');
 | 
						|
        buttonText = window.i18n('joinChannel');
 | 
						|
        descriptionLong = window.i18n('addChannelDescription');
 | 
						|
        subtitle = window.i18n('enterChannelURL');
 | 
						|
        placeholder = window.i18n('channelUrlPlaceholder');
 | 
						|
        break;
 | 
						|
      case 'closed-group':
 | 
						|
        title = window.i18n('newClosedGroup');
 | 
						|
        buttonText = window.i18n('createClosedGroup');
 | 
						|
        descriptionLong = window.i18n('createClosedGroupDescription');
 | 
						|
        subtitle = window.i18n('createClosedGroupNamePrompt');
 | 
						|
        placeholder = window.i18n('createClosedGroupPlaceholder');
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
    }
 | 
						|
 | 
						|
    const { groupName, selectedMembers } = this.state;
 | 
						|
    const ourSessionID = window.textsecure.storage.user.getNumber();
 | 
						|
 | 
						|
    const contacts = this.getContacts();
 | 
						|
    const noContactsForClosedGroup =
 | 
						|
      overlayMode === SessionGroupType.Closed && contacts.length === 0;
 | 
						|
 | 
						|
    return (
 | 
						|
      <div className="module-left-pane-overlay">
 | 
						|
        <div className="exit">
 | 
						|
          <SessionIconButton
 | 
						|
            iconSize={SessionIconSize.Small}
 | 
						|
            iconType={SessionIconType.Exit}
 | 
						|
            onClick={onCloseClick}
 | 
						|
          />
 | 
						|
        </div>
 | 
						|
 | 
						|
        <div className="spacer-md" />
 | 
						|
 | 
						|
        <h2>{title}</h2>
 | 
						|
 | 
						|
        <h3>
 | 
						|
          {subtitle}
 | 
						|
          <hr className="green-border" />
 | 
						|
        </h3>
 | 
						|
        <hr className="white-border" />
 | 
						|
 | 
						|
        {isOpenGroupView || isClosedGroupView ? (
 | 
						|
          <div className="create-group-name-input">
 | 
						|
            <SessionIdEditable
 | 
						|
              ref={this.inputRef}
 | 
						|
              editable={!noContactsForClosedGroup}
 | 
						|
              placeholder={placeholder}
 | 
						|
              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 />}
 | 
						|
 | 
						|
        {isClosedGroupView && (
 | 
						|
          <>
 | 
						|
            <div className="spacer-lg" />
 | 
						|
 | 
						|
            <div className="group-member-list__container">
 | 
						|
              {noContactsForClosedGroup ? (
 | 
						|
                <div className="group-member-list__no-contacts">
 | 
						|
                  {window.i18n('noContactsForGroup')}
 | 
						|
                </div>
 | 
						|
              ) : (
 | 
						|
                <div className="group-member-list__selection">
 | 
						|
                  {this.renderMemberList()}
 | 
						|
                </div>
 | 
						|
              )}
 | 
						|
            </div>
 | 
						|
 | 
						|
            <div className="spacer-lg" />
 | 
						|
          </>
 | 
						|
        )}
 | 
						|
 | 
						|
        <div className="session-description-long">{descriptionLong}</div>
 | 
						|
        {isMessageView && <h4>{window.i18n('or')}</h4>}
 | 
						|
 | 
						|
        {isMessageView && (
 | 
						|
          <UserSearchDropdown
 | 
						|
            searchTerm={searchTerm || ''}
 | 
						|
            updateSearch={updateSearch}
 | 
						|
            placeholder={window.i18n('searchByIDOrDisplayName')}
 | 
						|
            searchResults={searchResults}
 | 
						|
          />
 | 
						|
        )}
 | 
						|
 | 
						|
        {isAddContactView && (
 | 
						|
          <div className="panel-text-divider">
 | 
						|
            <span>{window.i18n('yourPublicKey')}</span>
 | 
						|
          </div>
 | 
						|
        )}
 | 
						|
 | 
						|
        {isAddContactView && (
 | 
						|
          <SessionIdEditable
 | 
						|
            editable={false}
 | 
						|
            placeholder=""
 | 
						|
            text={ourSessionID}
 | 
						|
          />
 | 
						|
        )}
 | 
						|
 | 
						|
        <SessionButton
 | 
						|
          buttonColor={SessionButtonColor.Green}
 | 
						|
          buttonType={SessionButtonType.BrandOutline}
 | 
						|
          text={buttonText}
 | 
						|
          disabled={noContactsForClosedGroup}
 | 
						|
          onClick={() => onButtonClick(groupName, selectedMembers)}
 | 
						|
        />
 | 
						|
      </div>
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  private renderMemberList() {
 | 
						|
    const members = this.getContacts();
 | 
						|
 | 
						|
    return members.map((member: ContactType) => (
 | 
						|
      <SessionMemberListItem
 | 
						|
        member={member}
 | 
						|
        isSelected={false}
 | 
						|
        onSelect={(selectedMember: ContactType) => {
 | 
						|
          this.handleSelectMember(selectedMember);
 | 
						|
        }}
 | 
						|
        onUnselect={(selectedMember: ContactType) => {
 | 
						|
          this.handleUnselectMember(selectedMember);
 | 
						|
        }}
 | 
						|
      />
 | 
						|
    ));
 | 
						|
  }
 | 
						|
 | 
						|
  private handleSelectMember(member: ContactType) {
 | 
						|
    if (this.state.selectedMembers.includes(member)) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    this.setState({
 | 
						|
      selectedMembers: [...this.state.selectedMembers, member],
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  private handleUnselectMember(member: ContactType) {
 | 
						|
    this.setState({
 | 
						|
      selectedMembers: this.state.selectedMembers.filter(selectedMember => {
 | 
						|
        return selectedMember !== member;
 | 
						|
      }),
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  private onGroupNameChanged(event: any) {
 | 
						|
    this.setState({
 | 
						|
      groupName: event,
 | 
						|
    });
 | 
						|
  }
 | 
						|
}
 |