Compare commits
No commits in common. "61b0cd51ae47ed057ee50b3e351b3a81b1fee80e" and "7aa9dde5a9b55488decaef7222883af7c1608271" have entirely different histories.
61b0cd51ae
...
7aa9dde5a9
@ -1,100 +1,18 @@
|
|||||||
import { useGameRepairMutation, useGameResetMutation, useGameStartMutation, useGameStopMutation, useGameSwitchPlayerMutation } from '@/hooks/mutations/useGameMutation'
|
|
||||||
import { useAuth } from '@/hooks/useAuth'
|
import { useAuth } from '@/hooks/useAuth'
|
||||||
import { useGame, useUpdateGameState } from '@/hooks/useGame'
|
|
||||||
import { useRouter } from 'expo-router'
|
import { useRouter } from 'expo-router'
|
||||||
import { useState } from 'react'
|
import { FAB, List, Surface } from 'react-native-paper'
|
||||||
import { Button, Dialog, FAB, List, Portal, Surface, Text } from 'react-native-paper'
|
|
||||||
|
|
||||||
export default function HistoryScreen() {
|
export default function HistoryScreen() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const auth = useAuth()
|
const auth = useAuth()
|
||||||
const game = useGame()
|
|
||||||
const updateGameState = useUpdateGameState()
|
|
||||||
|
|
||||||
const gameStartMutation = useGameStartMutation({
|
|
||||||
auth,
|
|
||||||
updateGameState,
|
|
||||||
})
|
|
||||||
const gameStopMutation = useGameStopMutation({
|
|
||||||
auth,
|
|
||||||
updateGameState,
|
|
||||||
})
|
|
||||||
const gameSwitchMutation = useGameSwitchPlayerMutation({
|
|
||||||
auth,
|
|
||||||
updateGameState,
|
|
||||||
})
|
|
||||||
const gameRepairMutation = useGameRepairMutation({
|
|
||||||
auth,
|
|
||||||
updateGameState,
|
|
||||||
})
|
|
||||||
const gameResetMutation = useGameResetMutation({
|
|
||||||
auth,
|
|
||||||
updateGameState,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [resetConfirmVisible, setResetConfirmVisible] = useState(false)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Surface
|
<Surface
|
||||||
style={{ flex: 1 }}>
|
style={{ flex: 1 }}>
|
||||||
<List.Section title={"Paramètres"}>
|
<List.Item
|
||||||
<List.Item
|
title="Connexion au serveur"
|
||||||
key={"login"}
|
description={auth.loggedIn ? "Vous êtes déjà connecté⋅e" : "Vous n'êtes pas connecté⋅e"}
|
||||||
title="Connexion au serveur"
|
right={() => <FAB icon="login" size="small" onPress={() => router.navigate('/login')} />}
|
||||||
description={auth.loggedIn ? "Vous êtes déjà connecté⋅e" : "Vous n'êtes pas connecté⋅e"}
|
onPress={() => router.navigate('/login')} />
|
||||||
right={() => <FAB icon="login" size="small" onPress={() => router.navigate('/login')} />}
|
|
||||||
onPress={() => router.navigate('/login')} />
|
|
||||||
</List.Section>
|
|
||||||
<List.Section title={"Gestion du jeu"}>
|
|
||||||
<List.Item
|
|
||||||
key={"start"}
|
|
||||||
title="Démarrer le jeu"
|
|
||||||
disabled={game.gameStarted}
|
|
||||||
right={() => <FAB icon="play" size="small" disabled={game.gameStarted} />}
|
|
||||||
onPress={() => gameStartMutation.mutate()} />
|
|
||||||
<List.Item
|
|
||||||
key={"stop"}
|
|
||||||
title="Arrêter le jeu"
|
|
||||||
disabled={!game.gameStarted}
|
|
||||||
right={() => <FAB icon="stop" size="small" disabled={!game.gameStarted} />}
|
|
||||||
onPress={() => gameStopMutation.mutate()} />
|
|
||||||
<List.Item
|
|
||||||
key={"switch"}
|
|
||||||
title="Changer de joueur⋅se en course"
|
|
||||||
description="À utiliser après une capture"
|
|
||||||
disabled={!game.gameStarted}
|
|
||||||
right={() => <FAB icon="exit-run" size="small" disabled={!game.gameStarted} />}
|
|
||||||
onPress={() => gameSwitchMutation.mutate()} />
|
|
||||||
</List.Section>
|
|
||||||
<List.Section title={"Avancé"}>
|
|
||||||
<List.Item
|
|
||||||
key={"repair"}
|
|
||||||
title="Réparer"
|
|
||||||
description="Permet de réparer les soldes des joueur⋅ses à partir des défis réalisés et des trains emprunter. À manipuler avec précaution."
|
|
||||||
right={() => <FAB icon="reload-alert" size="small" variant={'tertiary'} />}
|
|
||||||
onPress={() => gameRepairMutation.mutate()} />
|
|
||||||
<List.Item
|
|
||||||
key={"reset"}
|
|
||||||
title="Réinitialiser les données de jeu"
|
|
||||||
description="Permet de détruire toutes les données. À manipuler avec précaution."
|
|
||||||
right={() => <FAB icon="reload-alert" size="small" variant={'tertiary'} />}
|
|
||||||
onPress={() => setResetConfirmVisible(true)} />
|
|
||||||
</List.Section>
|
|
||||||
<Portal>
|
|
||||||
<Dialog key="confirmReset" visible={resetConfirmVisible} onDismiss={() => setResetConfirmVisible(false)}>
|
|
||||||
<Dialog.Title>Confirmer</Dialog.Title>
|
|
||||||
<Dialog.Content>
|
|
||||||
<Text variant="bodyMedium">
|
|
||||||
Cette action va réinitialiser TOUTES les données de jeu : l'historique des positions, les défis réalisés et les trains empruntés.
|
|
||||||
Êtes-vous réellement sûr⋅e de vouloir tout supprimer ?
|
|
||||||
</Text>
|
|
||||||
</Dialog.Content>
|
|
||||||
<Dialog.Actions>
|
|
||||||
<Button onPress={() => setResetConfirmVisible(false)}>Annuler</Button>
|
|
||||||
<Button onPress={() => { setResetConfirmVisible(false); gameResetMutation.mutate() }}>Confirmer</Button>
|
|
||||||
</Dialog.Actions>
|
|
||||||
</Dialog>
|
|
||||||
</Portal>
|
|
||||||
</Surface>
|
</Surface>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ import store from '@/utils/store'
|
|||||||
import { useStartBackgroundFetchServiceEffect } from '@/utils/background'
|
import { useStartBackgroundFetchServiceEffect } from '@/utils/background'
|
||||||
import LoginProvider from '@/components/LoginProvider'
|
import LoginProvider from '@/components/LoginProvider'
|
||||||
import GeolocationProvider from '@/components/GeolocationProvider'
|
import GeolocationProvider from '@/components/GeolocationProvider'
|
||||||
import GameProvider from '@/components/GameProvider'
|
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
@ -46,18 +45,16 @@ export default function RootLayout() {
|
|||||||
onSuccess={() => queryClient.resumePausedMutations().then(() => queryClient.invalidateQueries())}>
|
onSuccess={() => queryClient.resumePausedMutations().then(() => queryClient.invalidateQueries())}>
|
||||||
<LoginProvider loginRedirect={'/login'}>
|
<LoginProvider loginRedirect={'/login'}>
|
||||||
<GeolocationProvider>
|
<GeolocationProvider>
|
||||||
<GameProvider>
|
<PaperProvider theme={colorScheme === 'dark' ? MD3DarkTheme : MD3LightTheme}>
|
||||||
<PaperProvider theme={colorScheme === 'dark' ? MD3DarkTheme : MD3LightTheme}>
|
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||||
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
|
<Stack>
|
||||||
<Stack>
|
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
||||||
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
|
<Stack.Screen name="login" options={{ headerShown: false }} />
|
||||||
<Stack.Screen name="login" options={{ headerShown: false }} />
|
<Stack.Screen name="+not-found" />
|
||||||
<Stack.Screen name="+not-found" />
|
</Stack>
|
||||||
</Stack>
|
<StatusBar style="auto" />
|
||||||
<StatusBar style="auto" />
|
</ThemeProvider>
|
||||||
</ThemeProvider>
|
</PaperProvider>
|
||||||
</PaperProvider>
|
|
||||||
</GameProvider>
|
|
||||||
</GeolocationProvider>
|
</GeolocationProvider>
|
||||||
</LoginProvider>
|
</LoginProvider>
|
||||||
</PersistQueryClientProvider>
|
</PersistQueryClientProvider>
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
import { useAuth } from '@/hooks/useAuth'
|
|
||||||
import { useUpdateGameState } from '@/hooks/useGame'
|
|
||||||
import { useQuery } from '@tanstack/react-query'
|
|
||||||
import { ReactNode, useEffect } from 'react'
|
|
||||||
|
|
||||||
export default function GameProvider({ children }: { children: ReactNode }) {
|
|
||||||
const auth = useAuth()
|
|
||||||
const updateGameState = useUpdateGameState()
|
|
||||||
const gameQuery = useQuery({
|
|
||||||
queryKey: ['update-game'],
|
|
||||||
queryFn: () => fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/game/`, {
|
|
||||||
headers: { "Authorization": `Bearer ${auth.token}` }}
|
|
||||||
).then(resp => resp.json()),
|
|
||||||
enabled: auth.loggedIn,
|
|
||||||
refetchInterval: 5000,
|
|
||||||
})
|
|
||||||
const game = gameQuery.data
|
|
||||||
useEffect(() => {
|
|
||||||
if (game)
|
|
||||||
updateGameState(game)
|
|
||||||
}, [game])
|
|
||||||
|
|
||||||
return <>
|
|
||||||
{children}
|
|
||||||
</>
|
|
||||||
}
|
|
@ -1,159 +0,0 @@
|
|||||||
import { AuthState } from "@/utils/features/auth/authSlice"
|
|
||||||
import { GamePayload, GameState } from "@/utils/features/game/gameSlice"
|
|
||||||
import { useMutation } from "@tanstack/react-query"
|
|
||||||
|
|
||||||
type ErrorResponse = {
|
|
||||||
error: string
|
|
||||||
message: string
|
|
||||||
statusCode: number
|
|
||||||
}
|
|
||||||
|
|
||||||
type onPostSuccessFunc = () => void
|
|
||||||
type ErrorFuncProps = { response?: ErrorResponse, error?: Error }
|
|
||||||
type onErrorFunc = (props: ErrorFuncProps) => void
|
|
||||||
|
|
||||||
type GameProps = {
|
|
||||||
updateGameState: (payload: GamePayload) => { payload: GamePayload, type: "game/updateGameState" }
|
|
||||||
auth: AuthState
|
|
||||||
onPostSuccess?: onPostSuccessFunc
|
|
||||||
onError?: onErrorFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useGameStartMutation = ({ auth, updateGameState, onPostSuccess, onError }: GameProps) => {
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
return fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/game/start/`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Bearer ${auth.token}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
}).then(resp => resp.json())
|
|
||||||
},
|
|
||||||
onSuccess: async (data) => {
|
|
||||||
if (data.error) {
|
|
||||||
if (onError)
|
|
||||||
onError({ response: data })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
updateGameState(data)
|
|
||||||
if (onPostSuccess)
|
|
||||||
onPostSuccess()
|
|
||||||
},
|
|
||||||
onError: async (error: Error) => {
|
|
||||||
if (onError)
|
|
||||||
onError({ error: error })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useGameStopMutation = ({ auth, updateGameState, onPostSuccess, onError }: GameProps) => {
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
return fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/game/stop/`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Bearer ${auth.token}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
}).then(resp => resp.json())
|
|
||||||
},
|
|
||||||
onSuccess: async (data) => {
|
|
||||||
if (data.error) {
|
|
||||||
if (onError)
|
|
||||||
onError({ response: data })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
updateGameState(data)
|
|
||||||
if (onPostSuccess)
|
|
||||||
onPostSuccess()
|
|
||||||
},
|
|
||||||
onError: async (error: Error) => {
|
|
||||||
if (onError)
|
|
||||||
onError({ error: error })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useGameSwitchPlayerMutation = ({ auth, updateGameState, onPostSuccess, onError }: GameProps) => {
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
return fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/game/switch-running-player/`, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Bearer ${auth.token}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
}).then(resp => resp.json())
|
|
||||||
},
|
|
||||||
onSuccess: async (data) => {
|
|
||||||
if (data.error) {
|
|
||||||
if (onError)
|
|
||||||
onError({ response: data })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
updateGameState(data)
|
|
||||||
if (onPostSuccess)
|
|
||||||
onPostSuccess()
|
|
||||||
},
|
|
||||||
onError: async (error: Error) => {
|
|
||||||
if (onError)
|
|
||||||
onError({ error: error })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useGameRepairMutation = ({ auth, onPostSuccess, onError }: GameProps) => {
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
return fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/game/repair/`, {
|
|
||||||
method: "PUT",
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Bearer ${auth.token}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
}).then(resp => resp.json())
|
|
||||||
},
|
|
||||||
onSuccess: async (data) => {
|
|
||||||
if (data.error) {
|
|
||||||
if (onError)
|
|
||||||
onError({ response: data })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (onPostSuccess)
|
|
||||||
onPostSuccess()
|
|
||||||
},
|
|
||||||
onError: async (error: Error) => {
|
|
||||||
if (onError)
|
|
||||||
onError({ error: error })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useGameResetMutation = ({ auth, updateGameState, onPostSuccess, onError }: GameProps) => {
|
|
||||||
return useMutation({
|
|
||||||
mutationFn: async () => {
|
|
||||||
return fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/game/reset/`, {
|
|
||||||
method: "DELETE",
|
|
||||||
headers: {
|
|
||||||
"Authorization": `Bearer ${auth.token}`,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
}).then(resp => resp.json())
|
|
||||||
},
|
|
||||||
onSuccess: async (data) => {
|
|
||||||
if (data.error) {
|
|
||||||
if (onError)
|
|
||||||
onError({ response: data })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
updateGameState(data)
|
|
||||||
if (onPostSuccess)
|
|
||||||
onPostSuccess()
|
|
||||||
},
|
|
||||||
onError: async (error: Error) => {
|
|
||||||
if (onError)
|
|
||||||
onError({ error: error })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -8,6 +8,11 @@ type ErrorResponse = {
|
|||||||
statusCode: number
|
statusCode: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LoginForm = {
|
||||||
|
name: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
type onPostSuccessFunc = (data: any, variables: LocationObject, context: unknown) => void
|
type onPostSuccessFunc = (data: any, variables: LocationObject, context: unknown) => void
|
||||||
type ErrorFuncProps = { response?: ErrorResponse, error?: Error }
|
type ErrorFuncProps = { response?: ErrorResponse, error?: Error }
|
||||||
type onErrorFunc = (props: ErrorFuncProps) => void
|
type onErrorFunc = (props: ErrorFuncProps) => void
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useAppDispatch, useAppSelector } from "./useStore"
|
import { useAppDispatch, useAppSelector } from "./useStore"
|
||||||
import { GamePayload, setPlayerId, updateGameState, updateMoney } from "@/utils/features/game/gameSlice"
|
import { setPlayerId, updateMoney } from "@/utils/features/game/gameSlice"
|
||||||
|
|
||||||
export const useGame = () => useAppSelector((state) => state.game)
|
export const useGame = () => useAppSelector((state) => state.game)
|
||||||
export const useSetPlayerId = () => {
|
export const useSetPlayerId = () => {
|
||||||
@ -10,7 +10,3 @@ export const useUpdateMoney = () => {
|
|||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
return (money: number) => dispatch(updateMoney(money))
|
return (money: number) => dispatch(updateMoney(money))
|
||||||
}
|
}
|
||||||
export const useUpdateGameState = () => {
|
|
||||||
const dispatch = useAppDispatch()
|
|
||||||
return (game: GamePayload) => dispatch(updateGameState(game))
|
|
||||||
}
|
|
||||||
|
@ -7,10 +7,10 @@ export interface ChallengeAction {
|
|||||||
description: string,
|
description: string,
|
||||||
reward: number,
|
reward: number,
|
||||||
success: boolean,
|
success: boolean,
|
||||||
start: number, // date
|
start: Date,
|
||||||
end: number | null, // date
|
end: Date | null,
|
||||||
penaltyStart: number | null, // date
|
penaltyStart: Date | null,
|
||||||
penaltyEnd: number | null, // date
|
penaltyEnd: Date | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionsState {
|
export interface ActionsState {
|
||||||
|
@ -1,28 +1,13 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
|
|
||||||
export interface RunPayload {
|
|
||||||
id: number
|
|
||||||
gameId: number
|
|
||||||
runnerId: number
|
|
||||||
start: string
|
|
||||||
end: string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GamePayload {
|
|
||||||
id: number
|
|
||||||
started: boolean
|
|
||||||
currentRunId: number | null
|
|
||||||
currentRun: RunPayload | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GameState {
|
export interface GameState {
|
||||||
playerId: number | null
|
playerId: number | null
|
||||||
gameStarted: boolean
|
gameStarted: boolean
|
||||||
money: number
|
money: number
|
||||||
currentRunner: boolean
|
currentRunner: boolean
|
||||||
chaseFreeTime: number | null // date
|
chaseFreeTime: Date | null
|
||||||
penaltyStart: number | null // date
|
penaltyStart: Date | null
|
||||||
penaltyEnd: number | null // date
|
penaltyEnd: Date | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: GameState = {
|
const initialState: GameState = {
|
||||||
@ -45,18 +30,9 @@ export const gameSlice = createSlice({
|
|||||||
updateMoney: (state, action: PayloadAction<number>) => {
|
updateMoney: (state, action: PayloadAction<number>) => {
|
||||||
state.money = action.payload
|
state.money = action.payload
|
||||||
},
|
},
|
||||||
updateGameState: (state, action: PayloadAction<GamePayload>) => {
|
|
||||||
const game: GamePayload = action.payload
|
|
||||||
state.gameStarted = game.started
|
|
||||||
state.currentRunner = state.playerId === game.currentRun?.runnerId
|
|
||||||
if (state.currentRunner)
|
|
||||||
state.chaseFreeTime = null
|
|
||||||
else if (game.currentRun)
|
|
||||||
state.chaseFreeTime = new Date(game.currentRun?.start).getTime() + 45 * 60 * 1000
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const { setPlayerId, updateMoney, updateGameState } = gameSlice.actions
|
export const { setPlayerId, updateMoney } = gameSlice.actions
|
||||||
|
|
||||||
export default gameSlice.reducer
|
export default gameSlice.reducer
|
||||||
|
@ -83,8 +83,8 @@ export interface TrainTrip {
|
|||||||
distance: number,
|
distance: number,
|
||||||
from: string,
|
from: string,
|
||||||
to: string,
|
to: string,
|
||||||
departureTime: number,
|
departureTime: Date,
|
||||||
arrivalTime: number,
|
arrivalTime: Date,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TrainsState {
|
export interface TrainsState {
|
||||||
|
@ -35,7 +35,6 @@ export async function startGeolocationService(): Promise<void | (() => void)> {
|
|||||||
accuracy: Location.Accuracy.BestForNavigation,
|
accuracy: Location.Accuracy.BestForNavigation,
|
||||||
activityType: Location.ActivityType.OtherNavigation,
|
activityType: Location.ActivityType.OtherNavigation,
|
||||||
deferredUpdatesInterval: 100,
|
deferredUpdatesInterval: 100,
|
||||||
timeInterval: 100,
|
|
||||||
foregroundService: {
|
foregroundService: {
|
||||||
killServiceOnDestroy: false,
|
killServiceOnDestroy: false,
|
||||||
notificationBody: "Géolocalisation activée pour « Traintrape-moi »",
|
notificationBody: "Géolocalisation activée pour « Traintrape-moi »",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user