Utilisation de mutations plutôt que d'appels fetch directs
This commit is contained in:
parent
b0c17db233
commit
1c52ff5a10
@ -1,21 +1,32 @@
|
|||||||
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'
|
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'
|
||||||
import { Stack } from "expo-router"
|
import { Stack, useNavigationContainerRef } from 'expo-router'
|
||||||
import { useColorScheme } from '@/hooks/useColorScheme'
|
|
||||||
import { StatusBar } from 'expo-status-bar'
|
import { StatusBar } from 'expo-status-bar'
|
||||||
import { Provider as StoreProvider } from 'react-redux'
|
import { Provider as StoreProvider } from 'react-redux'
|
||||||
import { MD3DarkTheme, MD3LightTheme, PaperProvider } from 'react-native-paper'
|
import { MD3DarkTheme, MD3LightTheme, PaperProvider } from 'react-native-paper'
|
||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
|
import { useReactNavigationDevTools } from '@dev-plugins/react-navigation'
|
||||||
|
import { useReactQueryDevTools } from '@dev-plugins/react-query'
|
||||||
|
import { useColorScheme } from '@/hooks/useColorScheme'
|
||||||
import store from '@/utils/store'
|
import store from '@/utils/store'
|
||||||
import { useStartBackgroundFetchServiceEffect } from '@/utils/background'
|
import { useStartBackgroundFetchServiceEffect } from '@/utils/background'
|
||||||
import { useStartGeolocationServiceEffect } from '@/utils/geolocation'
|
import { useStartGeolocationServiceEffect } from '@/utils/geolocation'
|
||||||
import LoginProvider from '@/components/LoginProvider'
|
import LoginProvider from '@/components/LoginProvider'
|
||||||
|
|
||||||
|
const queryClient = new QueryClient()
|
||||||
|
|
||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
useStartGeolocationServiceEffect()
|
useStartGeolocationServiceEffect()
|
||||||
useStartBackgroundFetchServiceEffect()
|
useStartBackgroundFetchServiceEffect()
|
||||||
const colorScheme = useColorScheme()
|
const colorScheme = useColorScheme()
|
||||||
|
|
||||||
|
const navigationRef = useNavigationContainerRef()
|
||||||
|
useReactNavigationDevTools(navigationRef)
|
||||||
|
|
||||||
|
useReactQueryDevTools(queryClient)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StoreProvider store={store}>
|
<StoreProvider store={store}>
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
<LoginProvider loginRedirect={'/login'}>
|
<LoginProvider loginRedirect={'/login'}>
|
||||||
<PaperProvider theme={colorScheme === 'dark' ? MD3DarkTheme : MD3LightTheme}>
|
<PaperProvider theme={colorScheme === 'dark' ? MD3DarkTheme : MD3LightTheme}>
|
||||||
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||||
@ -28,6 +39,7 @@ export default function RootLayout() {
|
|||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</PaperProvider>
|
</PaperProvider>
|
||||||
</LoginProvider>
|
</LoginProvider>
|
||||||
|
</QueryClientProvider>
|
||||||
</StoreProvider>
|
</StoreProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import { useLoginMutation } from "@/hooks/mutations/useLoginMutation"
|
||||||
import { useAuth, useAuthLogin, useAuthLogout } from "@/hooks/useAuth"
|
import { useAuth, useAuthLogin, useAuthLogout } from "@/hooks/useAuth"
|
||||||
import * as SecureStore from "@/utils/SecureStore"
|
import { useMutation } from "@tanstack/react-query"
|
||||||
import { useRouter } from "expo-router"
|
import { useRouter } from "expo-router"
|
||||||
import { useRef, useState } from "react"
|
import { useRef, useState } from "react"
|
||||||
import { Platform } from "react-native"
|
|
||||||
import { Appbar, Button, Dialog, Portal, Surface, Text, TextInput } from "react-native-paper"
|
import { Appbar, Button, Dialog, Portal, Surface, Text, TextInput } from "react-native-paper"
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
@ -13,7 +13,6 @@ export default function Login() {
|
|||||||
const authLogout = useAuthLogout()
|
const authLogout = useAuthLogout()
|
||||||
|
|
||||||
const isLoggedIn = auth.loggedIn
|
const isLoggedIn = auth.loggedIn
|
||||||
const [loggingIn, setLoggingIn] = useState(false)
|
|
||||||
const [name, setName] = useState(auth.name ?? "")
|
const [name, setName] = useState(auth.name ?? "")
|
||||||
const [password, setPassword] = useState("")
|
const [password, setPassword] = useState("")
|
||||||
const [errorDialogVisible, setErrorDialogVisible] = useState(false)
|
const [errorDialogVisible, setErrorDialogVisible] = useState(false)
|
||||||
@ -25,80 +24,55 @@ export default function Login() {
|
|||||||
|
|
||||||
const hideErrorDialog = () => setErrorDialogVisible(false)
|
const hideErrorDialog = () => setErrorDialogVisible(false)
|
||||||
|
|
||||||
async function login() {
|
const loginMutation = useLoginMutation({
|
||||||
if (loggingIn)
|
authLogin,
|
||||||
return
|
onPostSuccess: () => {
|
||||||
setLoggingIn(true)
|
|
||||||
const resp = await fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/auth/login/`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({ name: name, password: password })
|
|
||||||
})
|
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(err => {
|
|
||||||
setErrorDialogVisible(true)
|
|
||||||
setErrorTitle("Erreur")
|
|
||||||
setErrorText("Une erreur inconnue est survenue lors de la connexion. Veuillez réessayer plus tard. " + err)
|
|
||||||
setLoggingIn(false)
|
|
||||||
})
|
|
||||||
if (!resp)
|
|
||||||
return
|
|
||||||
else if (resp.error) {
|
|
||||||
setErrorDialogVisible(true)
|
|
||||||
setErrorTitle(resp.error)
|
|
||||||
setErrorText(resp.message)
|
|
||||||
setLoggingIn(false)
|
|
||||||
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
|
|
||||||
SecureStore.setItem("apiPassword", password)
|
|
||||||
}
|
|
||||||
SecureStore.setItem("apiToken", resp.accessToken)
|
|
||||||
if (router.canGoBack())
|
if (router.canGoBack())
|
||||||
router.back()
|
router.back()
|
||||||
else
|
else
|
||||||
router.navigate('/')
|
router.navigate('/')
|
||||||
|
},
|
||||||
|
onError: ({ response, error }) => {
|
||||||
|
setErrorDialogVisible(true)
|
||||||
|
if (response) {
|
||||||
|
setErrorTitle(response.error)
|
||||||
|
setErrorText(response.message)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
async function logout() {
|
setErrorTitle("Erreur")
|
||||||
authLogout()
|
setErrorText(`Une erreur est survenue lors de la connexion : ${error}`)
|
||||||
await SecureStore.deleteItemAsync("apiName")
|
|
||||||
await SecureStore.deleteItemAsync("apiPassword")
|
|
||||||
await SecureStore.deleteItemAsync("apiToken")
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Surface style={{ flex: 1 }}>
|
<Surface style={{ flex: 1 }}>
|
||||||
<Appbar.Header>
|
<Appbar.Header>
|
||||||
{isLoggedIn && router.canGoBack() ? <Appbar.BackAction onPress={() => router.back()} /> : undefined}
|
{isLoggedIn && router.canGoBack() ? <Appbar.BackAction onPress={() => router.back()} /> : undefined}
|
||||||
<Appbar.Content title={"Connexion"} />
|
<Appbar.Content title={"Connexion"} />
|
||||||
{isLoggedIn ? <Appbar.Action icon={"logout"} onPress={logout} /> : undefined}
|
{isLoggedIn ? <Appbar.Action icon={"logout"} onPress={authLogout} /> : undefined}
|
||||||
</Appbar.Header>
|
</Appbar.Header>
|
||||||
<TextInput
|
<TextInput
|
||||||
ref={loginRef}
|
ref={loginRef}
|
||||||
label="Nom"
|
label="Nom"
|
||||||
value={name}
|
value={name}
|
||||||
onChangeText={(text) => setName(text)}
|
onChangeText={setName}
|
||||||
onSubmitEditing={() => passwordRef?.current.focus()}
|
onSubmitEditing={() => passwordRef?.current.focus()}
|
||||||
style={{ margin: 8 }} />
|
style={{ margin: 8 }} />
|
||||||
<TextInput
|
<TextInput
|
||||||
ref={passwordRef}
|
ref={passwordRef}
|
||||||
label="Mot de passe"
|
label="Mot de passe"
|
||||||
value={password}
|
value={password}
|
||||||
onChangeText={(text) => setPassword(text)}
|
onChangeText={setPassword}
|
||||||
onSubmitEditing={login}
|
onSubmitEditing={() => loginMutation.mutate({ name, password })}
|
||||||
secureTextEntry={true}
|
secureTextEntry={true}
|
||||||
style={{ margin: 8 }} />
|
style={{ margin: 8 }} />
|
||||||
<Button
|
<Button
|
||||||
key={loggingIn ? "disabledLoginButton" : "loginButton"}
|
key={loginMutation.isPending ? "disabledLoginButton" : "loginButton"}
|
||||||
onPress={login}
|
onPress={() => loginMutation.mutate({ name, password })}
|
||||||
mode={"contained"}
|
mode={"contained"}
|
||||||
icon="login"
|
icon="login"
|
||||||
disabled={loggingIn}
|
disabled={loginMutation.isPending}
|
||||||
style={{ margin: 8 }}>
|
style={{ margin: 8 }}>
|
||||||
Se connecter
|
Se connecter
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -3,6 +3,7 @@ import { useRouteInfo } from 'expo-router/build/hooks'
|
|||||||
import { ReactNode, useEffect } from 'react'
|
import { ReactNode, useEffect } from 'react'
|
||||||
import { useAuth, useAuthLogin } from '@/hooks/useAuth'
|
import { useAuth, useAuthLogin } from '@/hooks/useAuth'
|
||||||
import * as SecureStore from '@/utils/SecureStore'
|
import * as SecureStore from '@/utils/SecureStore'
|
||||||
|
import { useLoginMutation } from '@/hooks/mutations/useLoginMutation'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
loginRedirect: Href
|
loginRedirect: Href
|
||||||
@ -14,6 +15,15 @@ export default function LoginProvider({ loginRedirect, children }: Props) {
|
|||||||
const route = useRouteInfo()
|
const route = useRouteInfo()
|
||||||
const auth = useAuth()
|
const auth = useAuth()
|
||||||
const authLogin = useAuthLogin()
|
const authLogin = useAuthLogin()
|
||||||
|
const loginMutation = useLoginMutation({
|
||||||
|
authLogin,
|
||||||
|
onError: ({ response }) => {
|
||||||
|
if (response)
|
||||||
|
authLogin({ name: auth.name ?? "", password: null, token: null })
|
||||||
|
else
|
||||||
|
authLogin({ name: auth.name ?? "", token: null })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Renouvellement auto du jeton d'authentification
|
// Renouvellement auto du jeton d'authentification
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -31,23 +41,8 @@ export default function LoginProvider({ loginRedirect, children }: Props) {
|
|||||||
}
|
}
|
||||||
const timeout = setTimeout(async () => {
|
const timeout = setTimeout(async () => {
|
||||||
const password = SecureStore.getItem('apiPassword')
|
const password = SecureStore.getItem('apiPassword')
|
||||||
if (password) {
|
if (password)
|
||||||
await fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/auth/login/`, {
|
loginMutation.mutate({ name, password })
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({ name: name, password: password })
|
|
||||||
})
|
|
||||||
.then(resp => resp.json())
|
|
||||||
.then(resp => {
|
|
||||||
if (!resp.error)
|
|
||||||
authLogin({ name: name, token: resp.accessToken })
|
|
||||||
else
|
|
||||||
authLogin({ name: name, token: null })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
authLogin({ name: name, token: null })
|
|
||||||
}
|
|
||||||
}, waitTime)
|
}, waitTime)
|
||||||
return () => clearTimeout(timeout)
|
return () => clearTimeout(timeout)
|
||||||
}, [auth])
|
}, [auth])
|
||||||
|
49
client/hooks/mutations/useLoginMutation.ts
Normal file
49
client/hooks/mutations/useLoginMutation.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { AuthPayload } from "@/utils/features/location/authSlice"
|
||||||
|
import { useMutation } from "@tanstack/react-query"
|
||||||
|
|
||||||
|
type ErrorResponse = {
|
||||||
|
error: string
|
||||||
|
message: string
|
||||||
|
statusCode: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginForm = {
|
||||||
|
name: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type onPostSuccessFunc = () => void
|
||||||
|
type ErrorFuncProps = { response?: ErrorResponse, error?: Error }
|
||||||
|
type onErrorFunc = (props: ErrorFuncProps) => void
|
||||||
|
|
||||||
|
type LoginProps = {
|
||||||
|
authLogin: (payload: AuthPayload) => { payload: AuthPayload, type: "auth/login" }
|
||||||
|
onPostSuccess?: onPostSuccessFunc
|
||||||
|
onError?: onErrorFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useLoginMutation = ({ authLogin, onPostSuccess, onError }: LoginProps) => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ name, password }: LoginForm) => {
|
||||||
|
return fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/auth/login/`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ name: name, password: password })
|
||||||
|
}).then(resp => resp.json())
|
||||||
|
},
|
||||||
|
onSuccess: (data, { name, password }: LoginForm) => {
|
||||||
|
if (data.error) {
|
||||||
|
if (onError)
|
||||||
|
onError({ response: data })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
authLogin({ name: name, password: password, token: data.accessToken })
|
||||||
|
if (onPostSuccess)
|
||||||
|
onPostSuccess()
|
||||||
|
},
|
||||||
|
onError: (error: Error) => {
|
||||||
|
if (onError)
|
||||||
|
onError({ error: error })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
94
client/package-lock.json
generated
94
client/package-lock.json
generated
@ -8,12 +8,15 @@
|
|||||||
"name": "traintrape-moi-client",
|
"name": "traintrape-moi-client",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@dev-plugins/react-navigation": "^0.1.0",
|
||||||
|
"@dev-plugins/react-query": "^0.1.0",
|
||||||
"@expo/vector-icons": "^14.0.2",
|
"@expo/vector-icons": "^14.0.2",
|
||||||
"@maplibre/maplibre-react-native": "^10.0.0-alpha.28",
|
"@maplibre/maplibre-react-native": "^10.0.0-alpha.28",
|
||||||
"@pchmn/expo-material3-theme": "github:pchmn/expo-material3-theme",
|
"@pchmn/expo-material3-theme": "github:pchmn/expo-material3-theme",
|
||||||
"@react-navigation/bottom-tabs": "^7.0.0",
|
"@react-navigation/bottom-tabs": "^7.0.0",
|
||||||
"@react-navigation/native": "^7.0.0",
|
"@react-navigation/native": "^7.0.0",
|
||||||
"@reduxjs/toolkit": "^2.4.0",
|
"@reduxjs/toolkit": "^2.4.0",
|
||||||
|
"@tanstack/react-query": "^5.62.7",
|
||||||
"@turf/circle": "^7.1.0",
|
"@turf/circle": "^7.1.0",
|
||||||
"expo": "~52.0.11",
|
"expo": "~52.0.11",
|
||||||
"expo-background-fetch": "~13.0.3",
|
"expo-background-fetch": "~13.0.3",
|
||||||
@ -2313,6 +2316,51 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@dev-plugins/react-navigation": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dev-plugins/react-navigation/-/react-navigation-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-eV6gkA/wH2E7LS6UfH5Kw1Qhk4zcMU3OMhQSqn4XCZn33HoT/Q2tcBHrUiiWcBVX9MwB9NyJB0hPnJ8lNAIQxg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-navigation/devtools": "^7.0.1",
|
||||||
|
"nanoid": "^5.0.8"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@react-navigation/core": "*",
|
||||||
|
"expo": "^52.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dev-plugins/react-navigation/node_modules/nanoid": {
|
||||||
|
"version": "5.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
|
||||||
|
"integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18 || >=20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dev-plugins/react-query": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dev-plugins/react-query/-/react-query-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-GZeF9+AHI98DjUuga6YCwbhlq2BpaQ3rGUc7o9weO4oEXNFF7rv2asWpMDdBa0BXvVZjdERSW7HrRx2JAWF+6w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"flatted": "^3.3.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tanstack/react-query": "*",
|
||||||
|
"expo": "^52.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@egjs/hammerjs": {
|
"node_modules/@egjs/hammerjs": {
|
||||||
"version": "2.0.17",
|
"version": "2.0.17",
|
||||||
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
|
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
|
||||||
@ -4207,6 +4255,20 @@
|
|||||||
"react": ">= 18.2.0"
|
"react": ">= 18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-navigation/devtools": {
|
||||||
|
"version": "7.0.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/devtools/-/devtools-7.0.14.tgz",
|
||||||
|
"integrity": "sha512-Pb80D3kO84wW/VezHXTks1Bpbk0O6XTEJSIyzanXC3h4clICq/sVQIcXjHbHrtQnNB0SJdhf6/LG9l+SRyatYw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"nanoid": "3.3.7",
|
||||||
|
"stacktrace-parser": "^0.1.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 18.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-navigation/elements": {
|
"node_modules/@react-navigation/elements": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.0.tgz",
|
||||||
@ -4445,6 +4507,32 @@
|
|||||||
"@sinonjs/commons": "^3.0.0"
|
"@sinonjs/commons": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tanstack/query-core": {
|
||||||
|
"version": "5.62.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.7.tgz",
|
||||||
|
"integrity": "sha512-fgpfmwatsrUal6V+8EC2cxZIQVl9xvL7qYa03gsdsCy985UTUlS4N+/3hCzwR0PclYDqisca2AqR1BVgJGpUDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/react-query": {
|
||||||
|
"version": "5.62.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.7.tgz",
|
||||||
|
"integrity": "sha512-+xCtP4UAFDTlRTYyEjLx0sRtWyr5GIk7TZjZwBu4YaNahi3Rt2oMyRqfpfVrtwsqY2sayP4iXVCwmC+ZqqFmuw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-core": "5.62.7"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18 || ^19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tootallnate/once": {
|
"node_modules/@tootallnate/once": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
|
||||||
@ -8381,6 +8469,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/flatted": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/flow-enums-runtime": {
|
"node_modules/flow-enums-runtime": {
|
||||||
"version": "0.0.6",
|
"version": "0.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz",
|
||||||
|
@ -14,12 +14,15 @@
|
|||||||
"preset": "jest-expo"
|
"preset": "jest-expo"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@dev-plugins/react-navigation": "^0.1.0",
|
||||||
|
"@dev-plugins/react-query": "^0.1.0",
|
||||||
"@expo/vector-icons": "^14.0.2",
|
"@expo/vector-icons": "^14.0.2",
|
||||||
"@maplibre/maplibre-react-native": "^10.0.0-alpha.28",
|
"@maplibre/maplibre-react-native": "^10.0.0-alpha.28",
|
||||||
"@pchmn/expo-material3-theme": "github:pchmn/expo-material3-theme",
|
"@pchmn/expo-material3-theme": "github:pchmn/expo-material3-theme",
|
||||||
"@react-navigation/bottom-tabs": "^7.0.0",
|
"@react-navigation/bottom-tabs": "^7.0.0",
|
||||||
"@react-navigation/native": "^7.0.0",
|
"@react-navigation/native": "^7.0.0",
|
||||||
"@reduxjs/toolkit": "^2.4.0",
|
"@reduxjs/toolkit": "^2.4.0",
|
||||||
|
"@tanstack/react-query": "^5.62.7",
|
||||||
"@turf/circle": "^7.1.0",
|
"@turf/circle": "^7.1.0",
|
||||||
"expo": "~52.0.11",
|
"expo": "~52.0.11",
|
||||||
"expo-background-fetch": "~13.0.3",
|
"expo-background-fetch": "~13.0.3",
|
||||||
@ -31,7 +34,6 @@
|
|||||||
"expo-linking": "~7.0.3",
|
"expo-linking": "~7.0.3",
|
||||||
"expo-location": "^18.0.2",
|
"expo-location": "^18.0.2",
|
||||||
"expo-notifications": "~0.29.11",
|
"expo-notifications": "~0.29.11",
|
||||||
"expo-updates": "~0.26.10",
|
|
||||||
"expo-router": "~4.0.9",
|
"expo-router": "~4.0.9",
|
||||||
"expo-secure-store": "~14.0.0",
|
"expo-secure-store": "~14.0.0",
|
||||||
"expo-splash-screen": "~0.29.13",
|
"expo-splash-screen": "~0.29.13",
|
||||||
@ -39,6 +41,7 @@
|
|||||||
"expo-symbols": "~0.2.0",
|
"expo-symbols": "~0.2.0",
|
||||||
"expo-system-ui": "~4.0.4",
|
"expo-system-ui": "~4.0.4",
|
||||||
"expo-task-manager": "^12.0.3",
|
"expo-task-manager": "^12.0.3",
|
||||||
|
"expo-updates": "~0.26.10",
|
||||||
"expo-web-browser": "~14.0.1",
|
"expo-web-browser": "~14.0.1",
|
||||||
"maplibre-gl": "^4.7.1",
|
"maplibre-gl": "^4.7.1",
|
||||||
"maplibre-react-components": "^0.1.9",
|
"maplibre-react-components": "^0.1.9",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
import * as SecureStore from '@/utils/SecureStore'
|
import * as SecureStore from '@/utils/SecureStore'
|
||||||
|
import { Platform } from 'react-native'
|
||||||
|
|
||||||
interface AuthState {
|
interface AuthState {
|
||||||
loggedIn: boolean,
|
loggedIn: boolean,
|
||||||
@ -9,6 +10,7 @@ interface AuthState {
|
|||||||
|
|
||||||
export interface AuthPayload {
|
export interface AuthPayload {
|
||||||
name: string,
|
name: string,
|
||||||
|
password?: string | null,
|
||||||
token: string | null,
|
token: string | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,12 +28,28 @@ export const authSlice = createSlice({
|
|||||||
state.loggedIn = action.payload.token !== null
|
state.loggedIn = action.payload.token !== null
|
||||||
state.name = action.payload.name
|
state.name = action.payload.name
|
||||||
state.token = action.payload.token
|
state.token = action.payload.token
|
||||||
console.log(state)
|
|
||||||
|
SecureStore.setItem('apiName', action.payload.name)
|
||||||
|
if (action.payload.password !== undefined && Platform.OS !== "web") {
|
||||||
|
// Le stockage navigateur n'est pas sûr, on évite de stocker un mot de passe à l'intérieur
|
||||||
|
if (action.payload.password)
|
||||||
|
SecureStore.setItem('apiPassword', action.payload.password)
|
||||||
|
else
|
||||||
|
SecureStore.deleteItemAsync('apiPassword')
|
||||||
|
}
|
||||||
|
if (action.payload.token)
|
||||||
|
SecureStore.setItem('apiToken', action.payload.token)
|
||||||
|
else
|
||||||
|
SecureStore.deleteItemAsync('apiToken')
|
||||||
},
|
},
|
||||||
logout: (state) => {
|
logout: (state) => {
|
||||||
state.loggedIn = false
|
state.loggedIn = false
|
||||||
state.name = null
|
state.name = null
|
||||||
state.token = null
|
state.token = null
|
||||||
|
|
||||||
|
SecureStore.deleteItemAsync('apiName')
|
||||||
|
SecureStore.deleteItemAsync('apiPassword')
|
||||||
|
SecureStore.deleteItemAsync('apiToken')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user