<commit_before>// @flow

import type {
  NavigationScreenProp,
  NavigationLeafRoute,
} from 'react-navigation';
import type { AppState } from '../redux/redux-setup';
import type { LoadingStatus } from 'lib/types/loading-types';
import { loadingStatusPropType } from 'lib/types/loading-types';
import {
  type ThreadInfo,
  threadInfoPropType,
  type ThreadType,
  threadTypes,
  threadTypePropType,
  type NewThreadRequest,
  type NewThreadResult,
} from 'lib/types/thread-types';
import {
  type AccountUserInfo,
  accountUserInfoPropType,
} from 'lib/types/user-types';
import type { DispatchActionPromise } from 'lib/utils/action-utils';
import type { UserSearchResult } from 'lib/types/search-types';
import type { Styles } from '../types/styles';

import * as React from 'react';
import PropTypes from 'prop-types';
import { View, Text, Alert } from 'react-native';
import invariant from 'invariant';
import _flow from 'lodash/fp/flow';
import _filter from 'lodash/fp/filter';
import _sortBy from 'lodash/fp/sortBy';
import { createSelector } from 'reselect';

import { connect } from 'lib/utils/redux-utils';
import { newThreadActionTypes, newThread } from 'lib/actions/thread-actions';
import { searchUsersActionTypes, searchUsers } from 'lib/actions/user-actions';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors';
import {
  userInfoSelectorForOtherMembersOfThread,
  userSearchIndexForOtherMembersOfThread,
} from 'lib/selectors/user-selectors';
import SearchIndex from 'lib/shared/search-index';
import { threadInChatList, userIsMember } from 'lib/shared/thread-utils';
import { getUserSearchResults } from 'lib/shared/search-utils';
import { registerFetchKey } from 'lib/reducers/loading-reducer';
import { threadInfoSelector } from 'lib/selectors/thread-selectors';

import TagInput from '../components/tag-input.react';
import UserList from '../components/user-list.react';
import ThreadList from '../components/thread-list.react';
import LinkButton from '../components/link-button.react';
import { MessageListRouteName } from '../navigation/route-names';
import { registerChatScreen } from './chat-screen-registry';
import ThreadVisibility from '../components/thread-visibility.react';
import {
  type Colors,
  colorsPropType,
  colorsSelector,
  styleSelector,
} from '../themes/colors';

const tagInputProps = {
  placeholder: 'username',
  autoFocus: true,
  returnKeyType: 'go',
};

type NavProp = NavigationScreenProp<{|
  ...NavigationLeafRoute,
  params: {|
    threadType?: ThreadType,
    parentThreadID?: string,
    createButtonDisabled?: boolean,
  |},
|}>;

let queuedPress = false;
function setQueuedPress() {
  queuedPress = true;
}
let onPressCreateThread = setQueuedPress;
function setOnPressCreateThread(func: ?() => void) {
  if (!func) {
    onPressCreateThread = setQueuedPress;
    return;
  }
  onPressCreateThread = func;
  if (queuedPress) {
    onPressCreateThread();
    queuedPress = false;
  }
}
function pressCreateThread() {
  onPressCreateThread();
}

type Props = {|
  navigation: NavProp,
  // Redux state
  parentThreadInfo: ?ThreadInfo,
  loadingStatus: LoadingStatus,
  otherUserInfos: { [id: string]: AccountUserInfo },
  userSearchIndex: SearchIndex,
  threadInfos: { [id: string]: ThreadInfo },
  colors: Colors,
  styles: Styles,
  // Redux dispatch functions
  dispatchActionPromise: DispatchActionPromise,
  // async functions that hit server APIs
  newThread: (request: NewThreadRequest) => Promise<NewThreadResult>,
  searchUsers: (usernamePrefix: string) => Promise<UserSearchResult>,
|};
type State = {|
  usernameInputText: string,
  userInfoInputArray: $ReadOnlyArray<AccountUserInfo>,
|};
type PropsAndState = {| ...Props, ...State |};
class ComposeThread extends React.PureComponent<Props, State> {
  static propTypes = {
    navigation: PropTypes.shape({
      state: PropTypes.shape({
        key: PropTypes.string.isRequired,
        params: PropTypes.shape({
          parentThreadID: PropTypes.string,
          threadType: threadTypePropType,
        }).isRequired,
      }).isRequired,
      setParams: PropTypes.func.isRequired,
      goBack: PropTypes.func.isRequired,
      navigate: PropTypes.func.isRequired,
      getParam: PropTypes.func.isRequired,
    }).isRequired,
    parentThreadInfo: threadInfoPropType,
    loadingStatus: loadingStatusPropType.isRequired,
    otherUserInfos: PropTypes.objectOf(accountUserInfoPropType).isRequired,
    userSearchIndex: PropTypes.instanceOf(SearchIndex).isRequired,
    threadInfos: PropTypes.objectOf(threadInfoPropType).isRequired,
    colors: colorsPropType.isRequired,
    styles: PropTypes.objectOf(PropTypes.object).isRequired,
    dispatchActionPromise: PropTypes.func.isRequired,
    newThread: PropTypes.func.isRequired,
    searchUsers: PropTypes.func.isRequired,
  };
  static navigationOptions = ({ navigation }) => ({
    title: 'Compose thread',
    headerRight: (
      <LinkButton
        text="Create"
        onPress={pressCreateThread}
        disabled={!!navigation.getParam('createButtonDisabled')}
      />
    ),
    headerBackTitle: 'Back',
  });
  state = {
    usernameInputText: '',
    userInfoInputArray: [],
  };
  tagInput: ?TagInput<AccountUserInfo>;
  createThreadPressed = false;

