Skip to content

Instantly share code, notes, and snippets.

@zilahir
Last active May 26, 2019 12:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zilahir/ff52daaaef83a51eaaf89ecfd0b914cb to your computer and use it in GitHub Desktop.
Save zilahir/ff52daaaef83a51eaaf89ecfd0b914cb to your computer and use it in GitHub Desktop.
import React, { Component } from 'react'
import { View, StyleSheet, Text, StatusBar, ActivityIndicator, LinearGradient, Image, NetInfo, Animated, Dimensions, Easing } from 'react-native'
import { connect } from 'react-redux'
import firebase from 'firebase'
import { Facebook } from 'expo'
import { TextField } from 'react-native-material-textfield'
import Button from '../../components/common/Button'
import { colors } from '../../styles/colors'
import Logo from '../../../assets/logo.png'
import { setUser } from "../../actions/setUser"
import SnackBar from "../../components/common/SnackBar"
import Ripple from "../../components/common/Ripple"
const { width } = Dimensions.get('window');
const EXPANDED_BUTTON_WIDTH = width - 100;
const COLLAPSED_BUTTON_WIDTH = 40;
const AnimatedRipple = Animated.createAnimatedComponent(Ripple)
class LoginScreen extends Component {
constructor(props) {
super(props);
this.state = {
userName: '',
password: '',
errorMsg: '',
showLoadingSpinner: false,
isConnected: true,
buttonWidth: new Animated.Value(EXPANDED_BUTTON_WIDTH),
opacity: new Animated.Value(1),
loaderOpacity: new Animated.Value(0),
buttonOpacity: new Animated.Value(1),
rotation: new Animated.Value(0),
circlePosition: { x: 0, y: 0 },
scale: new Animated.Value(0),
circleOpacity: new Animated.Value(0),
inputAnimation: new Animated.Value(1)
}
this.handleLogin = this.handleLogin.bind(this)
this.handleFacebookLogin = this.handleFacebookLogin.bind(this)
}
componentDidMount() {
NetInfo.isConnected.addEventListener('connectionChange', this.handleConnectivityChange)
StatusBar.setBarStyle('light-content', true)
this.state.buttonWidth.addListener(({ value }) => {
if (value === COLLAPSED_BUTTON_WIDTH) {
Animated.parallel([
Animated.timing(this.state.buttonOpacity, {
toValue: 0,
duration: 150
}),
Animated.timing(this.state.loaderOpacity, {
toValue: 1,
duration: 250
}),
Animated.loop(Animated.timing(this.state.rotation, {
toValue: 1,
duration: 300,
easing: Easing.linear
}))
]).start();
// Animate white circle
setTimeout(() => {
Animated.parallel([
Animated.timing(this.state.circleOpacity, {
toValue: 1,
duration: 200
}),
Animated.timing(this.state.scale, {
toValue: 1,
duration: 1100,
easing: Easing.linear
})
]).start();
}, 1000)
}
});
}
componentWillUnmount() {
NetInfo.isConnected.removeEventListener('connectionChange', this.handleConnectivityChange)
}
handleConnectivityChange = isConnected => {
this.setState({ isConnected })
}
handleLogin() {
this.setState({
showLoadingSpinner: true,
errorMsg: ''
})
const { userName, password } = this.state
firebase.auth().signInWithEmailAndPassword(userName, password).then( (user) => {
Animated.parallel([
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 150
}),
Animated.timing(this.state.buttonWidth, {
toValue: COLLAPSED_BUTTON_WIDTH,
duration: 300
}),
Animated.timing(this.state.inputAnimation, {
toValue: 0,
duration: 300,
delay: 100
})
]).start()
this.props.onSetUser(user)
this.props.navigation.navigate('Home')
})
.catch( () => {
firebase.auth().createUserWithEmailAndPassword(userName, password).then( (user) => {
firebase.database().ref(`/users/${firebase.auth().currentUser.uid}`).set({email: firebase.auth().currentUser.email, uid: firebase.auth().currentUser.uid})
this.props.onSetUser(user)
this.props.navigation.navigate('Home')
})
.catch( (error) => {
console.log("error", error)
this.setState({
errorMsg: 'Authentication failed',
showLoadingSpinner: false
})
})
})
}
async handleFacebookLogin() {
const { type, token } = await Facebook.logInWithReadPermissionsAsync('352679058703874', { permissions: ['public_profile'] } )
if (type === 'success') {
const credentials = firebase.auth.FacebookAuthProvider.credential(token);
firebase.auth().signInWithCredential(credentials).catch(error => {
throw new Error(error)
})
}
}
render() {
const inputProps = {
textColor: 'white',
baseColor: 'rgba(255,255,255,0.8)',
tintColor: 'rgba(255,255,255,0.8)'
}
const spin = this.state.rotation.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg']
})
const borderColor = this.state.buttonOpacity.interpolate({
inputRange: [0, 1],
outputRange: ['rgba(0,0,0,0)', 'white']
})
const scale = this.state.scale.interpolate({
inputRange: [0, 1],
outputRange: [0, 100]
})
const translateY = this.state.inputAnimation.interpolate({
inputRange: [0, 1],
outputRange: [0, 60]
})
return (
<View style={styles.container}>
<Image style={styles.background}
source={require('./bg.jpg')} />
<LinearGradient
colors={['transparent', '#ab3f8f']}
style={styles.gradient} />
<Text style={styles.titleStyle}>LOGIN</Text>
<View style={styles.inputContainer}>
<Animated.View style={{
opacity: this.state.inputAnimation,
transform: [{ translateY }]
}}>
<TextField
{...inputProps}
label='Username'
style={styles.inputStyle} />
<TextField
{...inputProps}
label='Password'
secureTextEntry
style={styles.inputStyle} />
</Animated.View>
<AnimatedRipple
onLayout={({ nativeEvent }) => {
// get button coords for the circle
const { x, y } = nativeEvent.layout;
if (this.state.circlePosition.x === 0)
this.setState({ circlePosition: { x, y } })
}}
rippleContainerBorderRadius={20}
rippleOpacity={0.5}
onPress={this.handleLogin}
rippleColor={'white'}
style={{
marginTop: 80,
alignSelf: 'center',
width: this.state.buttonWidth
}}>
<Animated.View style={[styles.loginButtonStyle, { borderColor }]}>
<Animated.Text style={[styles.loginTextStyle, { opacity: this.state.opacity }]}>SIGN IN</Animated.Text>
<Animated.Image style={[
styles.loaderStyle,
{
opacity: this.state.loaderOpacity,
transform: [{ rotate: spin }]
}]} source={require('./spinner.png')} />
</Animated.View>
</AnimatedRipple>
<Text style={styles.bottomTextStyle}>No account?<Text style={{ fontWeight: 'bold' }}> Sign Up</Text></Text>
</View>
{/* Circle View */}
<Animated.View style={[styles.authCircleStyle, {
left: this.state.circlePosition.x + EXPANDED_BUTTON_WIDTH / 2 - 20,
top: this.state.circlePosition.y + 20,
transform: [{ scale }],
opacity: this.state.circleOpacity
}]} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
background: {
position: 'absolute',
height: '100%',
width: '100%',
opacity: 0.9
},
gradient: {
height: '100%',
width: '100%',
position: 'absolute',
},
titleStyle: {
fontWeight: 'bold',
fontSize: 35,
color: 'white',
marginTop: 80,
letterSpacing: 2,
alignSelf: 'center'
},
inputContainer: {
flex: 1,
justifyContent: 'flex-end',
paddingHorizontal: 50
},
inputStyle: {
backgroundColor: 'transparent',
color: 'white'
},
loginButtonStyle: {
borderRadius: 20,
borderWidth: 1.5,
alignItems: 'center',
height: 40,
width: '100%'
},
loginTextStyle: {
color: 'white',
padding: 10
},
bottomTextStyle: {
color: 'rgba(255,255,255,0.8)',
marginBottom: 20,
marginTop: 80,
alignSelf: 'center',
fontSize: 12
},
loaderStyle: {
position: 'absolute',
width: 40,
height: 39
},
authCircleStyle: {
height: 40,
width: 40,
backgroundColor: 'white',
position: 'absolute',
borderRadius: 20
}
});
const mapDispatchToProps = dispatch => ({
onSetUser: (user) => dispatch(setUser(user)),
})
export default connect(null, mapDispatchToProps)(LoginScreen)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment