diff options
author | Husam Salhab <47015061+hsalhab@users.noreply.github.com> | 2020-06-30 16:52:17 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-30 16:52:17 -0400 |
commit | d4c59d4d31aedbad19353e639953329df08e6e5a (patch) | |
tree | 446799875830477a5ad6dbff78ba7126a8eb7e17 /src | |
parent | 5c243b512343549b54dce69bf11ff4851056f26e (diff) | |
parent | b5da6e55ccd4109eb1aa7705540ffb0b4a30a805 (diff) |
Merge pull request #9 from JustinShillingford/tma42-Login-Page-UI
[TMA-61] Login Page UI with no real functionality
Diffstat (limited to 'src')
-rw-r--r-- | src/assets/sign_in_logo.png | bin | 0 -> 28865 bytes | |||
-rw-r--r-- | src/components/common/LoginInput.tsx | 96 | ||||
-rw-r--r-- | src/routes/Routes.tsx | 6 | ||||
-rw-r--r-- | src/screens/Login.tsx | 215 | ||||
-rw-r--r-- | src/screens/Registration.tsx | 16 |
5 files changed, 321 insertions, 12 deletions
diff --git a/src/assets/sign_in_logo.png b/src/assets/sign_in_logo.png Binary files differnew file mode 100644 index 00000000..27e43268 --- /dev/null +++ b/src/assets/sign_in_logo.png diff --git a/src/components/common/LoginInput.tsx b/src/components/common/LoginInput.tsx new file mode 100644 index 00000000..e4d6b957 --- /dev/null +++ b/src/components/common/LoginInput.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import {Text, TextInput, StyleSheet} from 'react-native'; + +const LoginInput = (props: LoginInputProps) => { + return ( + <> + <TextInput + accessibilityLabel={ + props.isUsername + ? 'Username text entry box' + : props.isPassword + ? 'Password text entry box' + : undefined + } + accessibilityHint={ + props.isUsername + ? 'Enter your tagg username here' + : props.isPassword + ? 'Enter your tagg password here' + : undefined + } + style={styles.credentials} + placeholder={ + props.isUsername + ? 'Username' + : props.isPassword + ? 'Password' + : undefined + } + placeholderTextColor="#FFFFFF" + autoCompleteType={ + props.isUsername ? 'username' : props.isPassword ? 'password' : 'off' + } + textContentType={ + props.isUsername ? 'username' : props.isPassword ? 'password' : 'none' + } + returnKeyType={ + props.isUsername ? 'next' : props.isPassword ? 'go' : 'default' + } + keyboardType={ + props.isUsername + ? 'ascii-capable' + : props.isPassword + ? 'default' + : undefined + } + onChangeText={(input) => props.onChangeText(input)} + defaultValue={props.type} + onSubmitEditing={props.onSubmitEditing} + blurOnSubmit={ + props.isUsername ? false : props.isPassword ? undefined : undefined + } + secureTextEntry={ + props.isUsername ? false : props.isPassword ? true : false + } + ref={props.input_ref} + /> + {!props.isValid && ( + <Text style={styles.invalidCredentials}>{props.validationWarning}</Text> + )} + </> + ); +}; + +const styles = StyleSheet.create({ + credentials: { + top: 190, + width: 248, + height: 40, + fontSize: 20, + color: '#FFFFFF', + borderColor: '#FFFDFD', + borderWidth: 2, + borderRadius: 20, + paddingLeft: 13, + marginVertical: 15, + }, + invalidCredentials: { + top: 180, + color: '#F4DDFF', + }, +}); + +interface LoginInputProps { + type: string; + isUsername?: boolean; + isPassword?: boolean; + onChangeText: (input: string) => void; + onSubmitEditing?: () => void; + input_ref?: object; + focusPasswordInput?: boolean; + isValid?: boolean; + validationWarning?: string; +} + +export default LoginInput; diff --git a/src/routes/Routes.tsx b/src/routes/Routes.tsx index 9c2efada..d96c1d80 100644 --- a/src/routes/Routes.tsx +++ b/src/routes/Routes.tsx @@ -15,7 +15,11 @@ interface RoutesProps {} const Routes: React.FC<RoutesProps> = ({}) => { return ( <RootStack.Navigator initialRouteName="Login"> - <RootStack.Screen name="Login" component={Login} /> + <RootStack.Screen + name="Login" + component={Login} + options={{headerShown: false}} + /> <RootStack.Screen name="Registration" component={Registration} /> </RootStack.Navigator> ); diff --git a/src/screens/Login.tsx b/src/screens/Login.tsx index 0305b907..417d9bd7 100644 --- a/src/screens/Login.tsx +++ b/src/screens/Login.tsx @@ -1,9 +1,22 @@ import React from 'react'; import {RouteProp} from '@react-navigation/native'; import {StackNavigationProp} from '@react-navigation/stack'; -import {View, Text, Button} from 'react-native'; +import { + View, + Text, + Alert, + StatusBar, + Image, + TouchableOpacity, + StyleSheet, + Keyboard, + TouchableWithoutFeedback, +} from 'react-native'; import {RootStackParams} from '../routes'; +import LinearGradient from 'react-native-linear-gradient'; + +import LoginInput from '../components/common/LoginInput'; type LoginScreenRouteProp = RouteProp<RootStackParams, 'Login'>; type LoginScreenNavigationProp = StackNavigationProp<RootStackParams, 'Login'>; @@ -12,16 +25,202 @@ interface LoginProps { route: LoginScreenRouteProp; navigation: LoginScreenNavigationProp; } + const Login = ({navigation}: LoginProps) => { + const input_ref = React.createRef(); + const [data, setData] = React.useState({ + username: '', + password: '', + isValidUser: true, + isValidPassword: true, + focusPasswordInput: false, + }); + + /* + Updates the state of username. Also verifies the input of the Username field. + */ + const handleUsernameUpdate = (val: string) => { + let validLength: boolean = val.trim().length >= 6; + + if (validLength) { + setData({ + ...data, + username: val, + isValidUser: true, + }); + } else { + setData({ + ...data, + username: val, + isValidUser: false, + }); + } + }; + + /* + Updates the state of password. Also verifies the input of the Password field. + */ + const handlePasswordUpdate = (val: string) => { + let validLength: boolean = val.trim().length >= 8; + + if (validLength) { + setData({ + ...data, + password: val, + isValidPassword: true, + }); + } else { + setData({ + ...data, + password: val, + isValidPassword: false, + }); + } + }; + + /* + Handler for the Let's Start button or the Go button on the keyboard. + */ + const handleLogin = () => { + if (data.isValidUser && data.isValidPassword) { + Alert.alert( + `My favorite Girl Scout Cookies are taggalongs! What are yours ${data.username}?`, + ); + } + }; + + /* + Handler for the submit button on the Username keyboard + */ + const handleUsernameSubmit = () => { + input_ref.current.focus(); + }; + + const handleRegistration = () => { + navigation.navigate('Registration'); + }; + return ( - <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}> - <Text style={{fontSize: 18}}>Welcome to Tagg! Login page goes here.</Text> - <Button - title="Register" - onPress={() => navigation.navigate('Registration')} - /> - </View> + <> + <StatusBar barStyle="light-content" /> + <TouchableWithoutFeedback + onPress={() => { + Keyboard.dismiss(); + }}> + <View style={styles.container}> + <LinearGradient + colors={['#8F00FF', '#6EE7E7']} + style={styles.linearGradient} + useAngle={true} + angle={154.72} + angleCenter={{x: 0.5, y: 0.5}}> + <Image + source={require('../assets/images/logo.png')} + style={styles.logo} + /> + <LoginInput + type={data.username} + isUsername={true} + onChangeText={(user) => handleUsernameUpdate(user)} + onSubmitEditing={() => handleUsernameSubmit()} + isValid={data.isValidUser} + validationWarning={'Username must be at least 6 characters long.'} + /> + <LoginInput + type={data.password} + isPassword={true} + onChangeText={(user) => handlePasswordUpdate(user)} + focusPasswordInput={data.focusPasswordInput} + onSubmitEditing={() => handleLogin()} + isValid={data.isValidPassword} + validationWarning={'Password must be at least 8 characters long.'} + input_ref={input_ref} + /> + <TouchableOpacity + accessibilityLabel="Forgot password button" + accessibilityHint="Select this if you forgot your tagg password" + style={styles.forgotPassword} + onPress={() => Alert.alert("tagg! You're it!")}> + <Text style={styles.forgotPasswordText}>Forgot password</Text> + </TouchableOpacity> + <TouchableOpacity + accessibilityLabel="Let's start button" + accessibilityHint="Select this after entering your tagg username and password" + style={styles.start} + onPress={() => handleLogin()}> + <Text style={styles.startText}>Let's Start!</Text> + </TouchableOpacity> + <Text + accessible={true} + accessibilityLabel="New to tagg?" + style={styles.newUser}> + New to tagg?{' '} + <Text + accessible={true} + accessibilityLabel="Get started" + accessibilityHint="Select this if you do not have a tagg account" + style={styles.getStarted} + onPress={() => handleRegistration()}> + Get started! + </Text> + </Text> + </LinearGradient> + </View> + </TouchableWithoutFeedback> + </> ); }; +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: 'transparent', + }, + linearGradient: { + flex: 1, + alignItems: 'center', + }, + logo: { + top: 165, + width: 215, + height: 149, + }, + forgotPassword: { + top: 190, + left: -60, + }, + forgotPasswordText: { + fontSize: 15, + color: '#FFFFFF', + textDecorationLine: 'underline', + }, + start: { + top: 195, + width: 144, + height: 36, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#FFFFFF', + borderRadius: 20, + marginTop: 15, + }, + startText: { + fontSize: 15, + color: '#78A0EF', + fontWeight: 'bold', + }, + getStarted: { + color: '#FFFFFF', + textDecorationLine: 'underline', + }, + newUser: { + top: 240, + color: '#F4DDFF', + }, + invalidCredentials: { + top: 180, + color: '#F4DDFF', + }, +}); + export default Login; diff --git a/src/screens/Registration.tsx b/src/screens/Registration.tsx index 44658591..57b0eb18 100644 --- a/src/screens/Registration.tsx +++ b/src/screens/Registration.tsx @@ -1,14 +1,24 @@ import React from 'react'; -import {View, Text} from 'react-native'; +import {View, Text, StyleSheet} from 'react-native'; interface RegistrationProps {} const Registration: React.FC<RegistrationProps> = ({}) => { return ( - <View style={{flex: 1, alignSelf: 'center', justifyContent: 'center'}}> - <Text style={{fontSize: 18}}>Registration sequence begins here!</Text> + <View style={styles.view}> + <Text style={styles.text}>Registration sequence begins here!</Text> </View> ); }; +const styles = StyleSheet.create({ + view: { + flex: 1, + alignSelf: 'center', + justifyContent: 'center', + }, + text: { + fontSize: 18, + }, +}); export default Registration; |