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.
Some checks failed
Deploy with Docker Compose / deploy (push) Failing after 3m2s
Some checks failed
Deploy with Docker Compose / deploy (push) Failing after 3m2s
This commit is contained in:
30
app/api/admin/challenges/route.ts
Normal file
30
app/api/admin/challenges/route.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
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 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
25
app/api/challenges/route.ts
Normal file
25
app/api/challenges/route.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
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 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
39
app/api/users/route.ts
Normal file
39
app/api/users/route.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
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 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
28
app/challenges/page.tsx
Normal file
28
app/challenges/page.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
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 (
|
||||
<main className="min-h-screen bg-black relative">
|
||||
<NavigationWrapper />
|
||||
<ChallengesSection backgroundImage={backgroundImage} />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function LoginPage() {
|
||||
<Card variant="dark" className="p-8">
|
||||
<SectionTitle
|
||||
variant="gradient"
|
||||
size="lg"
|
||||
size="md"
|
||||
className="mb-2 text-center"
|
||||
>
|
||||
CONNEXION
|
||||
|
||||
@@ -174,7 +174,7 @@ export default function RegisterPage() {
|
||||
<Navigation />
|
||||
<BackgroundSection backgroundImage="/got-2.jpg" className="pt-24">
|
||||
{/* Register Form */}
|
||||
<div className="w-full max-w-md mx-auto px-8">
|
||||
<div className="w-full max-w-4xl mx-auto px-8">
|
||||
<Card variant="dark" className="p-8">
|
||||
<SectionTitle
|
||||
variant="gradient"
|
||||
@@ -397,7 +397,7 @@ export default function RegisterPage() {
|
||||
<label className="block text-sm font-semibold text-gray-300 mb-3 uppercase tracking-wider">
|
||||
Classe de Personnage (optionnel)
|
||||
</label>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||
{CHARACTER_CLASSES.map((cls) => (
|
||||
<button
|
||||
key={cls.value}
|
||||
@@ -411,16 +411,16 @@ export default function RegisterPage() {
|
||||
: cls.value,
|
||||
})
|
||||
}
|
||||
className={`p-3 border-2 rounded-lg text-left transition-all ${
|
||||
className={`p-4 border-2 rounded-lg text-left transition-all ${
|
||||
formData.characterClass === cls.value
|
||||
? "border-pixel-gold bg-pixel-gold/20"
|
||||
: "border-pixel-gold/30 bg-black/40 hover:border-pixel-gold/50"
|
||||
? "border-pixel-gold bg-pixel-gold/20 shadow-lg shadow-pixel-gold/30"
|
||||
: "border-pixel-gold/30 bg-black/40 hover:border-pixel-gold/50 hover:bg-black/60"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">{cls.icon}</span>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className="text-2xl">{cls.icon}</span>
|
||||
<span
|
||||
className={`font-bold text-xs uppercase tracking-wider ${
|
||||
className={`font-bold text-sm uppercase tracking-wider ${
|
||||
formData.characterClass === cls.value
|
||||
? "text-pixel-gold"
|
||||
: "text-white"
|
||||
@@ -429,6 +429,9 @@ export default function RegisterPage() {
|
||||
{cls.name}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-400 leading-tight">
|
||||
{cls.desc}
|
||||
</p>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user