diff --git a/client/app/(tabs)/challenges.tsx b/client/app/(tabs)/challenges.tsx index f6db360..909b5d3 100644 --- a/client/app/(tabs)/challenges.tsx +++ b/client/app/(tabs)/challenges.tsx @@ -30,12 +30,12 @@ function ChallengeScreenBody() { const currentChallengeAction = useMemo(() => { if (!game.activeChallengeId) return null - return challengeActions.challengeActions.find((action) => action.id === game.activeChallengeId) + return challengeActions.find((action) => action.id === game.activeChallengeId) }, [game, challengeActions]) const currentChallenge = useMemo(() => { if (!currentChallengeAction) return null - return challenges.challenges.find((challenge) => challenge.id === currentChallengeAction.challengeId) + return challenges.find((challenge) => challenge.id === currentChallengeAction.challengeId) }, [currentChallengeAction, challenges]) const [loading, setLoading] = useState(false) const [successSnackbarVisible, setSuccessSnackbarVisible] = useState(false) diff --git a/client/app/(tabs)/history.tsx b/client/app/(tabs)/history.tsx index ac174f6..639863d 100644 --- a/client/app/(tabs)/history.tsx +++ b/client/app/(tabs)/history.tsx @@ -1,12 +1,78 @@ +import { useChallengeActions } from '@/hooks/useChallengeActions' +import { useChallenges } from '@/hooks/useChallenges' 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() { const moneyUpdates = useMoneyUpdates() return ( - - Ici on aura la gestion de l'historique des trains empruntés et des challenges effectués + + `money-update-list-item-${moneyUpdate.id}`} + ItemSeparatorComponent={() => } + renderItem={(item) => } /> ) } + +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 + {verb} {moneyUpdate.amount} le {earnDate} à {earnTime} + + }, [moneyUpdate.amount]) + + return ( + } + title={title} + description={description} + right={(props) => {}} />} /> + ) +} diff --git a/client/app/(tabs)/train.tsx b/client/app/(tabs)/train.tsx index 9371871..806f154 100644 --- a/client/app/(tabs)/train.tsx +++ b/client/app/(tabs)/train.tsx @@ -25,7 +25,7 @@ export default function TrainScreen() { train.id} ItemSeparatorComponent={() => } renderItem={(item) => } /> diff --git a/client/app/_layout.tsx b/client/app/_layout.tsx index d3e36a2..d6a6860 100644 --- a/client/app/_layout.tsx +++ b/client/app/_layout.tsx @@ -15,7 +15,6 @@ import { useStartBackgroundFetchServiceEffect } from '@/utils/background' import LoginProvider from '@/components/LoginProvider' import GeolocationProvider from '@/components/GeolocationProvider' import GameProvider from '@/components/GameProvider' -import { FontAwesome6 } from '@expo/vector-icons' const queryClient = new QueryClient({ defaultOptions: { @@ -49,10 +48,7 @@ export default function RootLayout() { - }}> + theme={colorScheme === 'dark' ? MD3DarkTheme : MD3LightTheme} > diff --git a/client/components/GameProvider.tsx b/client/components/GameProvider.tsx index 15de167..dcb5938 100644 --- a/client/components/GameProvider.tsx +++ b/client/components/GameProvider.tsx @@ -96,7 +96,7 @@ export default function GameProvider({ children }: { children: ReactNode }) { useEffect(() => { const now = new Date().getTime() - const activeChallenge: ChallengeAction | undefined = challengeActions.challengeActions + const activeChallenge: ChallengeAction | undefined = challengeActions .find(challengeAction => challengeAction.penaltyStart && challengeAction.penaltyEnd && challengeAction.penaltyStart <= now && now <= challengeAction.penaltyEnd) if (!activeChallenge || !game.currentRunner) diff --git a/client/components/GeolocationProvider.tsx b/client/components/GeolocationProvider.tsx index fe19558..6e42c5c 100644 --- a/client/components/GeolocationProvider.tsx +++ b/client/components/GeolocationProvider.tsx @@ -45,7 +45,7 @@ export default function GeolocationProvider({ children }: { children: ReactNode useEffect(() => { if (lastLocationsQuery.isSuccess && lastLocationsQuery.data) setLastPlayerLocations(lastLocationsQuery.data) - }, [lastLocationsQuery.status, lastLocationsQuery.dataUpdatedAt]) + }, [lastLocationsQuery.status, lastLocationsQuery.dataUpdatedAt, auth]) return <> {children} diff --git a/client/hooks/useChallengeActions.ts b/client/hooks/useChallengeActions.ts index 7c4e821..084b200 100644 --- a/client/hooks/useChallengeActions.ts +++ b/client/hooks/useChallengeActions.ts @@ -1,7 +1,7 @@ import { ChallengeActionsPayload, downloadChallengeActions } from "@/utils/features/challengeActions/challengeActionsSlice" import { useAppDispatch, useAppSelector } from "./useStore" -export const useChallengeActions = () => useAppSelector((state) => state.challengeActions) +export const useChallengeActions = () => useAppSelector((state) => state.challengeActions.challengeActions) export const useDownloadChallengeActions = () => { const dispath = useAppDispatch() return (challengesData: ChallengeActionsPayload) => dispath(downloadChallengeActions(challengesData)) diff --git a/client/hooks/useChallenges.ts b/client/hooks/useChallenges.ts index 97ec33d..7b45a38 100644 --- a/client/hooks/useChallenges.ts +++ b/client/hooks/useChallenges.ts @@ -1,7 +1,7 @@ import { ChallengesPayload, downloadChallenges } from "@/utils/features/challenges/challengesSlice" import { useAppDispatch, useAppSelector } from "./useStore" -export const useChallenges = () => useAppSelector((state) => state.challenges) +export const useChallenges = () => useAppSelector((state) => state.challenges.challenges) export const useDownloadChallenges = () => { const dispath = useAppDispatch() return (challengesData: ChallengesPayload) => dispath(downloadChallenges(challengesData)) diff --git a/client/hooks/useTrain.ts b/client/hooks/useTrain.ts index cf833ef..9df4b49 100644 --- a/client/hooks/useTrain.ts +++ b/client/hooks/useTrain.ts @@ -1,7 +1,7 @@ import { downloadTrains, TrainsPayload } from "@/utils/features/train/trainSlice" import { useAppDispatch, useAppSelector } from "./useStore" -export const useTrain = () => useAppSelector((state) => state.train) +export const useTrain = () => useAppSelector((state) => state.train.trains) export const useDownloadTrains = () => { const dispath = useAppDispatch() return (trainsData: TrainsPayload) => dispath(downloadTrains(trainsData)) diff --git a/client/utils/features/moneyUpdates/moneyUpdatesSlice.ts b/client/utils/features/moneyUpdates/moneyUpdatesSlice.ts index 8fe3497..b7b89d2 100644 --- a/client/utils/features/moneyUpdates/moneyUpdatesSlice.ts +++ b/client/utils/features/moneyUpdates/moneyUpdatesSlice.ts @@ -4,11 +4,12 @@ import { PaginationMeta } from '../common' export interface MoneyUpdate { id: number playerId: number + amount: number reason: 'START' | 'NEW_RUN' | 'BUY_TRAIN' | 'WIN_CHALLENGE' timestamp: number runId: number | null actionId: number | null - tripId: number | null + tripId: string | null } export interface MoneyUpdatesState { @@ -19,8 +20,19 @@ const initialState: MoneyUpdatesState = { 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 { - data: MoneyUpdate[] + data: MoneyUpdatePayload[] meta: PaginationMeta } @@ -31,7 +43,16 @@ export const moneyUpdatesSlice = createSlice({ downloadMoneyUpdates(state, action: PayloadAction) { state.moneyUpdates = state.moneyUpdates.filter(moneyUpdate => action.payload.data.filter(dlMU => dlMU.id === moneyUpdate.id) === null) 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) },