Afifchage de l'historique des mouvements de point

This commit is contained in:
Emmy D'Anello 2024-12-14 00:27:30 +01:00
parent 02304527d3
commit 3d50cee9a9
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
10 changed files with 102 additions and 19 deletions

View File

@ -30,12 +30,12 @@ function ChallengeScreenBody() {
const currentChallengeAction = useMemo(() => { const currentChallengeAction = useMemo(() => {
if (!game.activeChallengeId) if (!game.activeChallengeId)
return null return null
return challengeActions.challengeActions.find((action) => action.id === game.activeChallengeId) return challengeActions.find((action) => action.id === game.activeChallengeId)
}, [game, challengeActions]) }, [game, challengeActions])
const currentChallenge = useMemo(() => { const currentChallenge = useMemo(() => {
if (!currentChallengeAction) if (!currentChallengeAction)
return null return null
return challenges.challenges.find((challenge) => challenge.id === currentChallengeAction.challengeId) return challenges.find((challenge) => challenge.id === currentChallengeAction.challengeId)
}, [currentChallengeAction, challenges]) }, [currentChallengeAction, challenges])
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [successSnackbarVisible, setSuccessSnackbarVisible] = useState(false) const [successSnackbarVisible, setSuccessSnackbarVisible] = useState(false)

View File

@ -1,12 +1,78 @@
import { useChallengeActions } from '@/hooks/useChallengeActions'
import { useChallenges } from '@/hooks/useChallenges'
import { useMoneyUpdates } from '@/hooks/useMoneyUpdates' import { useMoneyUpdates } from '@/hooks/useMoneyUpdates'
import { Surface, Text } from 'react-native-paper' import { useTrain } from '@/hooks/useTrain'
import { MoneyUpdate } from '@/utils/features/moneyUpdates/moneyUpdatesSlice'
import { FontAwesome6 } from '@expo/vector-icons'
import { useMemo } from 'react'
import { FlatList } from 'react-native'
import { Divider, FAB, List, Surface, Text } from 'react-native-paper'
export default function HistoryScreen() { export default function HistoryScreen() {
const moneyUpdates = useMoneyUpdates() const moneyUpdates = useMoneyUpdates()
return ( return (
<Surface> <Surface style={{ flex :1 }}>
<Text>Ici on aura la gestion de l'historique des trains empruntés et des challenges effectués</Text> <FlatList
data={moneyUpdates}
keyExtractor={(moneyUpdate) => `money-update-list-item-${moneyUpdate.id}`}
ItemSeparatorComponent={() => <Divider />}
renderItem={(item) => <MoneyUpdateListItem moneyUpdate={item.item} />} />
</Surface> </Surface>
) )
} }
function MoneyUpdateListItem({ moneyUpdate }: { moneyUpdate: MoneyUpdate }) {
const trains = useTrain()
const challengeActions = useChallengeActions()
const challenges = useChallenges()
const icon = useMemo(() => {
switch (moneyUpdate.reason) {
case 'START': return 'star'
case 'NEW_RUN': return 'run'
case 'BUY_TRAIN': return 'train'
case 'WIN_CHALLENGE': return 'cards'
}
}, [moneyUpdate.reason])
const title = useMemo(() => {
switch (moneyUpdate.reason) {
case 'START':
return "Début de la partie"
case 'NEW_RUN':
return "Nouvelle tentative"
case 'BUY_TRAIN':
const train = trains.find((train) => train.id === moneyUpdate.tripId)
if (!train) return "Train"
const depDateTime = new Date(train.departureTime)
const depTime = depDateTime.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })
const arrDateTime = new Date(train.arrivalTime)
const arrTime = arrDateTime.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })
return `${train.from} ${depTime} => ${train.to} ${arrTime}`
case 'WIN_CHALLENGE':
const challengeAction = challengeActions.find((challengeAction) => challengeAction.id === moneyUpdate.actionId)
if (!challengeAction) return "Défi"
const challenge = challenges.find((challenge) => challenge.id === challengeAction.challengeId)
if (!challenge) return "Défi"
return challenge.title
}
}, [moneyUpdate.reason, moneyUpdate.tripId, moneyUpdate.actionId])
const description = useMemo(() => {
const earnDate = new Date(moneyUpdate.timestamp).toLocaleDateString(undefined, { day: '2-digit', month: '2-digit' })
const earnTime = new Date(moneyUpdate.timestamp).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })
const verb = moneyUpdate.amount > 0 ? "Gagné" : "Dépensé"
return <Text>
{verb} {moneyUpdate.amount} <FontAwesome6 name='coins' /> le {earnDate} à {earnTime}
</Text>
}, [moneyUpdate.amount])
return (
<List.Item
left={(props) => <List.Icon {...props} icon={icon} />}
title={title}
description={description}
right={(props) => <FAB mode='elevated' icon='delete' size='small' {...props} onPress={() => {}} />} />
)
}

