diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/App.tsx | 23 | ||||
-rw-r--r-- | src/__tests__/App-test.tsx | 16 | ||||
-rw-r--r-- | src/assets/images/logo.png | bin | 0 -> 7852 bytes | |||
-rw-r--r-- | src/assets/images/logo@2x.png | bin | 0 -> 18292 bytes | |||
-rw-r--r-- | src/assets/images/logo@3x.png | bin | 0 -> 30041 bytes | |||
-rw-r--r-- | src/index.ts | 1 | ||||
-rw-r--r-- | src/routes/Routes.tsx | 24 | ||||
-rw-r--r-- | src/routes/index.ts | 2 | ||||
-rw-r--r-- | src/screens/Login.tsx | 234 | ||||
-rw-r--r-- | src/screens/Registration.tsx | 14 | ||||
-rw-r--r-- | src/screens/index.ts | 2 |
11 files changed, 316 insertions, 0 deletions
diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 00000000..6c247f7c --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,23 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + * + * Generated with the TypeScript template + * https://github.com/react-native-community/react-native-template-typescript + * + * @format + */ + +import React from 'react'; +import Routes from './routes'; +import {NavigationContainer} from '@react-navigation/native'; + +const App = () => { + return ( + <NavigationContainer> + <Routes /> + </NavigationContainer> + ); +}; + +export default App; diff --git a/src/__tests__/App-test.tsx b/src/__tests__/App-test.tsx new file mode 100644 index 00000000..e362fb52 --- /dev/null +++ b/src/__tests__/App-test.tsx @@ -0,0 +1,16 @@ +/** + * @format + */ + +import 'react-native'; +import React from 'react'; +import App from '../App'; + +// Note: test renderer must be required after react-native. +import renderer from 'react-test-renderer'; + +jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper'); + +it('renders correctly', () => { + renderer.create(<App />); +}); diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png Binary files differnew file mode 100644 index 00000000..08b21ae9 --- /dev/null +++ b/src/assets/images/logo.png diff --git a/src/assets/images/logo@2x.png b/src/assets/images/logo@2x.png Binary files differnew file mode 100644 index 00000000..df6be90e --- /dev/null +++ b/src/assets/images/logo@2x.png diff --git a/src/assets/images/logo@3x.png b/src/assets/images/logo@3x.png Binary files differnew file mode 100644 index 00000000..7f254e8c --- /dev/null +++ b/src/assets/images/logo@3x.png diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..ab7fd11d --- /dev/null +++ b/src/index.ts @@ -0,0 +1 @@ +export {default} from './App'; diff --git a/src/routes/Routes.tsx b/src/routes/Routes.tsx new file mode 100644 index 00000000..0b08cbb1 --- /dev/null +++ b/src/routes/Routes.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import {createStackNavigator} from '@react-navigation/stack'; + +import {Login, Registration} from '../screens'; + +export type RootStackParams = { + Login: undefined; + Registration: undefined; +}; + +const RootStack = createStackNavigator<RootStackParamList>(); + +interface RoutesProps {} + +const Routes: React.FC<RoutesProps> = ({}) => { + return ( + <RootStack.Navigator initialRouteName="Login"> + <RootStack.Screen name="Login" component={Login} options={ { headerShown: false} }/> + <RootStack.Screen name="Registration" component={Registration} /> + </RootStack.Navigator> + ); +}; + +export default Routes; diff --git a/src/routes/index.ts b/src/routes/index.ts new file mode 100644 index 00000000..cfa05fcb --- /dev/null +++ b/src/routes/index.ts @@ -0,0 +1,2 @@ +export {default} from './Routes'; +export * from './Routes'; diff --git a/src/screens/Login.tsx b/src/screens/Login.tsx new file mode 100644 index 00000000..672fd035 --- /dev/null +++ b/src/screens/Login.tsx @@ -0,0 +1,234 @@ +import React, { useRef } from 'react'; +import {RouteProp} from '@react-navigation/native'; +import {StackNavigationProp} from '@react-navigation/stack'; +import { + View, + Text, + Alert, + StatusBar, + Image, + TextInput, + TouchableOpacity, + StyleSheet +} from 'react-native'; + +import {RootStackParams} from '../routes'; +import LinearGradient from 'react-native-linear-gradient'; + +type LoginScreenRouteProp = RouteProp<RootStackParams, 'Login'>; +type LoginScreenNavigationProp = StackNavigationProp<RootStackParams, 'Login'>; + +interface LoginProps { + route: LoginScreenRouteProp; + navigation: LoginScreenNavigationProp; +} +const Login = ({navigation}: LoginProps) => { + const passwordInput = useRef(); + const [data, setData] = React.useState({ + username: '', + password: '', + isValidUser: true, + isValidPassword: true, + }) + + /* + Updates the state of username. Also verifies the input of the Username field. + */ + const handleUsernameUpdate = (val:string) => { + var 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) => { + var 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}?`) + navigation.navigate('Registration') + } + } + + return ( + <> + <StatusBar + barStyle='light-content' + /> + <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} + /> + <TextInput + accessibilityLabel="Username text entry box" + accessibilityHint="Enter your tagg username here" + style={styles.credentials} + placeholder="Username" + placeholderTextColor='#FFFFFF' + autoCompleteType='username' + textContentType='username' + returnKeyType='next' + keyboardType='ascii-capable' + onChangeText={user => handleUsernameUpdate(user)} + defaultValue={data.username} + onSubmitEditing={() => {passwordInput.current.focus()}} + blurOnSubmit={false} + /> + { data.isValidUser ? null : + <Text style={styles.invalidCredentials}>Username must be at least 6 characters long.</Text> + } + <TextInput + accessibilityLabel="Password text entry box" + accessibilityHint="Enter your tagg password here" + style={styles.credentials} + placeholder="Password" + placeholderTextColor='#FFFFFF' + autoCompleteType='password' + textContentType='password' + returnKeyType='go' + onChangeText={pass => handlePasswordUpdate(pass)} + defaultValue={data.password} + onSubmitEditing={() => handleLogin()} + ref={passwordInput} + secureTextEntry={true} + /> + { data.isValidPassword ? null : + <Text style={styles.invalidCredentials}>Password must be at least 8 characters long.</Text> + } + <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={() => Alert.alert("I get the tagg flip it and tumble it.")}>Get started!</Text> + </Text> + </LinearGradient> + </View> + </> + // <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> + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: 'transparent', + }, + linearGradient: { + flex: 1, + alignItems: 'center', + }, + logo: { + top: 165, + width: 215, + height: 149, + }, + credentials: { + top: 190, + width: 248, + height: 40, + fontSize: 20, + color: '#FFFFFF', + borderColor: '#FFFDFD', + borderWidth: 2, + borderRadius: 20, + paddingLeft: 13, + marginVertical: 15, + }, + 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;
\ No newline at end of file diff --git a/src/screens/Registration.tsx b/src/screens/Registration.tsx new file mode 100644 index 00000000..44658591 --- /dev/null +++ b/src/screens/Registration.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import {View, Text} 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> + ); +}; + +export default Registration; diff --git a/src/screens/index.ts b/src/screens/index.ts new file mode 100644 index 00000000..60b26b4c --- /dev/null +++ b/src/screens/index.ts @@ -0,0 +1,2 @@ +export {default as Login} from './Login'; +export {default as Registration} from './Registration'; |