  componentDidMount() {
    registerChatScreen(this.props.navigation.state.key, this);
    setOnPressCreateThread(this.onPressCreateThread);
    this.searchUsers('');
  }

  componentWillUnmount() {
    registerChatScreen(this.props.navigation.state.key, null);
    setOnPressCreateThread(null);
  }

  get canReset() {
    return false;
  }

  userSearchResultsSelector = createSelector(
    (propsAndState: PropsAndState) => propsAndState.usernameInputText,
    (propsAndState: PropsAndState) => propsAndState.otherUserInfos,
    (propsAndState: PropsAndState) => propsAndState.userSearchIndex,
    (propsAndState: PropsAndState) => propsAndState.userInfoInputArray,
    (propsAndState: PropsAndState) => propsAndState.parentThreadInfo,
    (
      text: string,
      userInfos: { [id: string]: AccountUserInfo },
      searchIndex: SearchIndex,
      userInfoInputArray: $ReadOnlyArray<AccountUserInfo>,
      parentThreadInfo: ?ThreadInfo,
    ) =>
      getUserSearchResults(
        text,
        userInfos,
        searchIndex,
        userInfoInputArray.map(userInfo => userInfo.id),
        parentThreadInfo,
      ),
  );

  get userSearchResults() {
    return this.userSearchResultsSelector({ ...this.props, ...this.state });
  }

