diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/common/LoginInput.tsx | 21 | ||||
-rw-r--r-- | src/screens/Login.tsx | 40 |
2 files changed, 40 insertions, 21 deletions
diff --git a/src/components/common/LoginInput.tsx b/src/components/common/LoginInput.tsx index e4d6b957..2a1768a7 100644 --- a/src/components/common/LoginInput.tsx +++ b/src/components/common/LoginInput.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import {Text, TextInput, StyleSheet} from 'react-native'; +import {TextInput, StyleSheet} from 'react-native'; +import * as Animatable from 'react-native-animatable'; const LoginInput = (props: LoginInputProps) => { return ( @@ -44,6 +45,7 @@ const LoginInput = (props: LoginInputProps) => { ? 'default' : undefined } + autoCapitalize="none" onChangeText={(input) => props.onChangeText(input)} defaultValue={props.type} onSubmitEditing={props.onSubmitEditing} @@ -55,8 +57,13 @@ const LoginInput = (props: LoginInputProps) => { } ref={props.input_ref} /> - {!props.isValid && ( - <Text style={styles.invalidCredentials}>{props.validationWarning}</Text> + {props.attempt_submit && !props.isValid && ( + <Animatable.Text + animation="shake" + duration={500} + style={styles.invalidCredentials}> + {props.validationWarning} + </Animatable.Text> )} </> ); @@ -64,7 +71,7 @@ const LoginInput = (props: LoginInputProps) => { const styles = StyleSheet.create({ credentials: { - top: 190, + top: 175, width: 248, height: 40, fontSize: 20, @@ -76,8 +83,10 @@ const styles = StyleSheet.create({ marginVertical: 15, }, invalidCredentials: { - top: 180, + top: 165, color: '#F4DDFF', + paddingHorizontal: 30, + textAlign: 'center', }, }); @@ -87,8 +96,8 @@ interface LoginInputProps { isPassword?: boolean; onChangeText: (input: string) => void; onSubmitEditing?: () => void; + attempt_submit?: boolean; input_ref?: object; - focusPasswordInput?: boolean; isValid?: boolean; validationWarning?: string; } diff --git a/src/screens/Login.tsx b/src/screens/Login.tsx index 417d9bd7..2a4ec060 100644 --- a/src/screens/Login.tsx +++ b/src/screens/Login.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useRef} from 'react'; import {RouteProp} from '@react-navigation/native'; import {StackNavigationProp} from '@react-navigation/stack'; import { @@ -27,22 +27,23 @@ interface LoginProps { } const Login = ({navigation}: LoginProps) => { - const input_ref = React.createRef(); + const input_ref = useRef(); const [data, setData] = React.useState({ username: '', password: '', - isValidUser: true, - isValidPassword: true, - focusPasswordInput: false, + isValidUser: false, + isValidPassword: false, + attemptSubmit: false, }); /* - Updates the state of username. Also verifies the input of the Username field. + Updates the state of username. Also verifies the input of the Username field by ensuring proper length and characters. */ const handleUsernameUpdate = (val: string) => { - let validLength: boolean = val.trim().length >= 6; + let validLength: boolean = val.length >= 6; + let validChars: boolean = !/[^A-Za-z0-9_.]/g.test(val); - if (validLength) { + if (validLength && validChars) { setData({ ...data, username: val, @@ -58,10 +59,10 @@ const Login = ({navigation}: LoginProps) => { }; /* - Updates the state of password. Also verifies the input of the Password field. + Updates the state of password. Also verifies the input of the Password field by ensuring proper length. */ const handlePasswordUpdate = (val: string) => { - let validLength: boolean = val.trim().length >= 8; + let validLength: boolean = val.length >= 8; if (validLength) { setData({ @@ -82,6 +83,12 @@ const Login = ({navigation}: LoginProps) => { Handler for the Let's Start button or the Go button on the keyboard. */ const handleLogin = () => { + if (!data.attemptSubmit) { + setData({ + ...data, + attemptSubmit: true, + }); + } if (data.isValidUser && data.isValidPassword) { Alert.alert( `My favorite Girl Scout Cookies are taggalongs! What are yours ${data.username}?`, @@ -121,20 +128,23 @@ const Login = ({navigation}: LoginProps) => { <LoginInput type={data.username} isUsername={true} - onChangeText={(user) => handleUsernameUpdate(user)} + onChangeText={(user) => handleUsernameUpdate(user.trim())} onSubmitEditing={() => handleUsernameSubmit()} isValid={data.isValidUser} - validationWarning={'Username must be at least 6 characters long.'} + validationWarning={ + 'Username must be at least 6 characters and can only contain letters, numbers, periods, and underscores.' + } + attempt_submit={data.attemptSubmit} /> <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} + attempt_submit={data.attemptSubmit} /> <TouchableOpacity accessibilityLabel="Forgot password button" @@ -186,7 +196,7 @@ const styles = StyleSheet.create({ height: 149, }, forgotPassword: { - top: 190, + top: 175, left: -60, }, forgotPasswordText: { @@ -195,7 +205,7 @@ const styles = StyleSheet.create({ textDecorationLine: 'underline', }, start: { - top: 195, + top: 180, width: 144, height: 36, justifyContent: 'center', |