From 0f16edd8cc4553550c185f87f21f8bcc36649e71 Mon Sep 17 00:00:00 2001 From: Emmy D'Anello Date: Sat, 14 Dec 2024 17:18:41 +0100 Subject: [PATCH] =?UTF-8?q?Ajout=20possibilit=C3=A9=20modifier=20son=20d?= =?UTF-8?q?=C3=A9fi=20en=20cours?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/app/(tabs)/challenges.tsx | 9 +- client/app/(tabs)/settings.tsx | 1 - client/app/challenges-list.tsx | 85 +++++++++++++++++-- .../hooks/mutations/useChallengeMutation.ts | 30 +++++++ .../features/challenges/challengesSlice.ts | 2 +- 5 files changed, 114 insertions(+), 13 deletions(-) diff --git a/client/app/(tabs)/challenges.tsx b/client/app/(tabs)/challenges.tsx index 543fad9..bcc0fa3 100644 --- a/client/app/(tabs)/challenges.tsx +++ b/client/app/(tabs)/challenges.tsx @@ -5,7 +5,7 @@ import { useAuth } from '@/hooks/useAuth' import { useChallengeActions } from '@/hooks/useChallengeActions' import { useChallenges } from '@/hooks/useChallenges' import { useGame } from '@/hooks/useGame' -import { FontAwesome6 } from '@expo/vector-icons' +import { FontAwesome6, MaterialCommunityIcons } from '@expo/vector-icons' import { useQueryClient } from '@tanstack/react-query' import { useRouter } from 'expo-router' import { useEffect, useMemo, useState } from 'react' @@ -91,10 +91,11 @@ function ChallengeScreenBody() { style={{ flex: 1, margin: 20 }} />} {!loading && !game.penaltyEnd && !currentChallenge && game.currentRunner && <> - Aucun défi n'est en cours. + icon='vanish'> + Aucun défi n'est en cours. Veuillez tirer un défi en cliquant sur le bouton central. + Pour rappel, il faut être hors d'un train pour tirer un défi. { setSuccessVisible(true) setSuccessMessage("Réparation du jeu effectuée avec succès") diff --git a/client/app/challenges-list.tsx b/client/app/challenges-list.tsx index e4c96cd..bef8b36 100644 --- a/client/app/challenges-list.tsx +++ b/client/app/challenges-list.tsx @@ -1,20 +1,29 @@ import ChallengeCard from "@/components/ChallengeCard" -import { useAddChallengeMutation, useDeleteChallengeMutation, useEditChallengeMutation } from "@/hooks/mutations/useChallengeMutation" +import { useAddChallengeMutation, useAttachNewChallenge, useDeleteChallengeMutation, useEditChallengeMutation } from "@/hooks/mutations/useChallengeMutation" import { useAuth } from "@/hooks/useAuth" +import { useChallengeActions } from "@/hooks/useChallengeActions" import { useChallenges } from "@/hooks/useChallenges" +import { useGame } from "@/hooks/useGame" import { Challenge } from "@/utils/features/challenges/challengesSlice" import { FontAwesome6 } from "@expo/vector-icons" import { useQueryClient } from "@tanstack/react-query" import { useRouter } from "expo-router" -import { useState } from "react" +import React, { ReactNode, useMemo, useState } from "react" import { FlatList, StyleSheet } from "react-native" -import { Appbar, Button, Dialog, Divider, FAB, List, MD3Colors, Modal, Portal, Snackbar, Surface, Text, TextInput } from "react-native-paper" +import { ActivityIndicator, Appbar, Button, Dialog, Divider, FAB, List, MD3Colors, Modal, Portal, Snackbar, Surface, Text, TextInput, Tooltip } from "react-native-paper" export default function ChallengesList() { const router = useRouter() const queryClient = useQueryClient() const auth = useAuth() + const game = useGame() const challenges = useChallenges() + const challengeActions = useChallengeActions() + const currentChallengeAction = useMemo(() => { + if (!game.activeChallengeId) + return null + return challengeActions.find((action) => action.id === game.activeChallengeId) + }, [game, challengeActions]) const [editChallengeVisible, setEditChallengeVisible] = useState(false) const [editChallengeTitle, setEditChallengeTitle] = useState("") @@ -23,6 +32,8 @@ export default function ChallengesList() { const [editChallengeId, setEditChallengeId] = useState(null) const [displayedChallenge, setDisplayedChallenge] = useState(null) const [confirmDeletedVisible, setConfirmDeleteVisible] = useState(false) + const [challengeToAttach, setChallengeToAttach] = useState(null) + const [successSnackbarVisible, setSuccessSnackbarVisible] = useState(false) const [successMessage, setSuccessMessage] = useState("") const [errorVisible, setErrorVisible] = useState(false) @@ -80,6 +91,22 @@ export default function ChallengesList() { setError([400, error.message]) }, }) + const attachNewChallengeMutation = useAttachNewChallenge({ + auth, + onPostSuccess: () => { + setChallengeToAttach(null) + setSuccessMessage("Le défi en cours a bien été modifié !") + queryClient.invalidateQueries({ predicate: (query) => query.queryKey[0] === 'get-challenges' }) + }, + onError: ({ response, error }) => { + setChallengeToAttach(null) + setErrorVisible(true) + if (response) + setError([response.statusCode, response.message]) + else if (error) + setError([400, error.message]) + }, + }) function sendEditChallenge() { if (editChallengeId) { @@ -103,17 +130,26 @@ export default function ChallengesList() { displayedChallenge && deleteChallengeMutation.mutate(displayedChallenge) } + function sendAttachNewChallenge() { + if (!challengeToAttach || !currentChallengeAction) return + attachNewChallengeMutation.mutate({ challengeActionId: currentChallengeAction.id, newChallengeId: challengeToAttach.id }) + } + return ( - {router.canGoBack() ? router.back()} /> : undefined} + router.canGoBack() ? router.back() : router.navigate('/(tabs)/challenges')} /> `challenge-list-item-${challenge.id}`} ItemSeparatorComponent={() => } - renderItem={(item) => setDisplayedChallenge(item.item)} />} /> + renderItem={(item) => + setDisplayedChallenge(item.item)} + onLongPress={!currentChallengeAction ? undefined : () => setChallengeToAttach(item.item)} />} /> Confirmer + setChallengeToAttach(null)}> + Traiter ce défi + + + Voulez-vous vraiment remplacer votre défi actuel par le défi « {challengeToAttach?.title} » ? + + + + + + + ) } -function ChallengeListItem({ challenge, onPress }: { challenge: Challenge, onPress?: () => void }) { +type ChallengeListItemProps = { + challenge: Challenge, + activeRunner: boolean, + onPress?: () => void, + onLongPress?: () => void, +} + +function ChallengeListItem({ challenge, activeRunner, onPress, onLongPress }: ChallengeListItemProps) { + const challengeActions = useChallengeActions() + const attachedAction = challengeActions.find(challengeAction => challengeAction.challengeId === challenge.id) const description = Récompense : {challenge.reward} + const icon: ReactNode = useMemo(() => { + if (!activeRunner) + return undefined + else if (!attachedAction) + return + else if (!attachedAction.end) + return + else if (attachedAction.success) + return + else + return + }, [activeRunner, attachedAction]) return ( + right={() => icon} + onPress={onPress} + onLongPress={attachedAction ? undefined : onLongPress} /> ) } diff --git a/client/hooks/mutations/useChallengeMutation.ts b/client/hooks/mutations/useChallengeMutation.ts index baa6cb8..a930ec0 100644 --- a/client/hooks/mutations/useChallengeMutation.ts +++ b/client/hooks/mutations/useChallengeMutation.ts @@ -81,6 +81,36 @@ export const useEndChallenge = ({ auth, onPostSuccess, onError }: ChallengeActio }) } +export const useAttachNewChallenge = ({ auth, onPostSuccess, onError }: ChallengeActionProps) => { + return useMutation({ + mutationFn: async ({ challengeActionId, newChallengeId }: { challengeActionId: number, newChallengeId: number }) => { + return fetch(`${process.env.EXPO_PUBLIC_TRAINTRAPE_MOI_SERVER}/challenge-actions/${challengeActionId}/`, { + method: "PATCH", + headers: { + "Authorization": `Bearer ${auth.token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + challengeId: newChallengeId, + }) + }).then(resp => resp.json()) + }, + onSuccess: async (data) => { + if (data.statusCode) { + if (onError) + onError({ response: data }) + return + } + if (onPostSuccess) + onPostSuccess() + }, + onError: async (error: Error) => { + if (onError) + onError({ error: error }) + } + }) +} + export const useDeleteChallengeActionMutation = ({ auth, onPostSuccess, onError }: ChallengeActionProps) => { return useMutation({ mutationFn: async (challengeActionId: number) => { diff --git a/client/utils/features/challenges/challengesSlice.ts b/client/utils/features/challenges/challengesSlice.ts index 06e91a8..23f80b7 100644 --- a/client/utils/features/challenges/challengesSlice.ts +++ b/client/utils/features/challenges/challengesSlice.ts @@ -37,7 +37,7 @@ export const challengesSlice = createSlice({ reward: dlChallenge.reward, }) } - state.challenges.sort((c1, c2) => c2.id - c1.id) + state.challenges.sort((c1, c2) => c1.title.localeCompare(c2.title)) }, }, })