aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ios/Podfile.lock10
-rw-r--r--package.json1
-rw-r--r--src/assets/sign_in_logo.pngbin0 -> 28865 bytes
-rw-r--r--src/components/common/LoginInput.tsx96
-rw-r--r--src/routes/Routes.tsx6
-rw-r--r--src/screens/Login.tsx215
-rw-r--r--src/screens/Registration.tsx16
-rw-r--r--yarn.lock35
8 files changed, 350 insertions, 29 deletions
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 693e204c..fcff1410 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -1,5 +1,7 @@
PODS:
- boost-for-react-native (1.63.0)
+ - BVLinearGradient (2.5.6):
+ - React
- CocoaAsyncSocket (7.6.4)
- CocoaLibEvent (1.0.0)
- DoubleConversion (1.1.6)
@@ -233,7 +235,7 @@ PODS:
- React-cxxreact (= 0.62.2)
- React-jsi (= 0.62.2)
- React-jsinspector (0.62.2)
- - react-native-safe-area-context (3.0.6):
+ - react-native-safe-area-context (3.0.7):
- React
- React-RCTActionSheet (0.62.2):
- React-Core/RCTActionSheetHeaders (= 0.62.2)
@@ -307,6 +309,7 @@ PODS:
- Yoga (~> 1.14)
DEPENDENCIES:
+ - BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
@@ -376,6 +379,8 @@ SPEC REPOS:
- YogaKit
EXTERNAL SOURCES:
+ BVLinearGradient:
+ :path: "../node_modules/react-native-linear-gradient"
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
FBLazyVector:
@@ -439,6 +444,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
+ BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
@@ -463,7 +469,7 @@ SPEC CHECKSUMS:
React-jsi: b6dc94a6a12ff98e8877287a0b7620d365201161
React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da
React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493
- react-native-safe-area-context: e22a8ca00f758273d2408953965cb8db67da7925
+ react-native-safe-area-context: ef6f16c66b0797ecae1bf86c103dfb3dc16fc33d
React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c
React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0
React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71
diff --git a/package.json b/package.json
index d3ad6c4d..0c8f7bf1 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"react": "16.11.0",
"react-native": "0.62.2",
"react-native-gesture-handler": "^1.6.1",
+ "react-native-linear-gradient": "^2.5.6",
"react-native-reanimated": "^1.9.0",
"react-native-safe-area-context": "^3.0.6",
"react-native-screens": "^2.9.0"
diff --git a/src/assets/sign_in_logo.png b/src/assets/sign_in_logo.png
new file mode 100644
index 00000000..27e43268
--- /dev/null
+++ b/src/assets/sign_in_logo.png
Binary files differ
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;
diff --git a/yarn.lock b/yarn.lock
index 15aedb4c..e8d28bcf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1127,9 +1127,9 @@
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react-native@^0.62.0":
- version "0.62.13"
- resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.62.13.tgz#c688c5ae03e426f927f7e1fa1a59cd067f35d1c2"
- integrity sha512-hs4/tSABhcJx+J8pZhVoXHrOQD89WFmbs8QiDLNSA9zNrD46pityAuBWuwk1aMjPk9I3vC5ewkJroVRHgRIfdg==
+ version "0.62.14"
+ resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.62.14.tgz#13ce7dab136bb124b6f394fe7510442557b16d29"
+ integrity sha512-ItBgiEQks2Mid6GsiLBx75grNH0glaKemTK9V7G+vSnvP+Zk3x1Wr+aTy4dJxRPPMg14DAJyYePLZwj2cigXbw==
dependencies:
"@types/react" "*"
@@ -1141,9 +1141,9 @@
"@types/react" "*"
"@types/react@*":
- version "16.9.38"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.38.tgz#868405dace93a4095d3e054f4c4a1de7a1ac0680"
- integrity sha512-pHAeZbjjNRa/hxyNuLrvbxhhnKyKNiLC6I5fRF2Zr/t/S6zS41MiyzH4+c+1I9vVfvuRt1VS2Lodjr4ZWnxrdA==
+ version "16.9.41"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.41.tgz#925137ee4d2ff406a0ecf29e8e9237390844002e"
+ integrity sha512-6cFei7F7L4wwuM+IND/Q2cV1koQUvJ8iSV+Gwn0c3kvABZ691g7sp3hfEQHOUBJtccl1gPi+EyNjMIl9nGA0ug==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"
@@ -3691,9 +3691,9 @@ jest-mock@^24.9.0:
"@jest/types" "^24.9.0"
jest-pnp-resolver@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a"
- integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
+ integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
jest-regex-util@^24.3.0, jest-regex-util@^24.9.0:
version "24.9.0"
@@ -5107,6 +5107,11 @@ react-native-iphone-x-helper@^1.2.1:
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.2.1.tgz#645e2ffbbb49e80844bb4cbbe34a126fda1e6772"
integrity sha512-/VbpIEp8tSNNHIvstuA3Swx610whci1Zpc9mqNkqn14DkMbw+ORviln2u0XyHG1kPvvwTNGZY6QpeFwxYaSdbQ==
+react-native-linear-gradient@^2.5.6:
+ version "2.5.6"
+ resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.5.6.tgz#96215cbc5ec7a01247a20890888aa75b834d44a0"
+ integrity sha512-HDwEaXcQIuXXCV70O+bK1rizFong3wj+5Q/jSyifKFLg0VWF95xh8XQgfzXwtq0NggL9vNjPKXa016KuFu+VFg==
+
react-native-reanimated@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-1.9.0.tgz#38676c99dd585504fdc7331efb45e5f48ec7339a"
@@ -5115,9 +5120,9 @@ react-native-reanimated@^1.9.0:
fbjs "^1.0.0"
react-native-safe-area-context@^3.0.6:
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.0.6.tgz#ee180f53f9f40f8302923b9c09d821cf8ada01eb"
- integrity sha512-/McWHgRG3CjXo/1ctlxH3mjW2psjf/QYAt9kWUTEtHu4b6z1y4hfUIGuYEJ02asaS1ixPsYrkqVqwzTv4olUMQ==
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.0.7.tgz#0f53de7a30d626d82936000f3f6db374ecc4b800"
+ integrity sha512-dqhRTlIFe5+P1yxitj0C9XVUxLqOmjomeqzUSSY8sNOWVjtIhEY/fl4ZKYpAVnktd8dt3zl13XmJTmRmy3d0uA==
react-native-screens@^2.9.0:
version "2.9.0"
@@ -6349,9 +6354,9 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
iconv-lite "0.4.24"
whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
- integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.1.0.tgz#49d630cdfa308dba7f2819d49d09364f540dbcc6"
+ integrity sha512-pgmbsVWKpH9GxLXZmtdowDIqtb/rvPyjjQv3z9wLcmgWKFHilKnZD3ldgrOlwJoPGOUluQsRPWd52yVkPfmI1A==
whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0:
version "2.3.0"