From f2bb02406e98facad010ca9dd733f9a95bb2da54 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Mon, 15 Dec 2025 16:02:31 +0100 Subject: [PATCH] Revert "Add dotenv package for environment variable management and update pnpm-lock.yaml. Adjust layout in RegisterPage and LoginPage components for improved responsiveness. Enhance AdminPanel with ChallengeManagement section and update navigation links for challenges. Refactor Prisma schema to include Challenge model and related enums." This reverts commit f093977b34629f85e55ce1131c5b71f53ae5472e. --- actions/admin/challenges.ts | 152 - actions/challenges/create.ts | 112 - app/api/admin/challenges/route.ts | 30 - app/api/challenges/route.ts | 25 - app/api/users/route.ts | 39 - app/challenges/page.tsx | 28 - app/login/page.tsx | 2 +- app/register/page.tsx | 19 +- components/admin/AdminPanel.tsx | 20 +- components/admin/ChallengeManagement.tsx | 504 --- components/challenges/ChallengesSection.tsx | 428 -- components/navigation/Navigation.tsx | 31 - components/ui/Alert.tsx | 4 +- package.json | 1 - pnpm-lock.yaml | 9 - prisma/generated/prisma/browser.ts | 44 +- prisma/generated/prisma/client.ts | 68 +- prisma/generated/prisma/commonInputTypes.ts | 838 ++-- prisma/generated/prisma/enums.ts | 69 +- prisma/generated/prisma/internal/class.ts | 263 +- .../prisma/internal/prismaNamespace.ts | 1610 ++++--- .../prisma/internal/prismaNamespaceBrowser.ts | 235 +- prisma/generated/prisma/models.ts | 18 +- prisma/generated/prisma/models/Challenge.ts | 2261 ---------- prisma/generated/prisma/models/Event.ts | 2113 ++++++---- .../generated/prisma/models/EventFeedback.ts | 2104 ++++++---- .../prisma/models/EventRegistration.ts | 1825 +++++--- .../prisma/models/SitePreferences.ts | 1395 ++++--- prisma/generated/prisma/models/User.ts | 3698 ++++++++--------- .../prisma/models/UserPreferences.ts | 1754 +++++--- .../migration.sql | 2 - .../migration.sql | 33 - prisma/schema.prisma | 221 +- services/challenges/challenge.service.ts | 500 --- 34 files changed, 9061 insertions(+), 11394 deletions(-) delete mode 100644 actions/admin/challenges.ts delete mode 100644 actions/challenges/create.ts delete mode 100644 app/api/admin/challenges/route.ts delete mode 100644 app/api/challenges/route.ts delete mode 100644 app/api/users/route.ts delete mode 100644 app/challenges/page.tsx delete mode 100644 components/admin/ChallengeManagement.tsx delete mode 100644 components/challenges/ChallengesSection.tsx delete mode 100644 prisma/generated/prisma/models/Challenge.ts delete mode 100644 prisma/migrations/20251212093056_add_primary_color/migration.sql delete mode 100644 prisma/migrations/20251215140148_add_challenges/migration.sql delete mode 100644 services/challenges/challenge.service.ts 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} - -
-
-
- -
- -
- - -
-
- -
- -