  existingThreadsSelector = createSelector(<commit_msg>[native] Don't bother with registerChatScreen for ComposeThread<commit_after>// @flow

import type {
  NavigationScreenProp,
  NavigationLeafRoute,
} from 'react-navigation';
import type { AppState } from '../redux/redux-setup';
import type { LoadingStatus } from 'lib/types/loading-types';
import { loadingStatusPropType } from 'lib/types/loading-types';
import {
  type ThreadInfo,
  threadInfoPropType,
  type ThreadType,
  threadTypes,
  threadTypePropType,
  type NewThreadRequest,
  type NewThreadResult,
} from 'lib/types/thread-types';
import {
  type AccountUserInfo,
  accountUserInfoPropType,
} from 'lib/types/user-types';
import type { DispatchActionPromise } from 'lib/utils/action-utils';
import type { UserSearchResult } from 'lib/types/search-types';
import type { Styles } from '../types/styles';

import * as React from 'react';
import PropTypes from 'prop-types';
import { View, Text, Alert } from 'react-native';
import invariant from 'invariant';
import _flow from 'lodash/fp/flow';
import _filter from 'lodash/fp/filter';
import _sortBy from 'lodash/fp/sortBy';
import { createSelector } from 'reselect';

import { connect } from 'lib/utils/redux-utils';
import { newThreadActionTypes, newThread } from 'lib/actions/thread-actions';
import { searchUsersActionTypes, searchUsers } from 'lib/actions/user-actions';
import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors';
import {
  userInfoSelectorForOtherMembersOfThread,
  userSearchIndexForOtherMembersOfThread,
} from 'lib/selectors/user-selectors';
import SearchIndex from 'lib/shared/search-index';
import { threadInChatList, userIsMember } from 'lib/shared/thread-utils';
import { getUserSearchResults } from 'lib/shared/search-utils';
import { registerFetchKey } from 'lib/reducers/loading-reducer';
import { threadInfoSelector } from 'lib/selectors/thread-selectors';

import TagInput from '../components/tag-input.react';
import UserList from '../components/user-list.react';
import ThreadList from '../components/thread-list.react';
import LinkButton from '../components/link-button.react';
import { MessageListRouteName } from '../navigation/route-names';
import ThreadVisibility from '../components/thread-visibility.react';
import {
  type Colors,
  colorsPropType,
  colorsSelector,
  styleSelector,
} from '../themes/colors';

const tagInputProps = {
  placeholder: 'username',
  autoFocus: true,
  returnKeyType: 'go',
};

type NavProp = NavigationScreenProp<{|
  ...NavigationLeafRoute,
  params: {|
    threadType?: ThreadType,
    parentThreadID?: string,
    createButtonDisabled?: boolean,
  |},
|}>;

let queuedPress = false;
function setQueuedPress() {
  queuedPress = true;
}
let onPressCreateThread = setQueuedPress;
function setOnPressCreateThread(func: ?() => void) {
  if (!func) {
    onPressCreateThread = setQueuedPress;
    return;
  }
  onPressCreateThread = func;
  if (queuedPress) {
    onPressCreateThread();
    queuedPress = false;
  }
}
function pressCreateThread() {
  onPressCreateThread();
}

type Props = {|
  navigation: NavProp,
  // Redux state
  parentThreadInfo: ?ThreadInfo,
  loadingStatus: LoadingStatus,
  otherUserInfos: { [id: string]: AccountUserInfo },
  userSearchIndex: SearchIndex,
  threadInfos: { [id: string]: ThreadInfo },
  colors: Colors,
  styles: Styles,
  // Redux dispatch functions
  dispatchActionPromise: DispatchActionPromise,
  // async functions that hit server APIs
  newThread: (request: NewThreadRequest) => Promise<NewThreadResult>,
  searchUsers: (usernamePrefix: string) => Promise<UserSearchResult>,
|};
type State = {|
  usernameInputText: string,
  userInfoInputArray: $ReadOnlyArray<AccountUserInfo>,
|};
type PropsAndState = {| ...Props, ...State |};
class ComposeThread extends React.PureComponent<Props, State> {
  static propTypes = {
    navigation: PropTypes.shape({
      state: PropTypes.shape({
        key: PropTypes.string.isRequired,
        params: PropTypes.shape({
          parentThreadID: PropTypes.string,
          threadType: threadTypePropType,
        }).isRequired,
      }).isRequired,
      setParams: PropTypes.func.isRequired,
      goBack: PropTypes.func.isRequired,
      navigate: PropTypes.func.isRequired,
      getParam: PropTypes.func.isRequired,
    }).isRequired,
    parentThreadInfo: threadInfoPropType,
    loadingStatus: loadingStatusPropType.isRequired,
    otherUserInfos: PropTypes.objectOf(accountUserInfoPropType).isRequired,
    userSearchIndex: PropTypes.instanceOf(SearchIndex).isRequired,
    threadInfos: PropTypes.objectOf(threadInfoPropType).isRequired,
    colors: colorsPropType.isRequired,
    styles: PropTypes.objectOf(PropTypes.object).isRequired,
    dispatchActionPromise: PropTypes.func.isRequired,
    newThread: PropTypes.func.isRequired,
    searchUsers: PropTypes.func.isRequired,
  };
  static navigationOptions = ({ navigation }) => ({
    title: 'Compose thread',
    headerRight: (
      <LinkButton
        text="Create"
        onPress={pressCreateThread}
        disabled={!!navigation.getParam('createButtonDisabled')}
      />
    ),
    headerBackTitle: 'Back',
  });
  state = {
    usernameInputText: '',
    userInfoInputArray: [],
  };
  tagInput: ?TagInput<AccountUserInfo>;
  createThreadPressed = false;

  componentDidMount() {
    setOnPressCreateThread(this.onPressCreateThread);
    this.searchUsers('');
  }

  componentWillUnmount() {
    setOnPressCreateThread(null);
  }

  userSearchResultsSelector = createSelector(
    (propsAndState: PropsAndState) => propsAndState.usernameInputText,
    (propsAndState: PropsAndState) => propsAndState.otherUserInfos,
    (propsAndState: PropsAndState) => propsAndState.userSearchIndex,
    (propsAndState: PropsAndState) => propsAndState.userInfoInputArray,
    (propsAndState: PropsAndState) => propsAndState.parentThreadInfo,
    (
      text: string,
      userInfos: { [id: string]: AccountUserInfo },
      searchIndex: SearchIndex,
      userInfoInputArray: $ReadOnlyArray<AccountUserInfo>,
      parentThreadInfo: ?ThreadInfo,
    ) =>
      getUserSearchResults(
        text,
        userInfos,
        searchIndex,
        userInfoInputArray.map(userInfo => userInfo.id),
        parentThreadInfo,
      ),
  );

  get userSearchResults() {
    return this.userSearchResultsSelector({ ...this.props, ...this.state });
  }

  existingThreadsSelector = createSelector(
{'fraction_non_alphanumeric': 0.11649810854628272, 'fraction_numerical': 0.0, 'mean_word_length': 4.402001668056714, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1991085', 'n_tokens_mistral': 3778, 'n_tokens_neox': 3773, 'n_words': 791}