354 lines
15 KiB
TypeScript
354 lines
15 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import ImageSelector from "@/components/ImageSelector";
|
|
import UserManagement from "@/components/UserManagement";
|
|
import EventManagement from "@/components/EventManagement";
|
|
import FeedbackManagement from "@/components/FeedbackManagement";
|
|
|
|
interface SitePreferences {
|
|
id: string;
|
|
homeBackground: string | null;
|
|
eventsBackground: string | null;
|
|
leaderboardBackground: string | null;
|
|
}
|
|
|
|
interface AdminPanelProps {
|
|
initialPreferences: SitePreferences;
|
|
}
|
|
|
|
type AdminSection = "preferences" | "users" | "events" | "feedbacks";
|
|
|
|
export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
|
|
const [activeSection, setActiveSection] =
|
|
useState<AdminSection>("preferences");
|
|
const [preferences, setPreferences] = useState<SitePreferences | null>(
|
|
initialPreferences
|
|
);
|
|
const [isEditing, setIsEditing] = useState(false);
|
|
const [formData, setFormData] = useState({
|
|
homeBackground: initialPreferences.homeBackground || "",
|
|
eventsBackground: initialPreferences.eventsBackground || "",
|
|
leaderboardBackground: initialPreferences.leaderboardBackground || "",
|
|
});
|
|
|
|
const handleEdit = () => {
|
|
setIsEditing(true);
|
|
};
|
|
|
|
const handleSave = async () => {
|
|
try {
|
|
const response = await fetch("/api/admin/preferences", {
|
|
method: "PUT",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(formData),
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setPreferences(data);
|
|
setIsEditing(false);
|
|
}
|
|
} catch (error) {
|
|
console.error("Error updating preferences:", error);
|
|
}
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
setIsEditing(false);
|
|
if (preferences) {
|
|
setFormData({
|
|
homeBackground: preferences.homeBackground || "",
|
|
eventsBackground: preferences.eventsBackground || "",
|
|
leaderboardBackground: preferences.leaderboardBackground || "",
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<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-4 sm:px-8 py-16">
|
|
<h1 className="text-2xl sm:text-4xl font-gaming font-black mb-8 text-center break-words">
|
|
<span className="bg-gradient-to-r from-pixel-gold via-orange-400 to-pixel-gold bg-clip-text text-transparent">
|
|
ADMIN
|
|
</span>
|
|
</h1>
|
|
|
|
{/* Navigation Tabs */}
|
|
<div className="mb-8">
|
|
{/* Mobile: Grid layout */}
|
|
<div className="grid grid-cols-2 sm:hidden gap-2">
|
|
<button
|
|
onClick={() => setActiveSection("preferences")}
|
|
className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
|
|
activeSection === "preferences"
|
|
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold font-semibold"
|
|
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
|
}`}
|
|
>
|
|
Préférences
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveSection("users")}
|
|
className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
|
|
activeSection === "users"
|
|
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold font-semibold"
|
|
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
|
}`}
|
|
>
|
|
Utilisateurs
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveSection("events")}
|
|
className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
|
|
activeSection === "events"
|
|
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold font-semibold"
|
|
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
|
}`}
|
|
>
|
|
Événements
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveSection("feedbacks")}
|
|
className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
|
|
activeSection === "feedbacks"
|
|
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold font-semibold"
|
|
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50"
|
|
}`}
|
|
>
|
|
Feedbacks
|
|
</button>
|
|
</div>
|
|
|
|
{/* Desktop: Horizontal tabs */}
|
|
<div className="hidden sm:flex gap-4 justify-center">
|
|
<button
|
|
onClick={() => setActiveSection("preferences")}
|
|
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition whitespace-nowrap ${
|
|
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 whitespace-nowrap ${
|
|
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>
|
|
<button
|
|
onClick={() => setActiveSection("events")}
|
|
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition whitespace-nowrap ${
|
|
activeSection === "events"
|
|
? "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"
|
|
}`}
|
|
>
|
|
Événements
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveSection("feedbacks")}
|
|
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition whitespace-nowrap ${
|
|
activeSection === "feedbacks"
|
|
? "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"
|
|
}`}
|
|
>
|
|
Feedbacks
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{activeSection === "preferences" && (
|
|
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-4 sm:p-6 backdrop-blur-sm">
|
|
<h2 className="text-xl sm:text-2xl font-gaming font-bold mb-6 text-pixel-gold break-words">
|
|
Préférences UI Globales
|
|
</h2>
|
|
<div className="space-y-4">
|
|
<div className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4">
|
|
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3 mb-4">
|
|
<div className="min-w-0 flex-1">
|
|
<h3 className="text-pixel-gold font-bold text-base sm:text-lg break-words">
|
|
Images de fond du site
|
|
</h3>
|
|
<p className="text-gray-400 text-xs sm:text-sm">
|
|
Ces préférences s'appliquent à tous les utilisateurs
|
|
</p>
|
|
</div>
|
|
{!isEditing && (
|
|
<button
|
|
onClick={handleEdit}
|
|
className="px-3 sm:px-4 py-2 border border-pixel-gold/50 bg-black/60 text-white uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition whitespace-nowrap flex-shrink-0"
|
|
>
|
|
Modifier
|
|
</button>
|
|
)}
|
|
</div>
|
|
|
|
{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 flex-col sm:flex-row 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"
|
|
>
|
|
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-4">
|
|
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
|
<span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
|
|
Home:
|
|
</span>
|
|
{preferences?.homeBackground ? (
|
|
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
|
|
<img
|
|
src={preferences.homeBackground}
|
|
alt="Home background"
|
|
className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
|
|
onError={(e) => {
|
|
e.currentTarget.src = "/got-2.jpg";
|
|
}}
|
|
/>
|
|
<span className="text-xs text-gray-400 truncate min-w-0">
|
|
{preferences.homeBackground}
|
|
</span>
|
|
</div>
|
|
) : (
|
|
<span className="text-gray-400 text-sm sm:text-base">
|
|
Par défaut
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
|
<span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
|
|
Events:
|
|
</span>
|
|
{preferences?.eventsBackground ? (
|
|
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
|
|
<img
|
|
src={preferences.eventsBackground}
|
|
alt="Events background"
|
|
className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
|
|
onError={(e) => {
|
|
e.currentTarget.src = "/got-2.jpg";
|
|
}}
|
|
/>
|
|
<span className="text-xs text-gray-400 truncate min-w-0">
|
|
{preferences.eventsBackground}
|
|
</span>
|
|
</div>
|
|
) : (
|
|
<span className="text-gray-400 text-sm sm:text-base">
|
|
Par défaut
|
|
</span>
|
|
)}
|
|
</div>
|
|
<div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
|
|
<span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
|
|
Leaderboard:
|
|
</span>
|
|
{preferences?.leaderboardBackground ? (
|
|
<div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
|
|
<img
|
|
src={preferences.leaderboardBackground}
|
|
alt="Leaderboard background"
|
|
className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
|
|
onError={(e) => {
|
|
e.currentTarget.src = "/got-2.jpg";
|
|
}}
|
|
/>
|
|
<span className="text-xs text-gray-400 truncate min-w-0">
|
|
{preferences.leaderboardBackground}
|
|
</span>
|
|
</div>
|
|
) : (
|
|
<span className="text-gray-400 text-sm sm:text-base">
|
|
Par défaut
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{activeSection === "users" && (
|
|
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-4 sm:p-6 backdrop-blur-sm">
|
|
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
|
Gestion des Utilisateurs
|
|
</h2>
|
|
<UserManagement />
|
|
</div>
|
|
)}
|
|
|
|
{activeSection === "events" && (
|
|
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-4 sm:p-6 backdrop-blur-sm">
|
|
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
|
Gestion des Événements
|
|
</h2>
|
|
<EventManagement />
|
|
</div>
|
|
)}
|
|
|
|
{activeSection === "feedbacks" && (
|
|
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-4 sm:p-6 backdrop-blur-sm">
|
|
<h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
|
|
Gestion des Feedbacks
|
|
</h2>
|
|
<FeedbackManagement />
|
|
</div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|