diff --git a/client/app/(tabs)/settings.tsx b/client/app/(tabs)/settings.tsx
index 498a790..e3de771 100644
--- a/client/app/(tabs)/settings.tsx
+++ b/client/app/(tabs)/settings.tsx
@@ -1,16 +1,16 @@
-import * as SecureStore from '@/utils/SecureStore'
+import { useAuth } from '@/hooks/useAuth'
import { useRouter } from 'expo-router'
import { FAB, List, Surface } from 'react-native-paper'
export default function HistoryScreen() {
const router = useRouter()
- const isLoggedIn = SecureStore.getItem("apiToken") !== null
+ const auth = useAuth()
return (
router.navigate('/login')} />}
onPress={() => router.navigate('/login')} />
diff --git a/client/app/_layout.tsx b/client/app/_layout.tsx
index 61be9f8..fe93acd 100644
--- a/client/app/_layout.tsx
+++ b/client/app/_layout.tsx
@@ -1,42 +1,33 @@
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'
-import { Stack, useRouter } from "expo-router"
+import { Stack } from "expo-router"
import { useColorScheme } from '@/hooks/useColorScheme'
import { StatusBar } from 'expo-status-bar'
import { Provider as StoreProvider } from 'react-redux'
import { MD3DarkTheme, MD3LightTheme, PaperProvider } from 'react-native-paper'
import store from '@/utils/store'
-import * as SecureStore from '@/utils/SecureStore'
import { useStartBackgroundFetchServiceEffect } from '@/utils/background'
import { useStartGeolocationServiceEffect } from '@/utils/geolocation'
-import { useEffect } from 'react'
-import { useRouteInfo } from 'expo-router/build/hooks'
+import LoginProvider from '@/components/LoginProvider'
export default function RootLayout() {
useStartGeolocationServiceEffect()
useStartBackgroundFetchServiceEffect()
const colorScheme = useColorScheme()
- const router = useRouter()
- const route = useRouteInfo()
-
- // Si on est pas connecté⋅e, on reste sur la fenêtre de connexion
- useEffect(() => {
- const isLoggedIn = SecureStore.getItem("apiToken") !== null
- if (!isLoggedIn && route.pathname !== "/login")
- router.navigate("/login")
- }, [route, router])
return (
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
)
}
diff --git a/client/app/login.tsx b/client/app/login.tsx
index 63859a8..f3a464c 100644
--- a/client/app/login.tsx
+++ b/client/app/login.tsx
@@ -1,3 +1,4 @@
+import { useAuth, useAuthLogin, useAuthLogout } from "@/hooks/useAuth"
import * as SecureStore from "@/utils/SecureStore"
import { useRouter } from "expo-router"
import { useRef, useState } from "react"
@@ -6,9 +7,14 @@ import { Appbar, Button, Dialog, Portal, Surface, Text, TextInput } from "react-
export default function Login() {
const router = useRouter()
- const [isLoggedIn, setIsLoggedIn] = useState(SecureStore.getItem("apiToken") !== null)
+
+ const auth = useAuth()
+ const authLogin = useAuthLogin()
+ const authLogout = useAuthLogout()
+
+ const isLoggedIn = auth.loggedIn
const [loggingIn, setLoggingIn] = useState(false)
- const [name, setName] = useState(SecureStore.getItem('apiName') ?? "")
+ const [name, setName] = useState(auth.name ?? "")
const [password, setPassword] = useState("")
const [errorDialogVisible, setErrorDialogVisible] = useState(false)
const [errorTitle, setErrorTitle] = useState("")
@@ -45,6 +51,7 @@ export default function Login() {
return
}
setLoggingIn(false)
+ authLogin({ name: name, token: resp.accessToken })
SecureStore.setItem("apiName", name)
if (Platform.OS !== "web") {
// Le stockage navigateur n'est pas sûr, on évite de stocker un mot de passe à l'intérieur
@@ -58,10 +65,10 @@ export default function Login() {
}
async function logout() {
+ authLogout()
await SecureStore.deleteItemAsync("apiName")
await SecureStore.deleteItemAsync("apiPassword")
await SecureStore.deleteItemAsync("apiToken")
- setIsLoggedIn(false)
}
return (
diff --git a/client/components/LoginProvider.tsx b/client/components/LoginProvider.tsx
new file mode 100644
index 0000000..40fb3f9
--- /dev/null
+++ b/client/components/LoginProvider.tsx
@@ -0,0 +1,25 @@
+import { useAuth } from "@/hooks/useAuth"
+import { Href, useRouter } from "expo-router"
+import { useRouteInfo } from "expo-router/build/hooks"
+import { ReactNode, useEffect } from "react"
+
+type Props = {
+ loginRedirect: Href
+ children: ReactNode
+}
+
+export default function LoginProvider({ loginRedirect, children }: Props) {
+ const router = useRouter()
+ const route = useRouteInfo()
+
+ // Si on est pas connecté⋅e, on reste sur la fenêtre de connexion
+ const auth = useAuth()
+ useEffect(() => {
+ if (!auth.loggedIn && route.pathname !== loginRedirect)
+ router.navigate(loginRedirect)
+ }, [auth, route, router])
+
+ return <>
+ {children}
+ >
+}
\ No newline at end of file
diff --git a/client/hooks/useAuth.ts b/client/hooks/useAuth.ts
new file mode 100644
index 0000000..0f414cd
--- /dev/null
+++ b/client/hooks/useAuth.ts
@@ -0,0 +1,12 @@
+import { useAppDispatch, useAppSelector } from "./useStore"
+import { AuthPayload, login, logout } from "@/utils/features/location/authSlice"
+
+export const useAuth = () => useAppSelector((state) => state.auth)
+export const useAuthLogin = () => {
+ const dispath = useAppDispatch()
+ return (payload: AuthPayload) => dispath(login(payload))
+}
+export const useAuthLogout = () => {
+ const dispatch = useAppDispatch()
+ return () => dispatch(logout())
+}
diff --git a/client/hooks/useLocation.ts b/client/hooks/useLocation.ts
index 240f852..856b708 100644
--- a/client/hooks/useLocation.ts
+++ b/client/hooks/useLocation.ts
@@ -3,7 +3,7 @@ import { useAppDispatch, useAppSelector } from "./useStore"
import { setLocation } from "@/utils/features/location/locationSlice"
export const useLocation = () => useAppSelector((state) => state.location.location)
-export const useSetLocation = () => (location: LocationObject) => {
+export const useSetLocation = () => {
const dispatch = useAppDispatch()
- dispatch(setLocation(location))
+ return (location: LocationObject) => dispatch(setLocation(location))
}
diff --git a/client/utils/features/location/authSlice.ts b/client/utils/features/location/authSlice.ts
new file mode 100644
index 0000000..9365c35
--- /dev/null
+++ b/client/utils/features/location/authSlice.ts
@@ -0,0 +1,40 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit'
+import * as SecureStore from '@/utils/SecureStore'
+
+interface AuthState {
+ loggedIn: boolean,
+ name: string | null,
+ token: string | null,
+}
+
+export interface AuthPayload {
+ name: string | null,
+ token: string | null,
+}
+
+const initialState: AuthState = {
+ loggedIn: SecureStore.getItem('apiName') !== null && SecureStore.getItem('apiToken') !== null,
+ name: SecureStore.getItem('apiName'),
+ token: SecureStore.getItem('apiToken'),
+}
+
+export const authSlice = createSlice({
+ name: 'auth',
+ initialState: initialState,
+ reducers: {
+ login: (state, action: PayloadAction) => {
+ state.loggedIn = true
+ state.name = action.payload.name
+ state.token = action.payload.token
+ },
+ logout: (state) => {
+ state.loggedIn = false
+ state.name = null
+ state.token = null
+ }
+ },
+})
+
+export const { login, logout } = authSlice.actions
+
+export default authSlice.reducer
diff --git a/client/utils/store.ts b/client/utils/store.ts
index 35fd24e..68f6892 100644
--- a/client/utils/store.ts
+++ b/client/utils/store.ts
@@ -1,8 +1,10 @@
import { configureStore } from '@reduxjs/toolkit'
+import authReducer from './features/location/authSlice'
import locationReducer from './features/location/locationSlice'
const store = configureStore({
reducer: {
+ auth: authReducer,
location: locationReducer,
},
})