View File

@ -25,7 +25,7 @@ export default function TrainScreen() {
<Surface style={{ flex: 1 }}> <Surface style={{ flex: 1 }}>
<PenaltyBanner /> <PenaltyBanner />
<FlatList <FlatList
data={trains.trains} data={trains}
keyExtractor={(train) => train.id} keyExtractor={(train) => train.id}
ItemSeparatorComponent={() => <Divider />} ItemSeparatorComponent={() => <Divider />}
renderItem={(item) => <TrainListItem train={item.item} />} /> renderItem={(item) => <TrainListItem train={item.item} />} />

View File

@ -15,7 +15,6 @@ 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' import GameProvider from '@/components/GameProvider'
import { FontAwesome6 } from '@expo/vector-icons'
const queryClient = new QueryClient({ const queryClient = new QueryClient({
defaultOptions: { defaultOptions: {
@ -49,10 +48,7 @@ export default function RootLayout() {
<GeolocationProvider> <GeolocationProvider>
<GameProvider> <GameProvider>
<PaperProvider <PaperProvider
theme={colorScheme === 'dark' ? MD3DarkTheme : MD3LightTheme} theme={colorScheme === 'dark' ? MD3DarkTheme : MD3LightTheme} >
settings={{
// icon: (props) => <FontAwesome6 {...props} />
}}>
<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 }} />

View File

@ -96,7 +96,7 @@ export default function GameProvider({ children }: { children: ReactNode }) {
useEffect(() => { useEffect(() => {
const now = new Date().getTime() const now = new Date().getTime()
const activeChallenge: ChallengeAction | undefined = challengeActions.challengeActions const activeChallenge: ChallengeAction | undefined = challengeActions
.find(challengeAction => challengeAction.penaltyStart && challengeAction.penaltyEnd .find(challengeAction => challengeAction.penaltyStart && challengeAction.penaltyEnd
&& challengeAction.penaltyStart <= now && now <= challengeAction.penaltyEnd) && challengeAction.penaltyStart <= now && now <= challengeAction.penaltyEnd)
if (!activeChallenge || !game.currentRunner) if (!activeChallenge || !game.currentRunner)

View File

@ -45,7 +45,7 @@ export default function GeolocationProvider({ children }: { children: ReactNode
useEffect(() => { useEffect(() => {
if (lastLocationsQuery.isSuccess && lastLocationsQuery.data) if (lastLocationsQuery.isSuccess && lastLocationsQuery.data)
setLastPlayerLocations(lastLocationsQuery.data) setLastPlayerLocations(lastLocationsQuery.data)
}, [lastLocationsQuery.status, lastLocationsQuery.dataUpdatedAt]) }, [lastLocationsQuery.status, lastLocationsQuery.dataUpdatedAt, auth])
return <> return <>
{children} {children}

View File

@ -1,7 +1,7 @@
import { ChallengeActionsPayload, downloadChallengeActions } from "@/utils/features/challengeActions/challengeActionsSlice" import { ChallengeActionsPayload, downloadChallengeActions } from "@/utils/features/challengeActions/challengeActionsSlice"
import { useAppDispatch, useAppSelector } from "./useStore" import { useAppDispatch, useAppSelector } from "./useStore"
export const useChallengeActions = () => useAppSelector((state) => state.challengeActions) export const useChallengeActions = () => useAppSelector((state) => state.challengeActions.challengeActions)
export const useDownloadChallengeActions = () => { export const useDownloadChallengeActions = () => {
const dispath = useAppDispatch() const dispath = useAppDispatch()
return (challengesData: ChallengeActionsPayload) => dispath(downloadChallengeActions(challengesData)) return (challengesData: ChallengeActionsPayload) => dispath(downloadChallengeActions(challengesData))

View File

@ -1,7 +1,7 @@
import { ChallengesPayload, downloadChallenges } from "@/utils/features/challenges/challengesSlice" import { ChallengesPayload, downloadChallenges } from "@/utils/features/challenges/challengesSlice"
import { useAppDispatch, useAppSelector } from "./useStore" import { useAppDispatch, useAppSelector } from "./useStore"
export const useChallenges = () => useAppSelector((state) => state.challenges) export const useChallenges = () => useAppSelector((state) => state.challenges.challenges)
export const useDownloadChallenges = () => { export const useDownloadChallenges = () => {
const dispath = useAppDispatch() const dispath = useAppDispatch()
return (challengesData: ChallengesPayload) => dispath(downloadChallenges(challengesData)) return (challengesData: ChallengesPayload) => dispath(downloadChallenges(challengesData))

View File

@ -1,7 +1,7 @@
import { downloadTrains, TrainsPayload } from "@/utils/features/train/trainSlice" import { downloadTrains, TrainsPayload } from "@/utils/features/train/trainSlice"
import { useAppDispatch, useAppSelector } from "./useStore" import { useAppDispatch, useAppSelector } from "./useStore"
export const useTrain = () => useAppSelector((state) => state.train) export const useTrain = () => useAppSelector((state) => state.train.trains)
export const useDownloadTrains = () => { export const useDownloadTrains = () => {
const dispath = useAppDispatch() const dispath = useAppDispatch()
return (trainsData: TrainsPayload) => dispath(downloadTrains(trainsData)) return (trainsData: TrainsPayload) => dispath(downloadTrains(trainsData))

View File

@ -4,11 +4,12 @@ import { PaginationMeta } from '../common'
export interface MoneyUpdate { export interface MoneyUpdate {
id: number id: number
playerId: number playerId: number
amount: number
reason: 'START' | 'NEW_RUN' | 'BUY_TRAIN' | 'WIN_CHALLENGE' reason: 'START' | 'NEW_RUN' | 'BUY_TRAIN' | 'WIN_CHALLENGE'
timestamp: number timestamp: number
runId: number | null runId: number | null
actionId: number | null actionId: number | null
tripId: number | null tripId: string | null
} }
export interface MoneyUpdatesState { export interface MoneyUpdatesState {
@ -19,8 +20,19 @@ const initialState: MoneyUpdatesState = {
moneyUpdates: [] moneyUpdates: []
} }
export interface MoneyUpdatePayload {
id: number
playerId: number
amount: number
reason: 'START' | 'NEW_RUN' | 'BUY_TRAIN' | 'WIN_CHALLENGE'
timestamp: string
runId: number | null
actionId: number | null
tripId: string | null
}
export interface MoneyUpdatesPayload { export interface MoneyUpdatesPayload {
data: MoneyUpdate[] data: MoneyUpdatePayload[]
meta: PaginationMeta meta: PaginationMeta
} }
@ -31,7 +43,16 @@ export const moneyUpdatesSlice = createSlice({
downloadMoneyUpdates(state, action: PayloadAction<MoneyUpdatesPayload>) { downloadMoneyUpdates(state, action: PayloadAction<MoneyUpdatesPayload>) {
state.moneyUpdates = state.moneyUpdates.filter(moneyUpdate => action.payload.data.filter(dlMU => dlMU.id === moneyUpdate.id) === null) state.moneyUpdates = state.moneyUpdates.filter(moneyUpdate => action.payload.data.filter(dlMU => dlMU.id === moneyUpdate.id) === null)
for (const dlMU of action.payload.data) { for (const dlMU of action.payload.data) {
state.moneyUpdates.push(dlMU) state.moneyUpdates.push({
id: dlMU.id,
playerId: dlMU.playerId,
amount: dlMU.amount,
reason: dlMU.reason,
timestamp: new Date(dlMU.timestamp).getTime(),
runId: dlMU.runId,
actionId: dlMU.actionId,
tripId: dlMU.tripId,
})
} }
state.moneyUpdates.sort((mu1, mu2) => mu2.id - mu1.id) state.moneyUpdates.sort((mu1, mu2) => mu2.id - mu1.id)
}, },