Refactor AdminPage and remove AdminPanel component: Simplify admin navigation by redirecting to preferences page and eliminating the AdminPanel component, streamlining the admin interface.
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 6m21s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 6m21s
This commit is contained in:
26
app/admin/challenges/page.tsx
Normal file
26
app/admin/challenges/page.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import ChallengeManagement from "@/components/admin/ChallengeManagement";
|
||||
import { Card } from "@/components/ui";
|
||||
import { challengeService } from "@/services/challenges/challenge.service";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminChallengesPage() {
|
||||
const challenges = await challengeService.getAllChallenges();
|
||||
|
||||
// Sérialiser les dates pour le client
|
||||
const serializedChallenges = challenges.map((challenge) => ({
|
||||
...challenge,
|
||||
createdAt: challenge.createdAt.toISOString(),
|
||||
acceptedAt: challenge.acceptedAt?.toISOString() ?? null,
|
||||
completedAt: challenge.completedAt?.toISOString() ?? null,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Card variant="dark" className="p-6">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
Gestion des Défis
|
||||
</h2>
|
||||
<ChallengeManagement initialChallenges={serializedChallenges} />
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
34
app/admin/events/page.tsx
Normal file
34
app/admin/events/page.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import EventManagement from "@/components/admin/EventManagement";
|
||||
import { Card } from "@/components/ui";
|
||||
import { eventService } from "@/services/events/event.service";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminEventsPage() {
|
||||
const events = await eventService.getEventsWithStatus();
|
||||
|
||||
// Transformer les données pour la sérialisation
|
||||
const serializedEvents = events.map((event) => ({
|
||||
id: event.id,
|
||||
date: event.date.toISOString(),
|
||||
name: event.name,
|
||||
description: event.description,
|
||||
type: event.type,
|
||||
status: event.status,
|
||||
room: event.room,
|
||||
time: event.time,
|
||||
maxPlaces: event.maxPlaces,
|
||||
createdAt: event.createdAt.toISOString(),
|
||||
updatedAt: event.updatedAt.toISOString(),
|
||||
registrationsCount: event.registrationsCount,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Card variant="dark" className="p-6">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
Gestion des Événements
|
||||
</h2>
|
||||
<EventManagement initialEvents={serializedEvents} />
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
77
app/admin/feedbacks/page.tsx
Normal file
77
app/admin/feedbacks/page.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import FeedbackManagement from "@/components/admin/FeedbackManagement";
|
||||
import { Card } from "@/components/ui";
|
||||
import { eventFeedbackService } from "@/services/events/event-feedback.service";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminFeedbacksPage() {
|
||||
const [feedbacksRaw, statistics] = await Promise.all([
|
||||
eventFeedbackService.getAllFeedbacks(),
|
||||
eventFeedbackService.getFeedbackStatistics(),
|
||||
]);
|
||||
|
||||
// Type assertion car getAllFeedbacks inclut event et user par défaut
|
||||
const feedbacks = feedbacksRaw as unknown as Array<{
|
||||
id: string;
|
||||
rating: number;
|
||||
comment: string | null;
|
||||
isRead: boolean;
|
||||
createdAt: Date;
|
||||
event: {
|
||||
id: string;
|
||||
name: string;
|
||||
date: Date;
|
||||
type: string;
|
||||
};
|
||||
user: {
|
||||
id: string;
|
||||
username: string;
|
||||
email: string;
|
||||
avatar: string | null;
|
||||
score: number;
|
||||
};
|
||||
}>;
|
||||
|
||||
// Sérialiser les dates pour le client
|
||||
const serializedFeedbacks = feedbacks.map((feedback) => ({
|
||||
id: feedback.id,
|
||||
rating: feedback.rating,
|
||||
comment: feedback.comment,
|
||||
isRead: feedback.isRead,
|
||||
createdAt: feedback.createdAt.toISOString(),
|
||||
event: {
|
||||
id: feedback.event.id,
|
||||
name: feedback.event.name,
|
||||
date: feedback.event.date.toISOString(),
|
||||
type: feedback.event.type,
|
||||
},
|
||||
user: {
|
||||
id: feedback.user.id,
|
||||
username: feedback.user.username,
|
||||
email: feedback.user.email,
|
||||
avatar: feedback.user.avatar,
|
||||
score: feedback.user.score,
|
||||
},
|
||||
}));
|
||||
|
||||
const serializedStatistics = statistics.map((stat) => ({
|
||||
eventId: stat.eventId,
|
||||
eventName: stat.eventName,
|
||||
eventDate: stat.eventDate?.toISOString() ?? null,
|
||||
eventType: stat.eventType,
|
||||
averageRating: stat.averageRating,
|
||||
feedbackCount: stat.feedbackCount,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Card variant="dark" className="p-6">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
Gestion des Feedbacks
|
||||
</h2>
|
||||
<FeedbackManagement
|
||||
initialFeedbacks={serializedFeedbacks}
|
||||
initialStatistics={serializedStatistics}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
90
app/admin/houses/page.tsx
Normal file
90
app/admin/houses/page.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import HouseManagement from "@/components/admin/HouseManagement";
|
||||
import { Card } from "@/components/ui";
|
||||
import { houseService } from "@/services/houses/house.service";
|
||||
import { Prisma } from "@/prisma/generated/prisma/client";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminHousesPage() {
|
||||
type HouseWithIncludes = Prisma.HouseGetPayload<{
|
||||
include: {
|
||||
creator: {
|
||||
select: {
|
||||
id: true;
|
||||
username: true;
|
||||
avatar: true;
|
||||
};
|
||||
};
|
||||
memberships: {
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true;
|
||||
username: true;
|
||||
avatar: true;
|
||||
score: true;
|
||||
level: true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}>;
|
||||
|
||||
const houses = (await houseService.getAllHouses({
|
||||
include: {
|
||||
creator: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
avatar: true,
|
||||
},
|
||||
},
|
||||
memberships: {
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
avatar: true,
|
||||
score: true,
|
||||
level: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: [{ role: "asc" }, { joinedAt: "asc" }],
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
})) as unknown as HouseWithIncludes[];
|
||||
|
||||
// Transformer les données pour la sérialisation
|
||||
const serializedHouses = houses.map((house) => ({
|
||||
id: house.id,
|
||||
name: house.name,
|
||||
description: house.description,
|
||||
creatorId: house.creatorId,
|
||||
creator: house.creator,
|
||||
createdAt: house.createdAt.toISOString(),
|
||||
updatedAt: house.updatedAt.toISOString(),
|
||||
membersCount: house.memberships?.length || 0,
|
||||
memberships:
|
||||
house.memberships?.map((membership) => ({
|
||||
id: membership.id,
|
||||
role: membership.role,
|
||||
joinedAt: membership.joinedAt.toISOString(),
|
||||
user: membership.user,
|
||||
})) || [],
|
||||
}));
|
||||
|
||||
return (
|
||||
<Card variant="dark" className="p-6">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
Gestion des Maisons
|
||||
</h2>
|
||||
<HouseManagement initialHouses={serializedHouses} />
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
52
app/admin/layout.tsx
Normal file
52
app/admin/layout.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { Role } from "@/prisma/generated/prisma/client";
|
||||
import NavigationWrapper from "@/components/navigation/NavigationWrapper";
|
||||
import AdminNavigation from "@/components/admin/AdminNavigation";
|
||||
import { SectionTitle } from "@/components/ui";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user) {
|
||||
redirect("/login");
|
||||
}
|
||||
|
||||
if (session.user.role !== Role.ADMIN) {
|
||||
redirect("/");
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-black relative">
|
||||
{/* Background Image */}
|
||||
<div
|
||||
className="fixed inset-0 bg-cover bg-center bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: `url('/got-light.jpg')`,
|
||||
}}
|
||||
>
|
||||
{/* Dark overlay for readability */}
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/70 via-black/60 to-black/80"></div>
|
||||
</div>
|
||||
<NavigationWrapper />
|
||||
<section className="relative w-full min-h-screen flex flex-col items-center overflow-hidden pt-24 pb-16">
|
||||
<div className="relative z-10 w-full max-w-6xl mx-auto px-8 py-16">
|
||||
<SectionTitle variant="gradient" size="md" className="mb-16 text-center">
|
||||
ADMIN
|
||||
</SectionTitle>
|
||||
|
||||
<AdminNavigation />
|
||||
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,41 +1,7 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { sitePreferencesService } from "@/services/preferences/site-preferences.service";
|
||||
import { Role } from "@/prisma/generated/prisma/client";
|
||||
import NavigationWrapper from "@/components/navigation/NavigationWrapper";
|
||||
import AdminPanel from "@/components/admin/AdminPanel";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminPage() {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user) {
|
||||
redirect("/login");
|
||||
}
|
||||
|
||||
if (session.user.role !== Role.ADMIN) {
|
||||
redirect("/");
|
||||
}
|
||||
|
||||
// Récupérer les préférences globales du site (ou créer si elles n'existent pas)
|
||||
const sitePreferences =
|
||||
await sitePreferencesService.getOrCreateSitePreferences();
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-black relative">
|
||||
{/* Background Image */}
|
||||
<div
|
||||
className="fixed inset-0 bg-cover bg-center bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: `url('/got-light.jpg')`,
|
||||
}}
|
||||
>
|
||||
{/* Dark overlay for readability */}
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-black/70 via-black/60 to-black/80"></div>
|
||||
</div>
|
||||
<NavigationWrapper />
|
||||
<AdminPanel initialPreferences={sitePreferences} />
|
||||
</main>
|
||||
);
|
||||
redirect("/admin/preferences");
|
||||
}
|
||||
|
||||
30
app/admin/preferences/page.tsx
Normal file
30
app/admin/preferences/page.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { sitePreferencesService } from "@/services/preferences/site-preferences.service";
|
||||
import BackgroundPreferences from "@/components/admin/BackgroundPreferences";
|
||||
import EventPointsPreferences from "@/components/admin/EventPointsPreferences";
|
||||
import EventFeedbackPointsPreferences from "@/components/admin/EventFeedbackPointsPreferences";
|
||||
import HousePointsPreferences from "@/components/admin/HousePointsPreferences";
|
||||
import { Card } from "@/components/ui";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminPreferencesPage() {
|
||||
const sitePreferences =
|
||||
await sitePreferencesService.getOrCreateSitePreferences();
|
||||
|
||||
return (
|
||||
<Card variant="dark" className="p-4 sm:p-6">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
|
||||
<h2 className="text-xl sm:text-2xl font-gaming font-bold text-pixel-gold break-words">
|
||||
Préférences UI Globales
|
||||
</h2>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<BackgroundPreferences initialPreferences={sitePreferences} />
|
||||
<EventPointsPreferences initialPreferences={sitePreferences} />
|
||||
<EventFeedbackPointsPreferences initialPreferences={sitePreferences} />
|
||||
<HousePointsPreferences initialPreferences={sitePreferences} />
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
42
app/admin/users/page.tsx
Normal file
42
app/admin/users/page.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import UserManagement from "@/components/admin/UserManagement";
|
||||
import { Card } from "@/components/ui";
|
||||
import { userService } from "@/services/users/user.service";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminUsersPage() {
|
||||
const users = await userService.getAllUsers({
|
||||
orderBy: {
|
||||
score: "desc",
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
role: true,
|
||||
score: true,
|
||||
level: true,
|
||||
hp: true,
|
||||
maxHp: true,
|
||||
xp: true,
|
||||
maxXp: true,
|
||||
avatar: true,
|
||||
createdAt: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Sérialiser les dates pour le client
|
||||
const serializedUsers = users.map((user) => ({
|
||||
...user,
|
||||
createdAt: user.createdAt.toISOString(),
|
||||
}));
|
||||
|
||||
return (
|
||||
<Card variant="dark" className="p-6">
|
||||
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
||||
Gestion des Utilisateurs
|
||||
</h2>
|
||||
<UserManagement initialUsers={serializedUsers} />
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user