forked from vergnet/application-amicale
Merge branch 'login' into dev
This commit is contained in:
commit
4b370d5810
6 changed files with 228 additions and 2 deletions
|
@ -46,6 +46,11 @@ export default class SideBar extends React.PureComponent<Props, State> {
|
|||
route: "Main",
|
||||
icon: "home",
|
||||
},
|
||||
{
|
||||
name: 'LOGIN',
|
||||
route: "LoginScreen",
|
||||
icon: "login",
|
||||
},
|
||||
{
|
||||
name: i18n.t('sidenav.divider2'),
|
||||
route: "Divider2"
|
||||
|
|
|
@ -15,6 +15,7 @@ import Sidebar from "../components/Sidebar";
|
|||
import {createStackNavigator, TransitionPresets} from "@react-navigation/stack";
|
||||
import HeaderButton from "../components/HeaderButton";
|
||||
import i18n from "i18n-js";
|
||||
import LoginScreen from "../screens/Amicale/LoginScreen";
|
||||
|
||||
const defaultScreenOptions = {
|
||||
gestureEnabled: true,
|
||||
|
@ -186,6 +187,30 @@ function TetrisStackComponent() {
|
|||
);
|
||||
}
|
||||
|
||||
const LoginStack = createStackNavigator();
|
||||
|
||||
function LoginStackComponent() {
|
||||
return (
|
||||
<LoginStack.Navigator
|
||||
initialRouteName="LoginScreen"
|
||||
headerMode="float"
|
||||
screenOptions={defaultScreenOptions}
|
||||
>
|
||||
<LoginStack.Screen
|
||||
name="LoginScreen"
|
||||
component={LoginScreen}
|
||||
options={({navigation}) => {
|
||||
const openDrawer = getDrawerButton.bind(this, navigation);
|
||||
return {
|
||||
title: 'LOGIN',
|
||||
headerLeft: openDrawer
|
||||
};
|
||||
}}
|
||||
/>
|
||||
</LoginStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
const Drawer = createDrawerNavigator();
|
||||
|
||||
function getDrawerContent(props) {
|
||||
|
@ -231,6 +256,10 @@ export default function DrawerNavigator() {
|
|||
name="TetrisScreen"
|
||||
component={TetrisStackComponent}
|
||||
/>
|
||||
<Drawer.Screen
|
||||
name="LoginScreen"
|
||||
component={LoginStackComponent}
|
||||
/>
|
||||
</Drawer.Navigator>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
},
|
||||
"jest": {
|
||||
"preset": "react-native",
|
||||
"setupFilesAfterEnv": ["jest-extended"]
|
||||
"setupFilesAfterEnv": [
|
||||
"jest-extended"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "~10.0.0",
|
||||
|
@ -42,7 +44,8 @@
|
|||
"react-native-screens": "2.0.0-alpha.12",
|
||||
"react-native-webview": "7.4.3",
|
||||
"react-native-appearance": "~0.3.1",
|
||||
"expo-linear-gradient": "~8.0.0"
|
||||
"expo-linear-gradient": "~8.0.0",
|
||||
"expo-secure-store": "~8.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-expo": "^8.0.0",
|
||||
|
|
109
screens/Amicale/LoginScreen.js
Normal file
109
screens/Amicale/LoginScreen.js
Normal file
|
@ -0,0 +1,109 @@
|
|||
// @flow
|
||||
|
||||
import * as React from 'react';
|
||||
import {Keyboard, KeyboardAvoidingView, StyleSheet, TouchableWithoutFeedback, View} from "react-native";
|
||||
import {Button, Text, TextInput, Title} from 'react-native-paper';
|
||||
import ConnectionManager from "../../utils/ConnectionManager";
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
}
|
||||
|
||||
type State = {
|
||||
email: string,
|
||||
password: string,
|
||||
}
|
||||
|
||||
|
||||
export default class LoginScreen extends React.Component<Props, State> {
|
||||
|
||||
state = {
|
||||
email: '',
|
||||
password: '',
|
||||
};
|
||||
|
||||
onEmailChange: Function;
|
||||
onPasswordChange: Function;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.onEmailChange = this.onInputChange.bind(this, true);
|
||||
this.onPasswordChange = this.onInputChange.bind(this, false);
|
||||
}
|
||||
|
||||
onInputChange(isEmail: boolean, value: string) {
|
||||
if (isEmail)
|
||||
this.setState({email: value});
|
||||
else
|
||||
this.setState({password: value});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
console.log('pressed');
|
||||
ConnectionManager.getInstance().connect(this.state.email, this.state.password)
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
behavior={"padding"}
|
||||
contentContainerStyle={styles.container}
|
||||
style={styles.container}
|
||||
>
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
||||
<View style={styles.inner}>
|
||||
<Title>COUCOU</Title>
|
||||
<Text>entrez vos identifiants</Text>
|
||||
<TextInput
|
||||
label='Email'
|
||||
mode='outlined'
|
||||
value={this.state.email}
|
||||
onChangeText={this.onEmailChange}
|
||||
/>
|
||||
<TextInput
|
||||
label='Password'
|
||||
mode='outlined'
|
||||
value={this.state.password}
|
||||
onChangeText={this.onPasswordChange}
|
||||
/>
|
||||
<View style={styles.btnContainer}>
|
||||
<Button icon="send" onPress={() => this.onSubmit()}>
|
||||
LOGIN
|
||||
</Button>
|
||||
</View>
|
||||
<Text>Pas de compte, dommage !</Text>
|
||||
<View style={styles.btnContainer}>
|
||||
<Button icon="send" onPress={() => console.log('Pressed')}>
|
||||
Créer un compte
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1
|
||||
},
|
||||
inner: {
|
||||
padding: 24,
|
||||
flex: 1,
|
||||
},
|
||||
header: {
|
||||
fontSize: 36,
|
||||
marginBottom: 48
|
||||
},
|
||||
textInput: {},
|
||||
btnContainer: {
|
||||
marginTop: 12
|
||||
}
|
||||
});
|
65
utils/ConnectionManager.js
Normal file
65
utils/ConnectionManager.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
// @flow
|
||||
|
||||
export const ERROR_TYPE = {
|
||||
BAD_CREDENTIALS: 0,
|
||||
CONNECTION_ERROR: 1
|
||||
};
|
||||
|
||||
const AUTH_URL = "https://www.amicale-insat.fr/api/password";
|
||||
|
||||
export default class ConnectionManager {
|
||||
static instance: ConnectionManager | null = null;
|
||||
|
||||
#email: string;
|
||||
#token: string;
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this class instance or create one if none is found
|
||||
* @returns {ConnectionManager}
|
||||
*/
|
||||
static getInstance(): ConnectionManager {
|
||||
return ConnectionManager.instance === null ?
|
||||
ConnectionManager.instance = new ConnectionManager() :
|
||||
ConnectionManager.instance;
|
||||
}
|
||||
|
||||
async connect(email: string, password: string) {
|
||||
let data = {
|
||||
email: email,
|
||||
password: password,
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(AUTH_URL, {
|
||||
method: 'POST',
|
||||
headers: new Headers({
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: JSON.stringify(data)
|
||||
}).then(async (response) => response.json())
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
if (this.isResponseValid(data))
|
||||
resolve({success: data.success, token: data.token});
|
||||
else
|
||||
reject(ERROR_TYPE.BAD_CREDENTIALS);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
reject(ERROR_TYPE.CONNECTION_ERROR);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
isResponseValid(response: Object) {
|
||||
return response !== undefined
|
||||
&& response.success !== undefined
|
||||
&& response.success
|
||||
&& response.token !== undefined;
|
||||
}
|
||||
|
||||
}
|
15
utils/__test__/ConnectionManager.test.js
Normal file
15
utils/__test__/ConnectionManager.test.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
import ConnectionManager, {ERROR_TYPE} from "../ConnectionManager";
|
||||
|
||||
const fetch = require('isomorphic-fetch'); // fetch is not implemented in nodeJS but in react-native
|
||||
const c = ConnectionManager.getInstance();
|
||||
|
||||
test("connect bad credentials", () => {
|
||||
return expect(c.connect('truc', 'chose'))
|
||||
.rejects.toBe(ERROR_TYPE.BAD_CREDENTIALS);
|
||||
});
|
||||
|
||||
test("connect good credentials", () => {
|
||||
return expect(c.connect('vergnet@etud.insa-toulouse.fr', 'Coucoù512'))
|
||||
.resolves.toBe('test');
|
||||
});
|
Loading…
Reference in a new issue