Add database and Prisma configurations, enhance event and leaderboard components with API integration, and update navigation for session management
This commit is contained in:
253
app/admin/page.tsx
Normal file
253
app/admin/page.tsx
Normal file
@@ -0,0 +1,253 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Navigation from "@/components/Navigation";
|
||||
|
||||
interface UserPreferences {
|
||||
id: string;
|
||||
userId: string;
|
||||
homeBackground: string | null;
|
||||
eventsBackground: string | null;
|
||||
leaderboardBackground: string | null;
|
||||
user: {
|
||||
id: string;
|
||||
username: string;
|
||||
email: string;
|
||||
};
|
||||
}
|
||||
|
||||
export default function AdminPage() {
|
||||
const { data: session, status } = useSession();
|
||||
const router = useRouter();
|
||||
const [preferences, setPreferences] = useState<UserPreferences[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [editingUserId, setEditingUserId] = useState<string | null>(null);
|
||||
const [formData, setFormData] = useState({
|
||||
homeBackground: "",
|
||||
eventsBackground: "",
|
||||
leaderboardBackground: "",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (status === "unauthenticated") {
|
||||
router.push("/login");
|
||||
return;
|
||||
}
|
||||
|
||||
if (status === "authenticated" && session?.user?.role !== "ADMIN") {
|
||||
router.push("/");
|
||||
return;
|
||||
}
|
||||
|
||||
if (status === "authenticated" && session?.user?.role === "ADMIN") {
|
||||
fetchPreferences();
|
||||
}
|
||||
}, [status, session, router]);
|
||||
|
||||
const fetchPreferences = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/admin/preferences");
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setPreferences(data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching preferences:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEdit = (pref: UserPreferences) => {
|
||||
setEditingUserId(pref.userId);
|
||||
setFormData({
|
||||
homeBackground: pref.homeBackground || "",
|
||||
eventsBackground: pref.eventsBackground || "",
|
||||
leaderboardBackground: pref.leaderboardBackground || "",
|
||||
});
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!editingUserId) return;
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/admin/preferences", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
userId: editingUserId,
|
||||
...formData,
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
await fetchPreferences();
|
||||
setEditingUserId(null);
|
||||
setFormData({
|
||||
homeBackground: "",
|
||||
eventsBackground: "",
|
||||
leaderboardBackground: "",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating preferences:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setEditingUserId(null);
|
||||
setFormData({
|
||||
homeBackground: "",
|
||||
eventsBackground: "",
|
||||
leaderboardBackground: "",
|
||||
});
|
||||
};
|
||||
|
||||
if (status === "loading" || loading) {
|
||||
return (
|
||||
<main className="min-h-screen bg-black relative">
|
||||
<Navigation />
|
||||
<div className="flex items-center justify-center min-h-screen text-pixel-gold">
|
||||
Chargement...
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-black relative">
|
||||
<Navigation />
|
||||
<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">
|
||||
<h1 className="text-4xl font-gaming font-black mb-8 text-center">
|
||||
<span className="bg-gradient-to-r from-pixel-gold via-orange-400 to-pixel-gold bg-clip-text text-transparent">
|
||||
ADMIN - GESTION DES PRÉFÉRENCES UI
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm">
|
||||
<div className="space-y-4">
|
||||
{preferences.map((pref) => (
|
||||
<div
|
||||
key={pref.id}
|
||||
className="bg-black/60 border border-pixel-gold/20 rounded p-4"
|
||||
>
|
||||
<div className="flex justify-between items-start mb-4">
|
||||
<div>
|
||||
<h3 className="text-pixel-gold font-bold text-lg">
|
||||
{pref.user.username}
|
||||
</h3>
|
||||
<p className="text-gray-400 text-sm">{pref.user.email}</p>
|
||||
</div>
|
||||
{editingUserId !== pref.userId && (
|
||||
<button
|
||||
onClick={() => handleEdit(pref)}
|
||||
className="px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{editingUserId === pref.userId ? (
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">
|
||||
Background Home
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.homeBackground}
|
||||
onChange={(e) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
homeBackground: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="/got-2.jpg"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">
|
||||
Background Events
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.eventsBackground}
|
||||
onChange={(e) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
eventsBackground: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="/got-2.jpg"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-1">
|
||||
Background Leaderboard
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.leaderboardBackground}
|
||||
onChange={(e) =>
|
||||
setFormData({
|
||||
...formData,
|
||||
leaderboardBackground: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="/leaderboard-bg.jpg"
|
||||
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
className="px-4 py-2 border border-green-500/50 bg-green-900/20 text-green-400 uppercase text-xs tracking-widest rounded hover:bg-green-900/30 transition"
|
||||
>
|
||||
Enregistrer
|
||||
</button>
|
||||
<button
|
||||
onClick={handleCancel}
|
||||
className="px-4 py-2 border border-gray-600/50 bg-gray-900/20 text-gray-400 uppercase text-xs tracking-widest rounded hover:bg-gray-900/30 transition"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2 text-sm text-gray-400">
|
||||
<div>
|
||||
Home: {pref.homeBackground || "Par défaut"}
|
||||
</div>
|
||||
<div>
|
||||
Events: {pref.eventsBackground || "Par défaut"}
|
||||
</div>
|
||||
<div>
|
||||
Leaderboard:{" "}
|
||||
{pref.leaderboardBackground || "Par défaut"}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{preferences.length === 0 && (
|
||||
<div className="text-center text-gray-400 py-8">
|
||||
Aucune préférence trouvée
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user