From d2a1005d200abb91f72938d152a1493cb845d970 Mon Sep 17 00:00:00 2001
From: Justin Shillingford <jgs272@cornell.edu>
Date: Mon, 6 Jul 2020 16:05:03 -0400
Subject: [TMA-62] Basic Login Input Validation (#11)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Updated createRef() to useRef()

* Animated invalid input hint

Also removed useless focusPasswordInput prop

* Users can no longer submit without typing

* Added basic input validation for Username

* Fixed username input validation 😅

* Removed autocapitalize from keyboard

* Trim username input as early as possible

Also removed trim from password

* Adjusted styling to accomodate longer hint message

* Lint cleaning

* Updated documentation of update methods

* Forgot to include periods in the error message 😅

* Modified styling to accomodate longer hint
---
 src/screens/Login.tsx | 40 +++++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 15 deletions(-)

(limited to 'src/screens/Login.tsx')

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',
-- 
cgit v1.2.3-70-g09d2

