import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { ScrollView, Text, View, StyleSheet, FlatList, LayoutAnimation, SafeAreaView } from 'react-native'; import { connect } from 'react-redux'; import FastImage from 'react-native-fast-image'; import Icon from 'react-native-vector-icons/MaterialIcons'; import database from '../lib/realm'; import { selectServerRequest } from '../actions/server'; import { logout } from '../actions/login'; import Avatar from '../containers/Avatar'; import Status from '../containers/status'; import Touch from '../utils/touch'; import { STATUS_COLORS } from '../constants/colors'; import RocketChat from '../lib/rocketchat'; import log from '../utils/log'; import I18n from '../i18n'; import { NavigationActions } from '../Navigation'; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff' }, item: { flexDirection: 'row', alignItems: 'center' }, itemLeft: { marginHorizontal: 10, width: 30, alignItems: 'center' }, itemText: { marginVertical: 16, fontWeight: 'bold', color: '#292E35' }, separator: { borderBottomWidth: StyleSheet.hairlineWidth, borderColor: '#ddd', marginVertical: 4 }, serverImage: { width: 24, height: 24, borderRadius: 4 }, header: { paddingVertical: 16, flexDirection: 'row', alignItems: 'center' }, headerTextContainer: { flex: 1, flexDirection: 'column', alignItems: 'flex-start' }, headerUsername: { flexDirection: 'row', alignItems: 'center' }, avatar: { marginHorizontal: 10 }, status: { borderRadius: 12, width: 12, height: 12, marginRight: 5 }, currentServerText: { fontWeight: 'bold' } }); const keyExtractor = item => item.id; @connect(state => ({ server: state.server.server, user: { id: state.login.user && state.login.user.id, language: state.login.user && state.login.user.language, server: state.login.user && state.login.user.server, status: state.login.user && state.login.user.status, username: state.login.user && state.login.user.username } }), dispatch => ({ selectServerRequest: server => dispatch(selectServerRequest(server)), logout: () => dispatch(logout()) })) export default class Sidebar extends Component { static propTypes = { navigator: PropTypes.object, server: PropTypes.string.isRequired, selectServerRequest: PropTypes.func.isRequired, user: PropTypes.object, logout: PropTypes.func.isRequired } constructor(props) { super(props); this.state = { servers: [], showServers: false }; } componentDidMount() { this.setState(this.getState()); this.setStatus(); database.databases.serversDB.addListener('change', this.updateState); } componentWillReceiveProps(nextProps) { if (nextProps.user && this.props.user && this.props.user.language !== nextProps.user.language) { this.setStatus(); } } componentWillUnmount() { database.databases.serversDB.removeListener('change', this.updateState); } onPressItem = (item) => { this.props.selectServerRequest(item.id); } setStatus = () => { setTimeout(() => { this.setState({ status: [{ id: 'online', name: I18n.t('Online') }, { id: 'busy', name: I18n.t('Busy') }, { id: 'away', name: I18n.t('Away') }, { id: 'offline', name: I18n.t('Invisible') }] }); }); } getState = () => ({ servers: database.databases.serversDB.objects('servers') }) updateState = () => { this.setState(this.getState()); } closeDrawer = () => { this.props.navigator.toggleDrawer({ side: 'left', animated: true, to: 'close' }); } toggleServers = () => { LayoutAnimation.easeInEaseOut(); this.setState({ showServers: !this.state.showServers }); } sidebarNavigate = (screen, title) => { this.closeDrawer(); NavigationActions.resetTo({ screen, title }); } renderSeparator = key => <View key={key} style={styles.separator} />; renderItem = ({ text, left, onPress, testID }) => ( <Touch key={text} onPress={onPress} underlayColor='rgba(255, 255, 255, 0.5)' activeOpacity={0.3} testID={testID} > <View style={styles.item}> <View style={styles.itemLeft}> {left} </View> <Text style={styles.itemText}> {text} </Text> </View> </Touch> ) renderStatusItem = ({ item }) => ( this.renderItem({ text: item.name, left: <View style={[styles.status, { backgroundColor: STATUS_COLORS[item.id] }]} />, selected: this.props.user.status === item.id, onPress: () => { this.closeDrawer(); this.toggleServers(); if (this.props.user.status !== item.id) { try { RocketChat.setUserPresenceDefaultStatus(item.id); } catch (e) { log('onPressModalButton', e); } } } }) ) renderServer = ({ item }) => ( this.renderItem({ text: item.id, left: <FastImage style={styles.serverImage} source={{ uri: encodeURI(`${ item.id }/assets/favicon_32.png`) }} />, selected: this.props.server === item.id, onPress: async() => { this.closeDrawer(); this.toggleServers(); if (this.props.server !== item.id) { this.props.selectServerRequest(item.id); } }, testID: `sidebar-${ item.id }` }) ) renderNavigation = () => ( [ this.renderItem({ text: I18n.t('Chats'), left: <Icon name='chat-bubble' size={20} />, onPress: () => this.sidebarNavigate('RoomsListView', I18n.t('Messages')), testID: 'sidebar-chats' }), this.renderItem({ text: I18n.t('Profile'), left: <Icon name='person' size={20} />, onPress: () => this.sidebarNavigate('ProfileView', I18n.t('Profile')), testID: 'sidebar-profile' }), this.renderItem({ text: I18n.t('Settings'), left: <Icon name='settings' size={20} />, onPress: () => this.sidebarNavigate('SettingsView', I18n.t('Settings')), testID: 'sidebar-settings' }), this.renderSeparator('separator-logout'), this.renderItem({ text: I18n.t('Logout'), left: <Icon name='exit-to-app' size={20} />, onPress: () => this.props.logout(), testID: 'sidebar-logout' }) ] ) renderServers = () => ( [ <FlatList key='status-list' data={this.state.status} extraData={this.props.user} renderItem={this.renderStatusItem} keyExtractor={keyExtractor} />, this.renderSeparator('separator-status'), <FlatList key='servers-list' data={this.state.servers} extraData={this.props.server} renderItem={this.renderServer} keyExtractor={keyExtractor} />, this.renderSeparator('separator-add-server'), this.renderItem({ text: I18n.t('Add_Server'), left: <Icon name='add' size={20} />, onPress: () => { this.closeDrawer(); this.toggleServers(); NavigationActions.push({ screen: 'NewServerView', title: I18n.t('Add_Server') }); }, testID: 'sidebar-add-server' }) ] ) render() { const { user, server } = this.props; if (!user) { return null; } return ( <ScrollView style={styles.container}> <SafeAreaView testID='sidebar' style={styles.container}> <Touch onPress={() => this.toggleServers()} underlayColor='rgba(255, 255, 255, 0.5)' activeOpacity={0.3} testID='sidebar-toggle-server' > <View style={styles.header}> <Avatar text={user.username} size={30} style={styles.avatar} /> <View style={styles.headerTextContainer}> <View style={styles.headerUsername}> <Status style={styles.status} id={user.id} /> <Text numberOfLines={1}>{user.username}</Text> </View> <Text style={styles.currentServerText} numberOfLines={1}>{server}</Text> </View> <Icon name={this.state.showServers ? 'keyboard-arrow-up' : 'keyboard-arrow-down'} size={30} style={{ paddingHorizontal: 10 }} /> </View> </Touch> {this.renderSeparator('separator-header')} {!this.state.showServers ? this.renderNavigation() : null} {this.state.showServers ? this.renderServers() : null} </SafeAreaView> </ScrollView> ); } }