Refactor admin preferences management to use global site preferences, update UI components for better user experience, and implement image selection for background settings.

This commit is contained in:
Julien Froidefond
2025-12-09 08:37:52 +01:00
parent 4486f305f2
commit 8c326bdd20
21 changed files with 1853 additions and 199 deletions

View File

@@ -4,26 +4,25 @@ import { useEffect, useState } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import Navigation from "@/components/Navigation";
import ImageSelector from "@/components/ImageSelector";
interface UserPreferences {
interface SitePreferences {
id: string;
userId: string;
homeBackground: string | null;
eventsBackground: string | null;
leaderboardBackground: string | null;
user: {
id: string;
username: string;
email: string;
};
}
type AdminSection = "preferences" | "users";
export default function AdminPage() {
const { data: session, status } = useSession();
const router = useRouter();
const [preferences, setPreferences] = useState<UserPreferences[]>([]);
const [activeSection, setActiveSection] =
useState<AdminSection>("preferences");
const [preferences, setPreferences] = useState<SitePreferences | null>(null);
const [loading, setLoading] = useState(true);
const [editingUserId, setEditingUserId] = useState<string | null>(null);
const [isEditing, setIsEditing] = useState(false);
const [formData, setFormData] = useState({
homeBackground: "",
eventsBackground: "",
@@ -52,6 +51,11 @@ export default function AdminPage() {
if (response.ok) {
const data = await response.json();
setPreferences(data);
setFormData({
homeBackground: data.homeBackground || "",
eventsBackground: data.eventsBackground || "",
leaderboardBackground: data.leaderboardBackground || "",
});
}
} catch (error) {
console.error("Error fetching preferences:", error);
@@ -60,38 +64,23 @@ export default function AdminPage() {
}
};
const handleEdit = (pref: UserPreferences) => {
setEditingUserId(pref.userId);
setFormData({
homeBackground: pref.homeBackground || "",
eventsBackground: pref.eventsBackground || "",
leaderboardBackground: pref.leaderboardBackground || "",
});
const handleEdit = () => {
setIsEditing(true);
};
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,
}),
body: JSON.stringify(formData),
});
if (response.ok) {
await fetchPreferences();
setEditingUserId(null);
setFormData({
homeBackground: "",
eventsBackground: "",
leaderboardBackground: "",
});
setIsEditing(false);
}
} catch (error) {
console.error("Error updating preferences:", error);
@@ -99,12 +88,14 @@ export default function AdminPage() {
};
const handleCancel = () => {
setEditingUserId(null);
setFormData({
homeBackground: "",
eventsBackground: "",
leaderboardBackground: "",
});
setIsEditing(false);
if (preferences) {
setFormData({
homeBackground: preferences.homeBackground || "",
eventsBackground: preferences.eventsBackground || "",
leaderboardBackground: preferences.leaderboardBackground || "",
});
}
};
if (status === "loading" || loading) {
@@ -125,27 +116,53 @@ export default function AdminPage() {
<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
ADMIN
</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"
>
{/* Navigation Tabs */}
<div className="flex gap-4 mb-8 justify-center">
<button
onClick={() => setActiveSection("preferences")}
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${
activeSection === "preferences"
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold"
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
}`}
>
Préférences UI
</button>
<button
onClick={() => setActiveSection("users")}
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${
activeSection === "users"
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold"
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
}`}
>
Utilisateurs
</button>
</div>
{activeSection === "preferences" && (
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm">
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
Préférences UI Globales
</h2>
<div className="space-y-4">
<div 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}
Images de fond du site
</h3>
<p className="text-gray-400 text-sm">{pref.user.email}</p>
<p className="text-gray-400 text-sm">
Ces préférences s'appliquent à tous les utilisateurs
</p>
</div>
{editingUserId !== pref.userId && (
{!isEditing && (
<button
onClick={() => handleEdit(pref)}
onClick={handleEdit}
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
@@ -153,60 +170,39 @@ export default function AdminPage() {
)}
</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">
{isEditing ? (
<div className="space-y-6">
<ImageSelector
value={formData.homeBackground}
onChange={(url) =>
setFormData({
...formData,
homeBackground: url,
})
}
label="Background Home"
/>
<ImageSelector
value={formData.eventsBackground}
onChange={(url) =>
setFormData({
...formData,
eventsBackground: url,
})
}
label="Background Events"
/>
<ImageSelector
value={formData.leaderboardBackground}
onChange={(url) =>
setFormData({
...formData,
leaderboardBackground: url,
})
}
label="Background Leaderboard"
/>
<div className="flex gap-2 pt-4">
<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"
@@ -224,30 +220,34 @@ export default function AdminPage() {
) : (
<div className="space-y-2 text-sm text-gray-400">
<div>
Home: {pref.homeBackground || "Par défaut"}
Home: {preferences?.homeBackground || "Par défaut"}
</div>
<div>
Events: {pref.eventsBackground || "Par défaut"}
Events: {preferences?.eventsBackground || "Par défaut"}
</div>
<div>
Leaderboard:{" "}
{pref.leaderboardBackground || "Par défaut"}
{preferences?.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>
)}
{activeSection === "users" && (
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm">
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
Gestion des Utilisateurs
</h2>
<div className="text-center text-gray-400 py-8">
Section utilisateurs à venir...
</div>
</div>
)}
</div>
</section>
</main>
);
}