import ChallengeCard from "@/components/ChallengeCard" 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 React, { ReactNode, useMemo, useState } from "react" import { FlatList, StyleSheet } from "react-native" 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("") const [editChallengeDescription, setEditChallengeDescription] = useState("") const [editChallengeReward, setEditChallengeReward] = useState(0) 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) const [error, setError] = useState([200, ""]) const addChallengeMutation = useAddChallengeMutation({ auth, onPostSuccess: () => { setSuccessMessage("Le défi a bien été ajouté !") setSuccessSnackbarVisible(true) setEditChallengeVisible(false) queryClient.invalidateQueries({ predicate: (query) => query.queryKey[0] === 'get-challenges' }) }, onError: ({ response, error }) => { setErrorVisible(true) setEditChallengeVisible(false) if (response) setError([response.statusCode, response.message]) else if (error) setError([400, error.message]) }, }) const editChallengeMutation = useEditChallengeMutation({ auth, onPostSuccess: () => { setSuccessMessage("Le défi a bien été modifié !") setSuccessSnackbarVisible(true) setEditChallengeVisible(false) setDisplayedChallenge(null) queryClient.invalidateQueries({ predicate: (query) => query.queryKey[0] === 'get-challenges' }) }, onError: ({ response, error }) => { setErrorVisible(true) setEditChallengeVisible(false) setDisplayedChallenge(null) if (response) setError([response.statusCode, response.message]) else if (error) setError([400, error.message]) }, }) const deleteChallengeMutation = useDeleteChallengeMutation({ auth, onPostSuccess: () => { setSuccessMessage("Le défi a bien été supprimé !") setDisplayedChallenge(null) queryClient.invalidateQueries({ predicate: (query) => query.queryKey[0] === 'get-challenges' }) }, onError: ({ response, error }) => { setErrorVisible(true) setDisplayedChallenge(null) if (response) setError([response.statusCode, response.message]) else if (error) 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) { editChallengeMutation.mutate({ id: editChallengeId, title: editChallengeTitle, description: editChallengeDescription, reward: editChallengeReward, }) } else { addChallengeMutation.mutate({ title: editChallengeTitle, description: editChallengeDescription, reward: editChallengeReward, }) } } function sendDeleteChallenge() { displayedChallenge && deleteChallengeMutation.mutate(displayedChallenge) } function sendAttachNewChallenge() { if (!challengeToAttach || !currentChallengeAction) return attachNewChallengeMutation.mutate({ challengeActionId: currentChallengeAction.id, newChallengeId: challengeToAttach.id }) } return ( router.canGoBack() ? router.back() : router.navigate('/(tabs)/challenges')} /> `challenge-list-item-${challenge.id}`} ItemSeparatorComponent={() => } renderItem={(item) => setDisplayedChallenge(item.item)} onLongPress={!currentChallengeAction ? undefined : () => setChallengeToAttach(item.item)} />} /> setSuccessSnackbarVisible(false)} onIconPress={() => setSuccessSnackbarVisible(false)}> {successMessage} setErrorVisible(false)} onIconPress={() => setErrorVisible(false)}> Erreur {error[0]} : {error[1]} { if (editChallengeId) { setEditChallengeTitle("") setEditChallengeDescription("") setEditChallengeReward(0) setEditChallengeId(null) } setEditChallengeVisible(true) }} /> setDisplayedChallenge(null)} contentContainerStyle={{ flex: 1, marginHorizontal: 20, marginVertical: 100 }}> { setEditChallengeTitle(displayedChallenge?.title ?? "") setEditChallengeDescription(displayedChallenge?.description ?? "") setEditChallengeReward(displayedChallenge?.reward ?? 0) setEditChallengeId(displayedChallenge?.id ?? null) setEditChallengeVisible(true) }} onDelete={() => setConfirmDeleteVisible(true)} style={{ flexGrow: 1 }} /> setEditChallengeVisible(false)}> {editChallengeId ? "Modification d'un défi" : "Ajout d'un défi"} setEditChallengeReward(+text)} error={!editChallengeReward} onEndEditing={() => !addChallengeMutation.isPending && editChallengeMutation.isPending && sendEditChallenge()} /> setConfirmDeleteVisible(false)}> Êtes-vous sûre ? Voulez-vous vraiment supprimer le défi « {displayedChallenge?.title} » ? Cette opération est irréversible ! setChallengeToAttach(null)}> Traiter ce défi Voulez-vous vraiment remplacer votre défi actuel par le défi « {challengeToAttach?.title} » ? ) } 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 ( icon} onPress={onPress} onLongPress={attachedAction ? undefined : onLongPress} /> ) } const styles = StyleSheet.create({ addButton: { position: 'absolute', right: 25, bottom: 25, } })