diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx
index fb022e3..2987b71 100644
--- a/app/(tabs)/_layout.tsx
+++ b/app/(tabs)/_layout.tsx
@@ -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 (
+ )
+ }
+
return (
+
{plusShow && {
router.push("/(tabs)/home/addItem")
}}/>}
@@ -61,7 +62,7 @@ export default function Page() {
data={data}
ListHeaderComponent={
<>
- console.log("hello")}>
+
>
}
@@ -72,7 +73,7 @@ export default function Page() {
scrollEventThrottle={20}
>
-
+
);
}
\ No newline at end of file
diff --git a/app/_layout.tsx b/app/_layout.tsx
new file mode 100644
index 0000000..42cdecd
--- /dev/null
+++ b/app/_layout.tsx
@@ -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 (
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/contexts/AuthContext.tsx b/app/contexts/AuthContext.tsx
new file mode 100644
index 0000000..236c962
--- /dev/null
+++ b/app/contexts/AuthContext.tsx
@@ -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;
+ onLogin?: (email: string, password: string) => Promise
+ onLogout?: () => void
+}
+
+const SESSION_KEY = 'my_session'
+const USER_KEY = "email"
+const AuthContext = createContext({})
+
+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 {
+ 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 {children}
+}
\ No newline at end of file
diff --git a/app/index.jsx b/app/index.jsx
deleted file mode 100644
index 05e453f..0000000
--- a/app/index.jsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { View, Text } from 'react-native'
-import React from 'react'
-import { Redirect } from 'expo-router'
-
-export default function index() {
- return (
-
- )
-}
\ No newline at end of file
diff --git a/app/index.tsx b/app/index.tsx
new file mode 100644
index 0000000..094049b
--- /dev/null
+++ b/app/index.tsx
@@ -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 (
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/login.tsx b/app/login.tsx
new file mode 100644
index 0000000..501e82f
--- /dev/null
+++ b/app/login.tsx
@@ -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 (
+
+
+ {authState?.authenticated &&
+ }
+ }
+ onChangeHandler={setEmail}
+ />
+ }
+ rightIcon={}
+ onChangeHandler={setPassword}
+ secure = {true}
+ />
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/index.jsx b/components/index.tsx
similarity index 79%
rename from components/index.jsx
rename to components/index.tsx
index 403df5a..871d5ce 100644
--- a/components/index.jsx
+++ b/components/index.tsx
@@ -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,
}
diff --git a/components/login/input.tsx b/components/login/input.tsx
new file mode 100644
index 0000000..6e6ec48
--- /dev/null
+++ b/components/login/input.tsx
@@ -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)=>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 (
+
+ {label}
+
+ {leftIcon}
+
+ 1 ? true : false}
+ numberOfLines={numLines}
+ style={{flex: 4}}
+ />
+ {rightIcon}
+
+ {errorMessage}
+
+
+ )
+}
+
+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;
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index a72517a..6e8bf8b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 4a2fb5a..914e2df 100644
--- a/package.json
+++ b/package.json
@@ -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",