src/components/views/login-view.js
import React, {Component} from 'react';
import { View, Text, StyleSheet, Image, PixelRatio, Alert, TouchableOpacity, Button, KeyboardAvoidingView, Platform, ActivityIndicator } from 'react-native';
import { TextInput } from 'react-native-paper';
import Icon from 'react-native-vector-icons/FontAwesome';
import { styles, text, colours, login_styles } from './stylesheets/login-styles';
import BaseView from './view';
import SafeArea from './helpers/safearea';
import LoginButton from './helpers/loginbutton';
import LoginPresenter from '../presenters/login-presenter';
let logo = require('../../assets/images/ppInvertedLogo.png');
/**
* Class for the Login view
* @extends BaseView
*/
class LoginView extends BaseView {
static navigationOptions = {header:null};
/**
* Create an instance of LoginView
*
* @constructor
* @param {Object} props - Component properties
*/
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
loaderVisible: false,
};
this.LoginP = new LoginPresenter(this);
}
/**
* Navigate to the tabs screen.
*/
navigateToTabs = () => {
this.setState({loaderVisible: false});
this.props.navigation.navigate('Tabs');
}
/**
* Handle the click of the signup button.
*/
_handleClick = () => {
this.setState({loaderVisible: true});
if (this.LoginP.checkInput(this.state.username, this.state.password, this.reportError)) {
this.sendUpdate();
}
}
/**
* Handle the Twitter icon click.
*/
_handleClickT = () => {
if (Platform.OS !== 'ios' ) {
console.log('clicked twitter')
this.LoginP.updateT(this.onError);
} else {
Alert.alert(
'Twitter login on iOS is currently disabled',
"",
[
{text: 'OK', onPress: () => {}},
],
{cancelable: false},
);
}
}
/**
* Alert popup with a message.
*
* @param {string} message - An error message
*/
onError = (message) => {
Alert.alert(
message,
"",
[
{text: 'OK', onPress: () => {}},
],
{cancelable: false},
);
}
/**
* Handles a Facebook icon click.
*/
_handleClickF = () => {
if (Platform.OS !== 'ios' ) {
console.log('clicked facebook')
this.LoginP.updateF(this.onError);
} else {
Alert.alert(
'Facebook login on iOS is currently disabled',
"",
[
{text: 'OK', onPress: () => {}},
],
{cancelable: false},
);
}
}
/**
* Called if the user input username or password is invalid.
* @param {Object} errmsg - the error message that corresponding to the problem.
*/
reportError = (errmsg) => {
this.setState({loaderVisible: false});
Alert.alert(
'Error',
errmsg,
[
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{cancelable: false},
);
}
/**
* Send an update to the presenter
*/
sendUpdate = () => {
// Extract data from components
let new_data = {
data: {
username: this.state.username,
password: this.state.password
}
}
let data = new_data;
this.LoginP.update(data);
}
/**
* Refreshes the state of the component so new data is fetched.
*/
refreshState = () => {
this.setState({
refresh: !this.state.refresh
});
};
/**
* Handle an incorrect login by displaying an alert
*/
handleLoginIncorrect = () => {
this.setState({loaderVisible: false});
Alert.alert(
'Error',
'Username or Password is incorrect or email needs to be verified.',
[
{ text: "Ok", onPress: () => {}, style: "ok" },
],
{cancelable: false}
);
};
/**
* Component will unmount after this method is called, do any clean up here
* Call viewUnmounting in base class so it can do any cleanup for the view before calling the presenter destroy method
*/
componentWillUnmount = () => {
this.viewUnmounting(this.LoginP);
}
/**
* Renders the main content on the screen.
* Defined in a function because on Android we don't render the KeyboardAvoidingView
*/
renderContent = () => (
<View>
<View style={login_styles.centered}>
<Image source={logo} style={login_styles.image} resizeMode="contain" />
</View>
<View style={login_styles.editGroup}>
<View style={login_styles.username}>
<TextInput
style={text.textInput}
label="Username"
textContentType='username'
autoCapitalize="none"
value={this.state.username}
onChangeText={(username) => this.setState({username})}/>
</View>
<View style={login_styles.password}>
<TextInput
style={text.textInput}
label="Password"
textContentType='password'
secureTextEntry
value={this.state.password}
onChangeText={(password) => this.setState({password})}/>
</View>
<View style={{marginTop: 30}}>
<LoginButton text="SIGN IN" onPress={this._handleClick.bind(this)}/>
</View>
</View>
</View>
);
/**
* Renders the social media icons.
*/
_renderSocialMedia = () => (
<View style={login_styles.socialMedia}>
<Text style={login_styles.centerText}> Login With Social Account: </Text>
<View style={login_styles.socialIcons}>
<Icon.Button
name="facebook"
type="FontAwesome"
color="#000000"
backgroundColor={'transparent'}
onPress={() => this._handleClickF()}
size={30}
style={{marginRight: 10}}>
</Icon.Button>
<Icon.Button
name="twitter"
type="FontAwesome"
color="#000000"
backgroundColor={'transparent'}
onPress={() => this._handleClickT()}
size={30}
style={{marginLeft: 10}}>
</Icon.Button>
</View>
</View>
);
/**
* Extract data from the component's view and send an update to the presenter to do any logic before sending it to the model
*/
render() {
return (
<View style={[styles.container]}>
<SafeArea overrideColour={colours.ppGrey} />
{
Platform.OS === 'ios' &&
<KeyboardAvoidingView
style={styles.container}
behavior="padding"
enabled>
{this.renderContent()}
</KeyboardAvoidingView>
}
{
Platform.OS !== 'ios' &&
this.renderContent()
}
{this._renderSocialMedia()}
<View style={login_styles.bottom}>
<TouchableOpacity style={login_styles.signupButton} onPress={() => this.props.navigation.navigate('Signup')}>
<Text style={login_styles.signupText}>
{"New Member? SIGN UP!"}
</Text>
</TouchableOpacity>
</View>
{
this.state.loaderVisible &&
<View style={login_styles.loading} pointerEvents="none">
<ActivityIndicator size='small' color="#0000ff" />
</View>
}
</View>
);
}
}
export default LoginView;