import React from 'react'; import PropTypes from 'prop-types'; import { Keyboard, Text, ScrollView, View, StyleSheet, Alert } from 'react-native'; import { connect } from 'react-redux'; import SafeAreaView from 'react-native-safe-area-view'; import equal from 'deep-equal'; import { analytics } from '../utils/log'; import KeyboardView from '../presentation/KeyboardView'; import TextInput from '../containers/TextInput'; import Button from '../containers/Button'; import sharedStyles from './Styles'; import scrollPersistTaps from '../utils/scrollPersistTaps'; import I18n from '../i18n'; import { loginRequest as loginRequestAction } from '../actions/login'; import { LegalButton } from '../containers/HeaderButton'; import StatusBar from '../containers/StatusBar'; import { COLOR_PRIMARY } from '../constants/colors'; import { animateNextTransition } from '../utils/layoutAnimation'; const styles = StyleSheet.create({ bottomContainer: { flexDirection: 'column', alignItems: 'center', marginTop: 10 }, dontHaveAccount: { ...sharedStyles.textRegular, ...sharedStyles.textColorDescription, fontSize: 13 }, createAccount: { ...sharedStyles.textSemibold, color: COLOR_PRIMARY, fontSize: 13 }, loginTitle: { marginVertical: 0, marginTop: 15 } }); class LoginView extends React.Component { static navigationOptions = ({ navigation }) => { const title = navigation.getParam('title', 'Rocket.Chat'); return { title, headerRight: }; } static propTypes = { navigation: PropTypes.object, loginRequest: PropTypes.func.isRequired, error: PropTypes.object, Site_Name: PropTypes.string, Accounts_EmailOrUsernamePlaceholder: PropTypes.string, Accounts_PasswordPlaceholder: PropTypes.string, Accounts_PasswordReset: PropTypes.bool, isFetching: PropTypes.bool, failure: PropTypes.bool } static defaultProps = { Accounts_PasswordReset: true } constructor(props) { super(props); this.state = { user: '', password: '', code: '', showTOTP: false }; const { Site_Name } = this.props; this.setTitle(Site_Name); } componentWillReceiveProps(nextProps) { const { Site_Name, error } = this.props; if (nextProps.Site_Name && nextProps.Site_Name !== Site_Name) { this.setTitle(nextProps.Site_Name); } else if (nextProps.failure && !equal(error, nextProps.error)) { if (nextProps.error && nextProps.error.error === 'totp-required') { animateNextTransition(); this.setState({ showTOTP: true }); return; } Alert.alert(I18n.t('Oops'), I18n.t('Login_error')); } } shouldComponentUpdate(nextProps, nextState) { const { user, password, code, showTOTP } = this.state; const { isFetching, failure, error, Site_Name, Accounts_EmailOrUsernamePlaceholder, Accounts_PasswordPlaceholder } = this.props; if (nextState.user !== user) { return true; } if (nextState.password !== password) { return true; } if (nextState.code !== code) { return true; } if (nextState.showTOTP !== showTOTP) { return true; } if (nextProps.isFetching !== isFetching) { return true; } if (nextProps.failure !== failure) { return true; } if (nextProps.Site_Name !== Site_Name) { return true; } if (nextProps.Accounts_EmailOrUsernamePlaceholder !== Accounts_EmailOrUsernamePlaceholder) { return true; } if (nextProps.Accounts_PasswordPlaceholder !== Accounts_PasswordPlaceholder) { return true; } if (!equal(nextProps.error, error)) { return true; } return false; } setTitle = (title) => { const { navigation } = this.props; navigation.setParams({ title }); } valid = () => { const { user, password, code, showTOTP } = this.state; if (showTOTP) { return code.trim(); } return user.trim() && password.trim(); } submit = () => { if (!this.valid()) { return; } const { user, password, code } = this.state; const { loginRequest } = this.props; Keyboard.dismiss(); loginRequest({ user, password, code }); analytics().logEvent('login'); } register = () => { const { navigation, Site_Name } = this.props; navigation.navigate('RegisterView', { title: Site_Name }); } forgotPassword = () => { const { navigation, Site_Name } = this.props; navigation.navigate('ForgotPasswordView', { title: Site_Name }); } renderTOTP = () => { const { isFetching } = this.props; return ( {I18n.t('Two_Factor_Authentication')} {I18n.t('Whats_your_2fa')} this.codeInput = ref} autoFocus onChangeText={value => this.setState({ code: value })} keyboardType='numeric' returnKeyType='send' autoCapitalize='none' onSubmitEditing={this.submit} testID='login-view-totp' containerStyle={sharedStyles.inputLastChild} />