import React from 'react'; import PropTypes from 'prop-types'; import { View, FlatList, Text } from 'react-native'; import { connect } from 'react-redux'; import * as List from '../../containers/List'; import Touch from '../../utils/touch'; import RocketChat from '../../lib/rocketchat'; import DirectoryItem from '../../presentation/DirectoryItem'; import sharedStyles from '../Styles'; import I18n from '../../i18n'; import SearchBox from '../../containers/SearchBox'; import { CustomIcon } from '../../lib/Icons'; import StatusBar from '../../containers/StatusBar'; import ActivityIndicator from '../../containers/ActivityIndicator'; import * as HeaderButton from '../../containers/HeaderButton'; import debounce from '../../utils/debounce'; import log, { logEvent, events } from '../../utils/log'; import Options from './Options'; import { withTheme } from '../../theme'; import { themes } from '../../constants/colors'; import styles from './styles'; import { getUserSelector } from '../../selectors/login'; import SafeAreaView from '../../containers/SafeAreaView'; import { goRoom } from '../../utils/goRoom'; class DirectoryView extends React.Component { static navigationOptions = ({ navigation, isMasterDetail }) => { const options = { title: I18n.t('Directory') }; if (isMasterDetail) { options.headerLeft = () => ; } return options; } static propTypes = { navigation: PropTypes.object, baseUrl: PropTypes.string, isFederationEnabled: PropTypes.bool, user: PropTypes.shape({ id: PropTypes.string, token: PropTypes.string }), theme: PropTypes.string, directoryDefaultView: PropTypes.string, isMasterDetail: PropTypes.bool }; constructor(props) { super(props); this.state = { data: [], loading: false, text: '', total: -1, showOptionsDropdown: false, globalUsers: true, type: props.directoryDefaultView }; } componentDidMount() { this.load({}); } onSearchChangeText = (text) => { this.setState({ text }, this.search); } // eslint-disable-next-line react/sort-comp load = debounce(async({ newSearch = false }) => { if (newSearch) { this.setState({ data: [], total: -1, loading: false }); } const { loading, text, total, data: { length } } = this.state; if (loading || length === total) { return; } this.setState({ loading: true }); try { const { data, type, globalUsers } = this.state; const query = { text, type, workspace: globalUsers ? 'all' : 'local' }; const directories = await RocketChat.getDirectory({ query, offset: data.length, count: 50, sort: (type === 'users') ? { username: 1 } : { usersCount: -1 } }); if (directories.success) { this.setState({ data: [...data, ...directories.result], loading: false, total: directories.total }); } else { this.setState({ loading: false }); } } catch (e) { log(e); this.setState({ loading: false }); } }, 200) search = () => { this.load({ newSearch: true }); } changeType = (type) => { this.setState({ type, data: [] }, () => this.search()); if (type === 'users') { logEvent(events.DIRECTORY_SEARCH_USERS); } else if (type === 'channels') { logEvent(events.DIRECTORY_SEARCH_CHANNELS); } else if (type === 'teams') { logEvent(events.DIRECTORY_SEARCH_TEAMS); } } toggleWorkspace = () => { this.setState(({ globalUsers }) => ({ globalUsers: !globalUsers, data: [] }), () => this.search()); } toggleDropdown = () => { this.setState(({ showOptionsDropdown }) => ({ showOptionsDropdown: !showOptionsDropdown })); } goRoom = (item) => { const { navigation, isMasterDetail } = this.props; if (isMasterDetail) { navigation.navigate('DrawerNavigator'); } else { navigation.navigate('RoomsListView'); } goRoom({ item, isMasterDetail }); } onPressItem = async(item) => { const { type } = this.state; if (type === 'users') { const result = await RocketChat.createDirectMessage(item.username); if (result.success) { this.goRoom({ rid: result.room._id, name: item.username, t: 'd' }); } } else if (['p', 'c'].includes(item.t) && !item.teamMain) { const { room } = await RocketChat.getRoomInfo(item._id); this.goRoom({ rid: item._id, name: item.name, joinCodeRequired: room.joinCodeRequired, t: 'c', search: true }); } else { this.goRoom({ rid: item._id, name: item.name, t: item.t, search: true, teamMain: item.teamMain, teamId: item.teamId }); } } renderHeader = () => { const { type } = this.state; const { theme } = this.props; let text = 'Users'; let icon = 'user'; if (type === 'channels') { text = 'Channels'; icon = 'channel-public'; } if (type === 'teams') { text = 'Teams'; icon = 'teams'; } return ( <> {I18n.t(text)} ); } renderItem = ({ item, index }) => { const { data, type } = this.state; const { baseUrl, user, theme } = this.props; let style; if (index === data.length - 1) { style = { ...sharedStyles.separatorBottom, borderColor: themes[theme].separatorColor }; } const commonProps = { title: item.name, onPress: () => this.onPressItem(item), baseUrl, testID: `directory-view-item-${ item.name }`.toLowerCase(), style, user, theme, rid: item._id }; if (type === 'users') { return ( ); } if (type === 'teams') { return ( ); } return ( ); } render = () => { const { data, loading, showOptionsDropdown, type, globalUsers } = this.state; const { isFederationEnabled, theme } = this.props; return ( item._id} ListHeaderComponent={this.renderHeader} renderItem={this.renderItem} ItemSeparatorComponent={List.Separator} keyboardShouldPersistTaps='always' ListFooterComponent={loading ? : null} onEndReached={() => this.load({})} /> {showOptionsDropdown ? ( ) : null} ); } } const mapStateToProps = state => ({ baseUrl: state.server.server, user: getUserSelector(state), isFederationEnabled: state.settings.FEDERATION_Enabled, directoryDefaultView: state.settings.Accounts_Directory_DefaultView, isMasterDetail: state.app.isMasterDetail }); export default connect(mapStateToProps)(withTheme(DirectoryView));