verdnatura-chat/app/views/SidebarView/index.js

285 lines
7.4 KiB
JavaScript
Raw Normal View History

2019-03-12 16:23:06 +00:00
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
ScrollView, Text, View, FlatList, LayoutAnimation, SafeAreaView
} from 'react-native';
import { connect } from 'react-redux';
import equal from 'deep-equal';
import { RectButton } from 'react-native-gesture-handler';
import { logout as logoutAction } from '../../actions/login';
import Avatar from '../../containers/Avatar';
import StatusContainer from '../../containers/Status';
import Status from '../../containers/Status/Status';
import RocketChat from '../../lib/rocketchat';
import log from '../../utils/log';
import I18n from '../../i18n';
import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { CustomIcon } from '../../lib/Icons';
import styles from './styles';
import SidebarItem from './SidebarItem';
2019-03-29 19:36:07 +00:00
import { COLOR_TEXT } from '../../constants/colors';
import database from '../../lib/realm';
2019-03-12 16:23:06 +00:00
const keyExtractor = item => item.id;
const Separator = React.memo(() => <View style={styles.separator} />);
const permissions = [
'view-statistics',
'view-room-administration',
'view-user-administration',
'view-privileged-setting'
];
2019-03-12 16:23:06 +00:00
@connect(state => ({
Site_Name: state.settings.Site_Name,
user: {
id: state.login.user && state.login.user.id,
language: state.login.user && state.login.user.language,
status: state.login.user && state.login.user.status,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token,
roles: state.login.user && state.login.user.roles
2019-03-12 16:23:06 +00:00
},
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
}), dispatch => ({
logout: () => dispatch(logoutAction())
}))
export default class Sidebar extends Component {
static propTypes = {
baseUrl: PropTypes.string,
navigation: PropTypes.object,
Site_Name: PropTypes.string.isRequired,
user: PropTypes.object,
logout: PropTypes.func.isRequired,
activeItemKey: PropTypes.string
}
constructor(props) {
super(props);
this.state = {
showStatus: false,
status: []
};
}
componentDidMount() {
this.setStatus();
}
componentWillReceiveProps(nextProps) {
const { user } = this.props;
if (nextProps.user && user && user.language !== nextProps.user.language) {
this.setStatus();
}
}
shouldComponentUpdate(nextProps, nextState) {
const { status, showStatus } = this.state;
const {
Site_Name, user, baseUrl, activeItemKey
} = this.props;
if (nextState.showStatus !== showStatus) {
return true;
}
if (nextProps.Site_Name !== Site_Name) {
return true;
}
if (nextProps.Site_Name !== Site_Name) {
return true;
}
if (nextProps.baseUrl !== baseUrl) {
return true;
}
if (nextProps.activeItemKey !== activeItemKey) {
return true;
}
if (nextProps.user && user) {
if (nextProps.user.language !== user.language) {
return true;
}
if (nextProps.user.status !== user.status) {
return true;
}
if (nextProps.user.username !== user.username) {
return true;
}
}
if (!equal(nextState.status, status)) {
return true;
}
return false;
}
setStatus = () => {
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')
}]
});
}
toggleStatus = () => {
LayoutAnimation.easeInEaseOut();
this.setState(prevState => ({ showStatus: !prevState.showStatus }));
}
sidebarNavigate = (route) => {
const { navigation } = this.props;
navigation.navigate(route);
}
logout = () => {
const { logout } = this.props;
logout();
}
canSeeAdminPanel() {
const { user } = this.props;
const { roles } = user;
if (roles) {
const permissionsFiltered = database.objects('permissions')
.filter(permission => permissions.includes(permission._id));
return permissionsFiltered.reduce((result, permission) => (
[RELEASE] Merge beta into master (#1055) * Bump version to 1.16.0 (#1014) * [IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982) * :sparkles: Create user table * :sparkles: Introduce user table * :fire: Remove unused table * :heavy_plus_sign: Add userdefaults to storage data * :green_heart: Fix android build * :sparkles: Get credentials from iOS native client * :fire: Remove unused code * :rewind: Revert sign xcode * :bug: Fix first login-logout * :art: Use constants to UserDefaults Keys * :bug: Fix clear server-user-info on logout * :bug: Fix filter null value * :ambulance: Remove user object in logout * :sparkles: Fix get servers from native-client * :ambulance: Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * :bug: Fix native credentials (android) * Fix migration loop * [IMPROVEMENT] Hide frequently used emoji tab when empty (#792) * [IMPROVEMENT] Bigger emoji in emoji only messages (#793) * issue #725: bigger emoji in emoji only message * issue-725/add storybook for Message/Emoji * issue-725: update storybook/Message jest snapshot * comment storybook import * allow spaces and line breaks in emoji only message * merge develop * revert unnecessary spacing * [FIX] Empty message if contains only a link (#787) * Fix empty message if contains only a link * :bug: Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * :art: Improve regex to empty space on quote * :art: Improve on regex to empty space on quote * [NEW] Custom fields on signup (#1013) * added custom feilds on registration * added flag as leftIcon and removed lable * added try and catch * typo * [CHORE] Renew provisioning profiles (#1020) * [NEW] Auto-translate (#1012) * Update realm * View original and translate working * Read AutoTranslate_Enabled setting * RocketChat.canAutoTranslate() * AutoTranslateView * Save language * Auto-translate switch * Translate message * [IMPROVEMENT] Use haptics rather than vibration (#1016) * Install expo-haptics * Use expo-haptics rather than RN's Vibration module * [IMPROVEMENT] Use Rest API for file upload (#1005) * removed rn-fetch-blob and use native XMLHttpRequest instead * removed unnessary changes * fix android bug * fix android bug * added tmid support * fix bug * fixed isssue with cacel model * fix problems with audio * done requested changes * fix bug with android * [CHORE] [CI] [TESTS] update detox to make ci pass (#1026) * feat: update detox to 12.11.3 to make CI pass * ci: comment all jobs but leave e2e-test job * commit to rerun IC e2e-test job * ci: uncomment all CI jobs * [NEW] Room swipe actions: mark as read/unread, hide, fav (#976) * added unread and fav feature * changed the layout * fix jest * done requested changes * added requested changes * [FIX] Android build (#1027) * [FIX] Android build * CircleCI error * [FIX] iOS share credentials build (#1028) * [FIX] iOS share credentials build * Use `hasMigration` as a string * [CI] Restore cache on CI (#1029) * feat: add fastlane save\restore cache config; comment not needed jobs; * install fastlane using 'bundle install' * install fastlane using 'sudo bundle install' * uncomment ios build commands * run set up google services in ios folder * add working_directory: ios to ios-build steps * remove 'cd ios' from Fastlane build step * add save\restore cache for npm modules * group save_cache steps * cache fastlane in ios-testflight job * uncomment previously commented jobs\steps * fix: add missing colon * use key for caching: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }} * add names for save\restore steps * ci: add `default` step with `working_directory: ~/repo` to ios-build job * return back caching npm: `node-v1-{{ checksum "package.json" }}-{{ arch }}` * fix: add missing curly braces * save\restore cache in e2e-test job; remove {{arch}} from cache names * add names to restore_cache steps in android-build job * add names to save_cache steps in android-build job * add names to all save\restore steps; change checksum package.json to yarn.lock * change `npm` to `NPM` in steps naming * remove {{ checksum circle ci }} from android-build job and fix naming of steps * [FIX] Rooms swipes (#1034) * Regression: on press style feedback * Action button styles * Fix animations * Styles changed * Update subscription without having to wait for socket * Calculate width on RoomsListView instead * [FIX] Decrease bigger emoji size to 30 (#1031) * [FIX] Append server URL on avatar if necessary (#1038) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Bump version to 1.16.1 (#1045) * [FIX] Set UserDefaults AppGroup on notification tap (#1047) * [FIX] Auto-translate messages as they arrive * Fix favorite button
2019-07-15 17:24:48 +00:00
result || permission.roles.some(r => roles.indexOf(r) !== -1)),
false);
}
return false;
}
2019-03-12 16:23:06 +00:00
renderStatusItem = ({ item }) => {
const { user } = this.props;
return (
<SidebarItem
text={item.name}
left={<Status style={styles.status} size={12} status={item.id} />}
current={user.status === item.id}
onPress={() => {
this.toggleStatus();
if (user.status !== item.id) {
try {
RocketChat.setUserPresenceDefaultStatus(item.id);
} catch (e) {
2019-05-28 16:18:46 +00:00
log('err_set_user_presence_default_status', e);
2019-03-12 16:23:06 +00:00
}
}
}}
/>
);
}
renderNavigation = () => {
const { activeItemKey } = this.props;
return (
<React.Fragment>
<SidebarItem
text={I18n.t('Chats')}
2019-04-08 12:35:28 +00:00
left={<CustomIcon name='message' size={20} color={COLOR_TEXT} />}
2019-03-12 16:23:06 +00:00
onPress={() => this.sidebarNavigate('RoomsListView')}
testID='sidebar-chats'
current={activeItemKey === 'ChatsStack'}
/>
<SidebarItem
text={I18n.t('Profile')}
2019-03-29 19:36:07 +00:00
left={<CustomIcon name='user' size={20} color={COLOR_TEXT} />}
2019-03-12 16:23:06 +00:00
onPress={() => this.sidebarNavigate('ProfileView')}
testID='sidebar-profile'
current={activeItemKey === 'ProfileStack'}
/>
<SidebarItem
text={I18n.t('Settings')}
2019-03-29 19:36:07 +00:00
left={<CustomIcon name='cog' size={20} color={COLOR_TEXT} />}
2019-03-12 16:23:06 +00:00
onPress={() => this.sidebarNavigate('SettingsView')}
testID='sidebar-settings'
current={activeItemKey === 'SettingsStack'}
/>
{this.canSeeAdminPanel() ? (
<SidebarItem
text={I18n.t('Admin_Panel')}
left={<CustomIcon name='shield-alt' size={20} color={COLOR_TEXT} />}
onPress={() => this.sidebarNavigate('AdminPanelView')}
testID='sidebar-settings'
current={activeItemKey === 'AdminPanelStack'}
/>
) : null}
2019-03-12 16:23:06 +00:00
<Separator key='separator-logout' />
<SidebarItem
text={I18n.t('Logout')}
2019-03-29 19:36:07 +00:00
left={<CustomIcon name='sign-out' size={20} color={COLOR_TEXT} />}
2019-03-12 16:23:06 +00:00
onPress={this.logout}
testID='sidebar-logout'
/>
</React.Fragment>
);
}
renderStatus = () => {
const { status } = this.state;
const { user } = this.props;
return (
<FlatList
key='status-list'
data={status}
extraData={user}
renderItem={this.renderStatusItem}
keyExtractor={keyExtractor}
/>
);
}
render() {
const { showStatus } = this.state;
const { user, Site_Name, baseUrl } = this.props;
if (!user) {
return null;
}
return (
<SafeAreaView testID='sidebar-view' style={styles.container}>
<ScrollView style={styles.container} {...scrollPersistTaps}>
<RectButton
onPress={this.toggleStatus}
2019-03-29 19:36:07 +00:00
underlayColor={COLOR_TEXT}
2019-03-12 16:23:06 +00:00
activeOpacity={0.1}
testID='sidebar-toggle-status'
style={styles.header}
>
<Avatar
text={user.username}
size={30}
style={styles.avatar}
baseUrl={baseUrl}
2019-04-18 20:57:35 +00:00
userId={user.id}
token={user.token}
2019-03-12 16:23:06 +00:00
/>
<View style={styles.headerTextContainer}>
<View style={styles.headerUsername}>
<StatusContainer style={styles.status} size={12} id={user.id} />
2019-03-29 19:36:07 +00:00
<Text numberOfLines={1} style={styles.username}>{user.username}</Text>
2019-03-12 16:23:06 +00:00
</View>
<Text style={styles.currentServerText} numberOfLines={1}>{Site_Name}</Text>
</View>
<CustomIcon name='arrow-down' size={20} style={[styles.headerIcon, showStatus && styles.inverted]} />
</RectButton>
<Separator key='separator-header' />
{!showStatus ? this.renderNavigation() : null}
{showStatus ? this.renderStatus() : null}
</ScrollView>
</SafeAreaView>
);
}
}