Merge branch '29-integrate-login' into 'main'

Resolve "integrate Login"

Closes #29

See merge request thschleicher/interaktive-systeme!10
This commit is contained in:
jastornig 2023-12-08 14:46:43 +00:00
commit 424407faf3
11 changed files with 330 additions and 17 deletions

View file

@ -1,15 +1,22 @@
import { Tabs } from "expo-router/tabs";
import {StyleSheet, View} from "react-native"
import {StyleSheet, View, Text} from "react-native"
import { FontAwesome } from "@expo/vector-icons";
import {useThemeColor} from "../../hooks/hooks";
import React from "react";
import React, { useEffect } from "react";
import { Redirect } from "expo-router";
import { useAuth } from "../contexts/AuthContext";
export default function Layout() {
// const selectedColor: string = useThemeColor( "tabIconSelected");
// const defaultColor: string = useThemeColor("tabIconDefault");
// const backgroundColor: string = useThemeColor("backgroundColor");
// const tabBarColor: string = useThemeColor("tabBarColor");
const {authState} = useAuth()
useEffect(()=>{
console.log(authState, "in root Layout")
},[authState])
const styles = StyleSheet.create({
sceneContainer: {
@ -27,6 +34,11 @@ export default function Layout() {
tabBarStyle: styles.tabBar,
}
if(!authState?.authenticated){
return (
<Redirect href={"/"} />)
}
return (
<Tabs sceneContainerStyle={styles.sceneContainer} screenOptions={screenOptions}>
<Tabs.Screen name="budget/index" options={

View file

@ -6,10 +6,11 @@ import { FlatList, TextInput} from 'react-native-gesture-handler';
import { useRef, useState, useEffect } from 'react';
import React from 'react';
import { useRouter } from "expo-router"
import { useAuth } from '../../contexts/AuthContext';
export default function Page() {
const router = useRouter()
const {onLogout} = useAuth();
const [plusShow, setPlusShow] = useState(true);
const prevOffset = useRef(0);
const styles = StyleSheet.create({
@ -52,7 +53,7 @@ export default function Page() {
return (
<View style={{flex: 1}}>
<SafeAreaView style={{flex: 1}}>
{plusShow && <Plus onPress={()=>{
router.push("/(tabs)/home/addItem")
}}/>}
@ -61,7 +62,7 @@ export default function Page() {
data={data}
ListHeaderComponent={
<>
<Welcome name="My Dude" image={profile} onPress={()=>console.log("hello")}></Welcome>
<Welcome name="My Dude" image={profile} onPress={onLogout!}></Welcome>
<SearchBar placeholder='Type to Search...'></SearchBar>
</>
}
@ -72,7 +73,7 @@ export default function Page() {
scrollEventThrottle={20}
>
</FlatList>
</View>
</SafeAreaView>
);
}

12
app/_layout.tsx Normal file
View file

@ -0,0 +1,12 @@
import { Slot } from 'expo-router'
import React from 'react'
import { AuthProvider } from './contexts/AuthContext'
export default function _layout() {
console.log("layout called")
return (
<AuthProvider>
<Slot />
</AuthProvider>
)
}

View file

@ -0,0 +1,137 @@
import { createContext, useContext, useEffect, useState } from "react";
import { Platform } from "react-native";
import * as SecureStore from 'expo-secure-store'
interface AuthProps {
authState?: {email: string | null; authenticated: boolean | null; session: string | null};
onRegister?: (email: string, password: string) => Promise<any>;
onLogin?: (email: string, password: string) => Promise<any>
onLogout?: () => void
}
const SESSION_KEY = 'my_session'
const USER_KEY = "email"
const AuthContext = createContext<AuthProps>({})
export const useAuth = ()=>{
return useContext(AuthContext)
}
async function setStorageItemAsync(key: string, value: string | null){
if (Platform.OS === 'web') {
try {
if (value === null) {
localStorage.removeItem(key);
} else {
localStorage.setItem(key, value);
}
} catch (e) {
console.error('Local storage is unavailable:', e);
}
} else {
if (value == null) {
await SecureStore.deleteItemAsync(key);
} else {
await SecureStore.setItemAsync(key, value);
}
}
}
async function getStorageItemAsync(key: string) : Promise<string|null> {
if(Platform.OS === 'web'){
return localStorage.getItem(key)
}else{
return SecureStore.getItemAsync(key)
}
}
export const AuthProvider = ({children}: any) => {
const [authState, setAuthState] = useState<{
email: string | null;
authenticated: boolean | null;
session : string | null;
isLoading: boolean;
}>({
email: null, authenticated: null, session: null, isLoading: false
});
useEffect(() => {
const loadSession = async () => {
setAuthState((prev) => {
return {
...prev,
isLoading: true
}
})
const session = await getStorageItemAsync(SESSION_KEY)
const email = await getStorageItemAsync(USER_KEY)
if(session && email){
setAuthState({
email: email,
authenticated: true,
session: session,
isLoading: false
})
}
setAuthState((prev) => {
return {
...prev,
isLoading: false
}
})
}
loadSession()
},[])
const register = async (email: string, password: string) => {
//registration Logic goes here
}
const login = async (email: string, password: string) => {
//login functionality goes here
console.log("login called")
setAuthState((prev) => {
return{
...prev,
isLoading: true
}
})
setAuthState({
email: email,
authenticated: true,
session: "super duper session token das wir vlt mal brauchen",
isLoading: false
})
await setStorageItemAsync(SESSION_KEY, "super duper session token das wir vlt mal brauchen")
await setStorageItemAsync(USER_KEY, email)
}
const logout = async () => {
await setStorageItemAsync(SESSION_KEY, null)
await setStorageItemAsync(USER_KEY, null)
setAuthState({
email: null,
authenticated: false,
session: null,
isLoading: false
});
};
const value = {
onRegister: register,
onLogin: login,
onLogout: logout,
authState
}
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}

View file

@ -1,9 +0,0 @@
import { View, Text } from 'react-native'
import React from 'react'
import { Redirect } from 'expo-router'
export default function index() {
return (
<Redirect href={"(tabs)/home"}></Redirect>
)
}

14
app/index.tsx Normal file
View file

@ -0,0 +1,14 @@
import React, { useEffect } from 'react'
import { Redirect } from 'expo-router'
import { useAuth } from './contexts/AuthContext'
export default function index() {
const {authState} = useAuth()
return (
<Redirect href={authState?.authenticated ? "/home/" : "/login"}></Redirect>
)
}

46
app/login.tsx Normal file
View file

@ -0,0 +1,46 @@
import { View, Text, SafeAreaView, TextInput, Button} from 'react-native'
import React, { useEffect, useState } from 'react'
import { useAuth } from './contexts/AuthContext'
import { Redirect } from 'expo-router';
import { FontAwesome } from "@expo/vector-icons";
import { Input } from '../components';
export default function login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("")
const {authState, onLogin} = useAuth();
// const {authState, onLogin} = useAuth();
// useEffect(() => {
// login()
// }, [])
const login = async() => {
await onLogin!(email, password);
}
return (
<SafeAreaView style={{flex: 1, justifyContent: "center"}}>
{authState?.authenticated &&
<Redirect href={"/"}></Redirect>}
<Input
placeholder={'Email'}
label='Email or Username'
leftIcon={<FontAwesome name="user" size={20} />}
onChangeHandler={setEmail}
/>
<Input
placeholder={'Enter Password'}
label='Password'
leftIcon={<FontAwesome name="key" size={20} />}
rightIcon={<FontAwesome name="key" size={20} />}
onChangeHandler={setPassword}
secure = {true}
/>
<Button title='login' onPress={login}></Button>
</SafeAreaView>
);
}

View file

@ -6,10 +6,15 @@ import Welcome from "./home/Welcome/Welcome"
import Plus from "./common/plus/plus"
import SearchBar from "./common/searchBar/SearchBar"
//login
import Input from "./login/input"
export {
ExpenseItem,
Welcome,
Plus,
SearchBar
SearchBar,
Input,
}

View file

@ -0,0 +1,85 @@
import React from 'react';
import {View, Text, TextInput, StyleSheet} from 'react-native';
import { NativeSyntheticEvent } from 'react-native/Libraries/Types/CoreEventTypes';
import { TextInputEndEditingEventData } from 'react-native/Libraries/Components/TextInput/TextInput';
interface InputProps {
label? : string,
outlined? : boolean,
placeholder?: string,
leftIcon?: any,
rightIcon?: any,
numLines?: number,
onChangeHandler?: (text: string)=>void,
secure?: boolean,
validate?: (e : NativeSyntheticEvent<TextInputEndEditingEventData>)=>void, // ob die line "gecheckt" werden soll
errorMessage? : any, //error msg
errorColor?: string,
bgColor?: string,
}
function Input({
label,
outlined,
placeholder,
leftIcon,
rightIcon,
numLines,
onChangeHandler,
secure,
validate,
errorMessage,
errorColor,
bgColor
} : InputProps) {
const containerBorder = outlined ? styles.outlined : styles.standard
if(numLines == undefined){
numLines = 1
}
return (
<View style={{padding:10}}>
<Text style={styles.label}>{label}</Text>
<View
style={[styles.container, containerBorder, {backgroundColor: bgColor ? bgColor : "white"}]}>
<View style={{paddingRight:10}}>{leftIcon}</View>
<TextInput secureTextEntry={secure} placeholder={
placeholder ? placeholder : label ? 'Enter ${label}' : ''
}
onChangeText={onChangeHandler}
onEndEditing={validate}
multiline={numLines > 1 ? true : false}
numberOfLines={numLines}
style={{flex: 4}}
/>
{rightIcon}
</View>
<Text style={{color: errorColor? errorColor: "red"}}>{errorMessage}</Text>
</View>
)
}
const styles = StyleSheet.create({
label: {
fontWeight: '500',
},
container: {
padding: 10,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'white'
},
outlined: {
borderColor: 'darkgrey',
borderRadius: 4,
borderWidth: 1,
},
standard: {
borderBottomColor: 'darkgrey',
borderBottomWidth: 1,
},
})
export default Input;

9
package-lock.json generated
View file

@ -14,6 +14,7 @@
"expo-font": "~11.4.0",
"expo-linking": "~5.0.2",
"expo-router": "^2.0.0",
"expo-secure-store": "~12.3.1",
"expo-splash-screen": "~0.20.5",
"expo-status-bar": "~1.6.0",
"expo-system-ui": "~2.4.0",
@ -9008,6 +9009,14 @@
}
}
},
"node_modules/expo-secure-store": {
"version": "12.3.1",
"resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-12.3.1.tgz",
"integrity": "sha512-XLIgWDiIuiR0c+AA4NCWWibAMHCZUyRcy+lQBU49U6rvG+xmd3YrBJfQjfqAPyLroEqnLPGTWUX57GyRsfDOQw==",
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-splash-screen": {
"version": "0.20.5",
"resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-0.20.5.tgz",

View file

@ -34,7 +34,8 @@
"react-native-gesture-handler": "~2.12.0",
"react-native-safe-area-context": "4.6.3",
"react-native-screens": "~3.22.0",
"react-native-web": "~0.19.6"
"react-native-web": "~0.19.6",
"expo-secure-store": "~12.3.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",