From fbabb4d7af52c85dae11af6bdea49070bd17a9d6 Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Sun, 29 Mar 2020 11:47:27 +0200 Subject: [PATCH] First draft of connection --- components/Sidebar.js | 5 ++ navigation/DrawerNavigator.js | 29 ++++++ package.json | 7 +- screens/Amicale/LoginScreen.js | 109 +++++++++++++++++++++++ utils/ConnectionManager.js | 65 ++++++++++++++ utils/__test__/ConnectionManager.test.js | 15 ++++ 6 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 screens/Amicale/LoginScreen.js create mode 100644 utils/ConnectionManager.js create mode 100644 utils/__test__/ConnectionManager.test.js diff --git a/components/Sidebar.js b/components/Sidebar.js index 3fca4cd..383ce66 100644 --- a/components/Sidebar.js +++ b/components/Sidebar.js @@ -46,6 +46,11 @@ export default class SideBar extends React.PureComponent { route: "Main", icon: "home", }, + { + name: 'LOGIN', + route: "LoginScreen", + icon: "login", + }, { name: i18n.t('sidenav.divider2'), route: "Divider2" diff --git a/navigation/DrawerNavigator.js b/navigation/DrawerNavigator.js index 0073467..5c3570a 100644 --- a/navigation/DrawerNavigator.js +++ b/navigation/DrawerNavigator.js @@ -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 ( + + { + const openDrawer = getDrawerButton.bind(this, navigation); + return { + title: 'LOGIN', + headerLeft: openDrawer + }; + }} + /> + + ); +} + const Drawer = createDrawerNavigator(); function getDrawerContent(props) { @@ -231,6 +256,10 @@ export default function DrawerNavigator() { name="TetrisScreen" component={TetrisStackComponent} /> + ); } diff --git a/package.json b/package.json index d3e83da..23bc6b6 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/screens/Amicale/LoginScreen.js b/screens/Amicale/LoginScreen.js new file mode 100644 index 0000000..00853ba --- /dev/null +++ b/screens/Amicale/LoginScreen.js @@ -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 { + + 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 ( + + + + COUCOU + entrez vos identifiants + + + + + + Pas de compte, dommage ! + + + + + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1 + }, + inner: { + padding: 24, + flex: 1, + }, + header: { + fontSize: 36, + marginBottom: 48 + }, + textInput: {}, + btnContainer: { + marginTop: 12 + } +}); diff --git a/utils/ConnectionManager.js b/utils/ConnectionManager.js new file mode 100644 index 0000000..64fab55 --- /dev/null +++ b/utils/ConnectionManager.js @@ -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; + } + +} diff --git a/utils/__test__/ConnectionManager.test.js b/utils/__test__/ConnectionManager.test.js new file mode 100644 index 0000000..40bb62c --- /dev/null +++ b/utils/__test__/ConnectionManager.test.js @@ -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'); +});