diff --git a/actions/admin/challenges.ts b/actions/admin/challenges.ts deleted file mode 100644 index de5073e..0000000 --- a/actions/admin/challenges.ts +++ /dev/null @@ -1,152 +0,0 @@ -'use server' - -import { revalidatePath } from 'next/cache' -import { auth } from '@/lib/auth' -import { challengeService } from '@/services/challenges/challenge.service' -import { Role } from '@/prisma/generated/prisma/client' -import { - ValidationError, - NotFoundError, -} from '@/services/errors' - -async function checkAdminAccess() { - const session = await auth() - if (!session?.user || session.user.role !== Role.ADMIN) { - throw new Error('Accès refusé - Admin uniquement') - } - return session -} - -export async function validateChallenge( - challengeId: string, - winnerId: string, - adminComment?: string -) { - try { - const session = await checkAdminAccess() - - const challenge = await challengeService.validateChallenge( - challengeId, - session.user.id, - winnerId, - adminComment - ) - - revalidatePath('/admin') - revalidatePath('/challenges') - revalidatePath('/leaderboard') - - return { success: true, message: 'Défi validé avec succès', data: challenge } - } catch (error) { - console.error('Validate challenge error:', error) - - if (error instanceof ValidationError) { - return { success: false, error: error.message } - } - if (error instanceof NotFoundError) { - return { success: false, error: error.message } - } - if (error instanceof Error && error.message.includes('Accès refusé')) { - return { success: false, error: error.message } - } - - return { success: false, error: 'Une erreur est survenue lors de la validation du défi' } - } -} - -export async function rejectChallenge( - challengeId: string, - adminComment?: string -) { - try { - const session = await checkAdminAccess() - - const challenge = await challengeService.rejectChallenge( - challengeId, - session.user.id, - adminComment - ) - - revalidatePath('/admin') - revalidatePath('/challenges') - - return { success: true, message: 'Défi rejeté', data: challenge } - } catch (error) { - console.error('Reject challenge error:', error) - - if (error instanceof ValidationError) { - return { success: false, error: error.message } - } - if (error instanceof NotFoundError) { - return { success: false, error: error.message } - } - if (error instanceof Error && error.message.includes('Accès refusé')) { - return { success: false, error: error.message } - } - - return { success: false, error: 'Une erreur est survenue lors du rejet du défi' } - } -} - -export async function updateChallenge( - challengeId: string, - data: { - title?: string - description?: string - pointsReward?: number - } -) { - try { - const session = await checkAdminAccess() - - const challenge = await challengeService.updateChallenge(challengeId, { - title: data.title, - description: data.description, - pointsReward: data.pointsReward, - }) - - revalidatePath('/admin') - revalidatePath('/challenges') - - return { success: true, message: 'Défi mis à jour avec succès', data: challenge } - } catch (error) { - console.error('Update challenge error:', error) - - if (error instanceof ValidationError) { - return { success: false, error: error.message } - } - if (error instanceof NotFoundError) { - return { success: false, error: error.message } - } - if (error instanceof Error && error.message.includes('Accès refusé')) { - return { success: false, error: error.message } - } - - return { success: false, error: 'Une erreur est survenue lors de la mise à jour du défi' } - } -} - -export async function deleteChallenge(challengeId: string) { - try { - const session = await checkAdminAccess() - - await challengeService.deleteChallenge(challengeId) - - revalidatePath('/admin') - revalidatePath('/challenges') - - return { success: true, message: 'Défi supprimé avec succès' } - } catch (error) { - console.error('Delete challenge error:', error) - - if (error instanceof NotFoundError) { - return { success: false, error: error.message } - } - if (error instanceof Error && error.message.includes('Accès refusé')) { - return { success: false, error: error.message } - } - - return { success: false, error: 'Une erreur est survenue lors de la suppression du défi' } - } -} - diff --git a/actions/challenges/create.ts b/actions/challenges/create.ts deleted file mode 100644 index fc2b67a..0000000 --- a/actions/challenges/create.ts +++ /dev/null @@ -1,112 +0,0 @@ -'use server' - -import { revalidatePath } from 'next/cache' -import { auth } from '@/lib/auth' -import { challengeService } from '@/services/challenges/challenge.service' -import { - ValidationError, - NotFoundError, - ConflictError, -} from '@/services/errors' - -export async function createChallenge(data: { - challengedId: string - title: string - description: string - pointsReward?: number -}) { - try { - const session = await auth() - - if (!session?.user?.id) { - return { success: false, error: 'Vous devez être connecté pour créer un défi' } - } - - const challenge = await challengeService.createChallenge({ - challengerId: session.user.id, - challengedId: data.challengedId, - title: data.title, - description: data.description, - pointsReward: data.pointsReward || 100, - }) - - revalidatePath('/challenges') - revalidatePath('/profile') - - return { success: true, message: 'Défi créé avec succès', data: challenge } - } catch (error) { - console.error('Create challenge error:', error) - - if (error instanceof ValidationError || error instanceof ConflictError) { - return { success: false, error: error.message } - } - if (error instanceof NotFoundError) { - return { success: false, error: error.message } - } - - return { success: false, error: 'Une erreur est survenue lors de la création du défi' } - } -} - -export async function acceptChallenge(challengeId: string) { - try { - const session = await auth() - - if (!session?.user?.id) { - return { success: false, error: 'Vous devez être connecté pour accepter un défi' } - } - - const challenge = await challengeService.acceptChallenge( - challengeId, - session.user.id - ) - - revalidatePath('/challenges') - revalidatePath('/profile') - - return { success: true, message: 'Défi accepté', data: challenge } - } catch (error) { - console.error('Accept challenge error:', error) - - if (error instanceof ValidationError) { - return { success: false, error: error.message } - } - if (error instanceof NotFoundError) { - return { success: false, error: error.message } - } - - return { success: false, error: 'Une erreur est survenue lors de l\'acceptation du défi' } - } -} - -export async function cancelChallenge(challengeId: string) { - try { - const session = await auth() - - if (!session?.user?.id) { - return { success: false, error: 'Vous devez être connecté pour annuler un défi' } - } - - const challenge = await challengeService.cancelChallenge( - challengeId, - session.user.id - ) - - revalidatePath('/challenges') - revalidatePath('/profile') - - return { success: true, message: 'Défi annulé', data: challenge } - } catch (error) { - console.error('Cancel challenge error:', error) - - if (error instanceof ValidationError) { - return { success: false, error: error.message } - } - if (error instanceof NotFoundError) { - return { success: false, error: error.message } - } - - return { success: false, error: 'Une erreur est survenue lors de l\'annulation du défi' } - } -} - diff --git a/app/api/admin/challenges/route.ts b/app/api/admin/challenges/route.ts deleted file mode 100644 index e447672..0000000 --- a/app/api/admin/challenges/route.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { NextResponse } from "next/server"; -import { auth } from "@/lib/auth"; -import { challengeService } from "@/services/challenges/challenge.service"; -import { Role } from "@/prisma/generated/prisma/client"; - -export async function GET() { - try { - const session = await auth(); - - if (!session?.user || session.user.role !== Role.ADMIN) { - return NextResponse.json({ error: "Accès refusé" }, { status: 403 }); - } - - // Récupérer tous les défis (PENDING et ACCEPTED) pour l'admin - const allChallenges = await challengeService.getAllChallenges(); - // Filtrer pour ne garder que PENDING et ACCEPTED - const challenges = allChallenges.filter( - (c) => c.status === "PENDING" || c.status === "ACCEPTED" - ); - - return NextResponse.json(challenges); - } catch (error) { - console.error("Error fetching challenges:", error); - return NextResponse.json( - { error: "Erreur lors de la récupération des défis" }, - { status: 500 } - ); - } -} - diff --git a/app/api/challenges/route.ts b/app/api/challenges/route.ts deleted file mode 100644 index 4db2d1c..0000000 --- a/app/api/challenges/route.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { NextResponse } from "next/server"; -import { auth } from "@/lib/auth"; -import { challengeService } from "@/services/challenges/challenge.service"; - -export async function GET() { - try { - const session = await auth(); - - if (!session?.user?.id) { - return NextResponse.json({ error: "Vous devez être connecté" }, { status: 401 }); - } - - // Récupérer tous les défis de l'utilisateur - const challenges = await challengeService.getUserChallenges(session.user.id); - - return NextResponse.json(challenges); - } catch (error) { - console.error("Error fetching challenges:", error); - return NextResponse.json( - { error: "Erreur lors de la récupération des défis" }, - { status: 500 } - ); - } -} - diff --git a/app/api/users/route.ts b/app/api/users/route.ts deleted file mode 100644 index e3a924a..0000000 --- a/app/api/users/route.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { NextResponse } from "next/server"; -import { auth } from "@/lib/auth"; -import { userService } from "@/services/users/user.service"; - -export async function GET() { - try { - const session = await auth(); - - if (!session?.user?.id) { - return NextResponse.json({ error: "Vous devez être connecté" }, { status: 401 }); - } - - // Récupérer tous les utilisateurs (pour sélectionner qui défier) - const users = await userService.getAllUsers({ - orderBy: { - username: "asc", - }, - select: { - id: true, - username: true, - avatar: true, - score: true, - level: true, - }, - }); - - // Filtrer l'utilisateur actuel - const otherUsers = users.filter((user) => user.id !== session.user.id); - - return NextResponse.json(otherUsers); - } catch (error) { - console.error("Error fetching users:", error); - return NextResponse.json( - { error: "Erreur lors de la récupération des utilisateurs" }, - { status: 500 } - ); - } -} - diff --git a/app/challenges/page.tsx b/app/challenges/page.tsx deleted file mode 100644 index 944a981..0000000 --- a/app/challenges/page.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { redirect } from "next/navigation"; -import { auth } from "@/lib/auth"; -import { getBackgroundImage } from "@/lib/preferences"; -import NavigationWrapper from "@/components/navigation/NavigationWrapper"; -import ChallengesSection from "@/components/challenges/ChallengesSection"; - -export const dynamic = "force-dynamic"; - -export default async function ChallengesPage() { - const session = await auth(); - - if (!session?.user) { - redirect("/login"); - } - - const backgroundImage = await getBackgroundImage( - "home", - "/got-background.jpg" - ); - - return ( -
- - -
- ); -} - diff --git a/app/login/page.tsx b/app/login/page.tsx index 69b6604..fc31174 100644 --- a/app/login/page.tsx +++ b/app/login/page.tsx @@ -60,7 +60,7 @@ export default function LoginPage() { CONNEXION diff --git a/app/register/page.tsx b/app/register/page.tsx index a1471a7..23b580e 100644 --- a/app/register/page.tsx +++ b/app/register/page.tsx @@ -174,7 +174,7 @@ export default function RegisterPage() { {/* Register Form */} -
+
Classe de Personnage (optionnel) -
+
{CHARACTER_CLASSES.map((cls) => ( ))}
diff --git a/components/admin/AdminPanel.tsx b/components/admin/AdminPanel.tsx index e22033d..d10df95 100644 --- a/components/admin/AdminPanel.tsx +++ b/components/admin/AdminPanel.tsx @@ -4,7 +4,6 @@ import { useState } from "react"; import UserManagement from "@/components/admin/UserManagement"; import EventManagement from "@/components/admin/EventManagement"; import FeedbackManagement from "@/components/admin/FeedbackManagement"; -import ChallengeManagement from "@/components/admin/ChallengeManagement"; import BackgroundPreferences from "@/components/admin/BackgroundPreferences"; import { Button, Card, SectionTitle } from "@/components/ui"; @@ -19,7 +18,7 @@ interface AdminPanelProps { initialPreferences: SitePreferences; } -type AdminSection = "preferences" | "users" | "events" | "feedbacks" | "challenges"; +type AdminSection = "preferences" | "users" | "events" | "feedbacks"; export default function AdminPanel({ initialPreferences }: AdminPanelProps) { const [activeSection, setActiveSection] = @@ -68,14 +67,6 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) { > Feedbacks -
{activeSection === "preferences" && ( @@ -117,15 +108,6 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
)} - - {activeSection === "challenges" && ( - -

- Gestion des Défis -

- -
- )}
); diff --git a/components/admin/ChallengeManagement.tsx b/components/admin/ChallengeManagement.tsx deleted file mode 100644 index f19e07b..0000000 --- a/components/admin/ChallengeManagement.tsx +++ /dev/null @@ -1,504 +0,0 @@ -"use client"; - -import { useEffect, useState, useTransition } from "react"; -import { validateChallenge, rejectChallenge, updateChallenge, deleteChallenge } from "@/actions/admin/challenges"; -import { Button, Card, Input, Textarea, Alert } from "@/components/ui"; -import { Avatar } from "@/components/ui"; - -interface Challenge { - id: string; - challenger: { - id: string; - username: string; - avatar: string | null; - }; - challenged: { - id: string; - username: string; - avatar: string | null; - }; - title: string; - description: string; - pointsReward: number; - status: string; - adminComment: string | null; - createdAt: string; - acceptedAt: string | null; -} - -export default function ChallengeManagement() { - const [challenges, setChallenges] = useState([]); - const [loading, setLoading] = useState(true); - const [selectedChallenge, setSelectedChallenge] = useState(null); - const [editingChallenge, setEditingChallenge] = useState(null); - const [winnerId, setWinnerId] = useState(""); - const [adminComment, setAdminComment] = useState(""); - const [editTitle, setEditTitle] = useState(""); - const [editDescription, setEditDescription] = useState(""); - const [editPointsReward, setEditPointsReward] = useState(0); - const [isPending, startTransition] = useTransition(); - const [successMessage, setSuccessMessage] = useState(null); - const [errorMessage, setErrorMessage] = useState(null); - - useEffect(() => { - fetchChallenges(); - }, []); - - const fetchChallenges = async () => { - try { - const response = await fetch("/api/admin/challenges"); - if (response.ok) { - const data = await response.json(); - setChallenges(data); - } - } catch (error) { - console.error("Error fetching challenges:", error); - } finally { - setLoading(false); - } - }; - - const handleValidate = async () => { - if (!selectedChallenge || !winnerId) { - setErrorMessage("Veuillez sélectionner un gagnant"); - setTimeout(() => setErrorMessage(null), 5000); - return; - } - - startTransition(async () => { - const result = await validateChallenge( - selectedChallenge.id, - winnerId, - adminComment || undefined - ); - - if (result.success) { - setSuccessMessage("Défi validé avec succès ! Les points ont été attribués."); - setSelectedChallenge(null); - setWinnerId(""); - setAdminComment(""); - fetchChallenges(); - setTimeout(() => setSuccessMessage(null), 5000); - } else { - setErrorMessage(result.error || "Erreur lors de la validation"); - setTimeout(() => setErrorMessage(null), 5000); - } - }); - }; - - const handleReject = async () => { - if (!selectedChallenge) return; - - if (!confirm("Êtes-vous sûr de vouloir rejeter ce défi ?")) { - return; - } - - startTransition(async () => { - const result = await rejectChallenge( - selectedChallenge.id, - adminComment || undefined - ); - - if (result.success) { - setSuccessMessage("Défi rejeté"); - setSelectedChallenge(null); - setAdminComment(""); - fetchChallenges(); - setTimeout(() => setSuccessMessage(null), 5000); - } else { - setErrorMessage(result.error || "Erreur lors du rejet"); - setTimeout(() => setErrorMessage(null), 5000); - } - }); - }; - - const handleEdit = (challenge: Challenge) => { - setEditingChallenge(challenge); - setEditTitle(challenge.title); - setEditDescription(challenge.description); - setEditPointsReward(challenge.pointsReward); - }; - - const handleUpdate = async () => { - if (!editingChallenge) return; - - startTransition(async () => { - const result = await updateChallenge(editingChallenge.id, { - title: editTitle, - description: editDescription, - pointsReward: editPointsReward, - }); - - if (result.success) { - setSuccessMessage("Défi mis à jour avec succès"); - setEditingChallenge(null); - setEditTitle(""); - setEditDescription(""); - setEditPointsReward(0); - fetchChallenges(); - setTimeout(() => setSuccessMessage(null), 5000); - } else { - setErrorMessage(result.error || "Erreur lors de la mise à jour"); - setTimeout(() => setErrorMessage(null), 5000); - } - }); - }; - - const handleDelete = async (challengeId: string) => { - if (!confirm("Êtes-vous sûr de vouloir supprimer ce défi ? Cette action est irréversible.")) { - return; - } - - startTransition(async () => { - const result = await deleteChallenge(challengeId); - - if (result.success) { - setSuccessMessage("Défi supprimé avec succès"); - fetchChallenges(); - setTimeout(() => setSuccessMessage(null), 5000); - } else { - setErrorMessage(result.error || "Erreur lors de la suppression"); - setTimeout(() => setErrorMessage(null), 5000); - } - }); - }; - - if (loading) { - return ( -
Chargement...
- ); - } - - if (challenges.length === 0) { - return ( -
- Aucun défi en attente -
- ); - } - - const acceptedChallenges = challenges.filter((c) => c.status === "ACCEPTED"); - const pendingChallenges = challenges.filter((c) => c.status === "PENDING"); - - return ( -
- {successMessage && ( - - {successMessage} - - )} - {errorMessage && ( - - {errorMessage} - - )} -
- {acceptedChallenges.length} défi{acceptedChallenges.length > 1 ? "s" : ""} en attente de validation - {pendingChallenges.length > 0 && ( - - • {pendingChallenges.length} défi{pendingChallenges.length > 1 ? "s" : ""} en attente d'acceptation - - )} -
- - {challenges.map((challenge) => ( - -
-
-

- {challenge.title} -

-

{challenge.description}

- -
-
- - - {challenge.challenger.username} - - VS - - - {challenge.challenged.username} - -
-
- -
- Récompense: {challenge.pointsReward} points -
-
- - {challenge.status === "ACCEPTED" ? "Accepté" : "En attente d'acceptation"} - -
- {challenge.acceptedAt && ( -
- Accepté le: {new Date(challenge.acceptedAt).toLocaleDateString("fr-FR")} -
- )} -
- -
- - {challenge.status === "ACCEPTED" && ( - - )} - -
-
-
- ))} - - {/* Modal de validation */} - {selectedChallenge && ( -
{ - setSelectedChallenge(null); - setWinnerId(""); - setAdminComment(""); - }} - > - e.stopPropagation()} - > -
-

- Valider/Rejeter le défi -

- -
-

- {selectedChallenge.title} -

-

- {selectedChallenge.description} -

- -
-
- - - {selectedChallenge.challenger.username} - -
- VS -
- - - {selectedChallenge.challenged.username} - -
-
-
- -
- -
- - -
-
- -
- -