Compare commits

...

2 Commits

9 changed files with 451 additions and 312 deletions

View File

@@ -69,77 +69,124 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
return ( return (
<section className="relative w-full min-h-screen flex flex-col items-center overflow-hidden pt-24 pb-16"> <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"> <div className="relative z-10 w-full max-w-6xl mx-auto px-4 sm:px-8 py-16">
<h1 className="text-4xl font-gaming font-black mb-8 text-center"> <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"> <span className="bg-gradient-to-r from-pixel-gold via-orange-400 to-pixel-gold bg-clip-text text-transparent">
ADMIN ADMIN
</span> </span>
</h1> </h1>
{/* Navigation Tabs */} {/* Navigation Tabs */}
<div className="flex gap-4 mb-8 justify-center"> <div className="mb-8">
<button {/* Mobile: Grid layout */}
onClick={() => setActiveSection("preferences")} <div className="grid grid-cols-2 sm:hidden gap-2">
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${ <button
activeSection === "preferences" onClick={() => setActiveSection("preferences")}
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold" className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50" 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 UI }`}
</button> >
<button Préférences
onClick={() => setActiveSection("users")} </button>
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${ <button
activeSection === "users" onClick={() => setActiveSection("users")}
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold" className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50" 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 Utilisateurs
onClick={() => setActiveSection("events")} </button>
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${ <button
activeSection === "events" onClick={() => setActiveSection("events")}
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold" className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50" 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 Événements
onClick={() => setActiveSection("feedbacks")} </button>
className={`px-6 py-3 border uppercase text-xs tracking-widest rounded transition ${ <button
activeSection === "feedbacks" onClick={() => setActiveSection("feedbacks")}
? "border-pixel-gold bg-pixel-gold/10 text-pixel-gold" className={`px-3 py-2.5 border uppercase text-xs tracking-wider rounded transition ${
: "border-pixel-gold/30 bg-black/60 text-gray-400 hover:border-pixel-gold/50" 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> >
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> </div>
{activeSection === "preferences" && ( {activeSection === "preferences" && (
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm"> <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"> <h2 className="text-xl sm:text-2xl font-gaming font-bold mb-6 text-pixel-gold break-words">
Préférences UI Globales Préférences UI Globales
</h2> </h2>
<div className="space-y-4"> <div className="space-y-4">
<div className="bg-black/60 border border-pixel-gold/20 rounded p-4"> <div className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4">
<div className="flex justify-between items-start mb-4"> <div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3 mb-4">
<div> <div className="min-w-0 flex-1">
<h3 className="text-pixel-gold font-bold text-lg"> <h3 className="text-pixel-gold font-bold text-base sm:text-lg break-words">
Images de fond du site Images de fond du site
</h3> </h3>
<p className="text-gray-400 text-sm"> <p className="text-gray-400 text-xs sm:text-sm">
Ces préférences s&apos;appliquent à tous les utilisateurs Ces préférences s&apos;appliquent à tous les utilisateurs
</p> </p>
</div> </div>
{!isEditing && ( {!isEditing && (
<button <button
onClick={handleEdit} 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" 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 Modifier
</button> </button>
@@ -178,7 +225,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
} }
label="Background Leaderboard" label="Background Leaderboard"
/> />
<div className="flex gap-2 pt-4"> <div className="flex flex-col sm:flex-row gap-2 pt-4">
<button <button
onClick={handleSave} 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" 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"
@@ -195,70 +242,76 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
</div> </div>
) : ( ) : (
<div className="space-y-4"> <div className="space-y-4">
<div className="flex items-center gap-4"> <div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
<span className="text-pixel-gold font-bold min-w-[120px]"> <span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
Home: Home:
</span> </span>
{preferences?.homeBackground ? ( {preferences?.homeBackground ? (
<div className="flex items-center gap-3"> <div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
<img <img
src={preferences.homeBackground} src={preferences.homeBackground}
alt="Home background" alt="Home background"
className="w-20 h-12 object-cover rounded border border-pixel-gold/30" className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
onError={(e) => { onError={(e) => {
e.currentTarget.src = "/got-2.jpg"; e.currentTarget.src = "/got-2.jpg";
}} }}
/> />
<span className="text-xs text-gray-400 truncate max-w-xs"> <span className="text-xs text-gray-400 truncate min-w-0">
{preferences.homeBackground} {preferences.homeBackground}
</span> </span>
</div> </div>
) : ( ) : (
<span className="text-gray-400">Par défaut</span> <span className="text-gray-400 text-sm sm:text-base">
Par défaut
</span>
)} )}
</div> </div>
<div className="flex items-center gap-4"> <div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
<span className="text-pixel-gold font-bold min-w-[120px]"> <span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
Events: Events:
</span> </span>
{preferences?.eventsBackground ? ( {preferences?.eventsBackground ? (
<div className="flex items-center gap-3"> <div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
<img <img
src={preferences.eventsBackground} src={preferences.eventsBackground}
alt="Events background" alt="Events background"
className="w-20 h-12 object-cover rounded border border-pixel-gold/30" className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
onError={(e) => { onError={(e) => {
e.currentTarget.src = "/got-2.jpg"; e.currentTarget.src = "/got-2.jpg";
}} }}
/> />
<span className="text-xs text-gray-400 truncate max-w-xs"> <span className="text-xs text-gray-400 truncate min-w-0">
{preferences.eventsBackground} {preferences.eventsBackground}
</span> </span>
</div> </div>
) : ( ) : (
<span className="text-gray-400">Par défaut</span> <span className="text-gray-400 text-sm sm:text-base">
Par défaut
</span>
)} )}
</div> </div>
<div className="flex items-center gap-4"> <div className="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4">
<span className="text-pixel-gold font-bold min-w-[120px]"> <span className="text-pixel-gold font-bold text-sm sm:text-base min-w-0 sm:min-w-[120px] flex-shrink-0">
Leaderboard: Leaderboard:
</span> </span>
{preferences?.leaderboardBackground ? ( {preferences?.leaderboardBackground ? (
<div className="flex items-center gap-3"> <div className="flex items-center gap-2 sm:gap-3 min-w-0 flex-1">
<img <img
src={preferences.leaderboardBackground} src={preferences.leaderboardBackground}
alt="Leaderboard background" alt="Leaderboard background"
className="w-20 h-12 object-cover rounded border border-pixel-gold/30" className="w-16 h-10 sm:w-20 sm:h-12 object-cover rounded border border-pixel-gold/30 flex-shrink-0"
onError={(e) => { onError={(e) => {
e.currentTarget.src = "/got-2.jpg"; e.currentTarget.src = "/got-2.jpg";
}} }}
/> />
<span className="text-xs text-gray-400 truncate max-w-xs"> <span className="text-xs text-gray-400 truncate min-w-0">
{preferences.leaderboardBackground} {preferences.leaderboardBackground}
</span> </span>
</div> </div>
) : ( ) : (
<span className="text-gray-400">Par défaut</span> <span className="text-gray-400 text-sm sm:text-base">
Par défaut
</span>
)} )}
</div> </div>
</div> </div>
@@ -269,7 +322,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
)} )}
{activeSection === "users" && ( {activeSection === "users" && (
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm"> <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"> <h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
Gestion des Utilisateurs Gestion des Utilisateurs
</h2> </h2>
@@ -278,7 +331,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
)} )}
{activeSection === "events" && ( {activeSection === "events" && (
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm"> <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"> <h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
Gestion des Événements Gestion des Événements
</h2> </h2>
@@ -287,7 +340,7 @@ export default function AdminPanel({ initialPreferences }: AdminPanelProps) {
)} )}
{activeSection === "feedbacks" && ( {activeSection === "feedbacks" && (
<div className="bg-black/80 border border-pixel-gold/30 rounded-lg p-6 backdrop-blur-sm"> <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"> <h2 className="text-2xl font-gaming font-bold mb-6 text-pixel-gold">
Gestion des Feedbacks Gestion des Feedbacks
</h2> </h2>

View File

@@ -213,14 +213,14 @@ export default function EventManagement() {
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<div className="flex justify-between items-center mb-4"> <div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-4">
<h3 className="text-xl font-gaming font-bold text-pixel-gold"> <h3 className="text-lg sm:text-xl font-gaming font-bold text-pixel-gold break-words">
Événements ({events.length}) Événements ({events.length})
</h3> </h3>
{!isCreating && !editingEvent && ( {!isCreating && !editingEvent && (
<button <button
onClick={handleCreate} onClick={handleCreate}
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" className="px-3 sm:px-4 py-2 border border-green-500/50 bg-green-900/20 text-green-400 uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-green-900/30 transition whitespace-nowrap flex-shrink-0"
> >
+ Nouvel événement + Nouvel événement
</button> </button>
@@ -228,24 +228,28 @@ export default function EventManagement() {
</div> </div>
{(isCreating || editingEvent) && ( {(isCreating || editingEvent) && (
<div className="bg-black/60 border border-pixel-gold/20 rounded p-4 mb-4"> <div className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4 mb-4">
<h4 className="text-pixel-gold font-bold mb-4"> <h4 className="text-pixel-gold font-bold mb-4 text-base sm:text-lg break-words">
{isCreating ? "Créer un événement" : "Modifier l'événement"} {isCreating ? "Créer un événement" : "Modifier l'événement"}
</h4> </h4>
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<label className="block text-sm text-gray-300 mb-1">Date</label> <label className="block text-xs sm:text-sm text-gray-300 mb-1">
Date
</label>
<input <input
type="date" type="date"
value={formData.date} value={formData.date}
onChange={(e) => onChange={(e) =>
setFormData({ ...formData, date: e.target.value }) setFormData({ ...formData, date: e.target.value })
} }
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm" className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
/> />
</div> </div>
<div> <div>
<label className="block text-sm text-gray-300 mb-1">Nom</label> <label className="block text-xs sm:text-sm text-gray-300 mb-1">
Nom
</label>
<input <input
type="text" type="text"
value={formData.name} value={formData.name}
@@ -253,11 +257,11 @@ export default function EventManagement() {
setFormData({ ...formData, name: e.target.value }) setFormData({ ...formData, name: e.target.value })
} }
placeholder="Nom de l'événement" placeholder="Nom de l'événement"
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm" className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
/> />
</div> </div>
<div> <div>
<label className="block text-sm text-gray-300 mb-1"> <label className="block text-xs sm:text-sm text-gray-300 mb-1">
Description Description
</label> </label>
<textarea <textarea
@@ -267,12 +271,14 @@ export default function EventManagement() {
} }
placeholder="Description de l'événement" placeholder="Description de l'événement"
rows={4} rows={4}
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm" className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
/> />
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm text-gray-300 mb-1">Type</label> <label className="block text-xs sm:text-sm text-gray-300 mb-1">
Type
</label>
<select <select
value={formData.type} value={formData.type}
onChange={(e) => onChange={(e) =>
@@ -281,7 +287,7 @@ export default function EventManagement() {
type: e.target.value as Event["type"], type: e.target.value as Event["type"],
}) })
} }
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm" className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
> >
{eventTypes.map((type) => ( {eventTypes.map((type) => (
<option key={type} value={type}> <option key={type} value={type}>
@@ -291,9 +297,9 @@ export default function EventManagement() {
</select> </select>
</div> </div>
</div> </div>
<div className="grid grid-cols-3 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div> <div>
<label className="block text-sm text-gray-300 mb-1"> <label className="block text-xs sm:text-sm text-gray-300 mb-1">
Salle Salle
</label> </label>
<input <input
@@ -303,11 +309,11 @@ export default function EventManagement() {
setFormData({ ...formData, room: e.target.value }) setFormData({ ...formData, room: e.target.value })
} }
placeholder="Ex: Nautilus" placeholder="Ex: Nautilus"
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm" className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
/> />
</div> </div>
<div> <div>
<label className="block text-sm text-gray-300 mb-1"> <label className="block text-xs sm:text-sm text-gray-300 mb-1">
Heure Heure
</label> </label>
<input <input
@@ -317,11 +323,11 @@ export default function EventManagement() {
setFormData({ ...formData, time: e.target.value }) setFormData({ ...formData, time: e.target.value })
} }
placeholder="Ex: 11h-12h" placeholder="Ex: 11h-12h"
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm" className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
/> />
</div> </div>
<div> <div>
<label className="block text-sm text-gray-300 mb-1"> <label className="block text-xs sm:text-sm text-gray-300 mb-1">
Places max Places max
</label> </label>
<input <input
@@ -336,11 +342,11 @@ export default function EventManagement() {
}) })
} }
placeholder="Ex: 25" placeholder="Ex: 25"
className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm" className="w-full px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm"
/> />
</div> </div>
</div> </div>
<div className="flex gap-2"> <div className="flex flex-col sm:flex-row gap-2">
<button <button
onClick={handleSave} onClick={handleSave}
disabled={saving} disabled={saving}
@@ -368,19 +374,19 @@ export default function EventManagement() {
{events.map((event) => ( {events.map((event) => (
<div <div
key={event.id} key={event.id}
className="bg-black/60 border border-pixel-gold/20 rounded p-4" className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4"
> >
<div className="flex justify-between items-start"> <div className="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-3">
<div className="flex-1"> <div className="flex-1 min-w-0">
<div className="flex items-center gap-3 mb-2"> <div className="flex flex-wrap items-center gap-2 sm:gap-3 mb-2">
<h4 className="text-pixel-gold font-bold text-lg"> <h4 className="text-pixel-gold font-bold text-base sm:text-lg break-words">
{event.name} {event.name}
</h4> </h4>
<span className="px-2 py-1 bg-pixel-gold/20 border border-pixel-gold/50 text-pixel-gold text-xs uppercase rounded"> <span className="px-2 py-1 bg-pixel-gold/20 border border-pixel-gold/50 text-pixel-gold text-[10px] sm:text-xs uppercase rounded whitespace-nowrap flex-shrink-0">
{getEventTypeLabel(event.type)} {getEventTypeLabel(event.type)}
</span> </span>
<span <span
className={`px-2 py-1 text-xs uppercase rounded ${(() => { className={`px-2 py-1 text-[10px] sm:text-xs uppercase rounded whitespace-nowrap flex-shrink-0 ${(() => {
const status = calculateEventStatus(event.date); const status = calculateEventStatus(event.date);
return status === "UPCOMING" return status === "UPCOMING"
? "bg-green-900/50 border border-green-500/50 text-green-400" ? "bg-green-900/50 border border-green-500/50 text-green-400"
@@ -392,45 +398,45 @@ export default function EventManagement() {
{getStatusLabel(calculateEventStatus(event.date))} {getStatusLabel(calculateEventStatus(event.date))}
</span> </span>
</div> </div>
<p className="text-gray-400 text-sm mb-2"> <p className="text-gray-400 text-xs sm:text-sm mb-2 break-words">
{event.description} {event.description}
</p> </p>
<div className="flex flex-wrap items-center gap-4 mt-2"> <div className="flex flex-wrap items-center gap-2 sm:gap-4 mt-2">
<p className="text-gray-500 text-xs"> <p className="text-gray-500 text-[10px] sm:text-xs whitespace-nowrap">
Date: {new Date(event.date).toLocaleDateString("fr-FR")} Date: {new Date(event.date).toLocaleDateString("fr-FR")}
</p> </p>
{event.room && ( {event.room && (
<p className="text-gray-500 text-xs"> <p className="text-gray-500 text-[10px] sm:text-xs whitespace-nowrap">
📍 Salle: {event.room} 📍 Salle: {event.room}
</p> </p>
)} )}
{event.time && ( {event.time && (
<p className="text-gray-500 text-xs"> <p className="text-gray-500 text-[10px] sm:text-xs whitespace-nowrap">
🕐 Heure: {event.time} 🕐 Heure: {event.time}
</p> </p>
)} )}
{event.maxPlaces && ( {event.maxPlaces && (
<p className="text-gray-500 text-xs"> <p className="text-gray-500 text-[10px] sm:text-xs whitespace-nowrap">
👥 Places: {event.maxPlaces} 👥 Places: {event.maxPlaces}
</p> </p>
)} )}
<span className="px-2 py-1 bg-blue-900/30 border border-blue-500/50 text-blue-400 text-xs rounded"> <span className="px-2 py-1 bg-blue-900/30 border border-blue-500/50 text-blue-400 text-[10px] sm:text-xs rounded whitespace-nowrap flex-shrink-0">
{event.registrationsCount || 0} inscrit {event.registrationsCount || 0} inscrit
{event.registrationsCount !== 1 ? "s" : ""} {event.registrationsCount !== 1 ? "s" : ""}
</span> </span>
</div> </div>
</div> </div>
{!isCreating && !editingEvent && ( {!isCreating && !editingEvent && (
<div className="flex gap-2 ml-4"> <div className="flex gap-2 sm:ml-4 flex-shrink-0">
<button <button
onClick={() => handleEdit(event)} onClick={() => handleEdit(event)}
className="px-3 py-1 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition" className="px-2 sm:px-3 py-1 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"
> >
Modifier Modifier
</button> </button>
<button <button
onClick={() => handleDelete(event.id)} onClick={() => handleDelete(event.id)}
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-xs tracking-widest rounded hover:bg-red-900/30 transition" className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-red-900/30 transition whitespace-nowrap"
> >
Supprimer Supprimer
</button> </button>

View File

@@ -74,18 +74,20 @@ export default function FeedbackManagement() {
const renderStars = (rating: number) => { const renderStars = (rating: number) => {
return ( return (
<div className="flex items-center gap-1"> <div className="flex items-center gap-0.5 sm:gap-1">
{[1, 2, 3, 4, 5].map((star) => ( {[1, 2, 3, 4, 5].map((star) => (
<span <span
key={star} key={star}
className={`text-lg ${ className={`text-sm sm:text-lg ${
star <= rating ? "text-pixel-gold" : "text-gray-600" star <= rating ? "text-pixel-gold" : "text-gray-600"
}`} }`}
> >
</span> </span>
))} ))}
<span className="text-gray-400 text-sm ml-2">({rating}/5)</span> <span className="text-gray-400 text-xs sm:text-sm ml-1 sm:ml-2">
({rating}/5)
</span>
</div> </div>
); );
}; };
@@ -96,25 +98,25 @@ export default function FeedbackManagement() {
if (loading) { if (loading) {
return ( return (
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-8"> <div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-4 sm:p-8">
<p className="text-gray-400 text-center">Chargement...</p> <p className="text-gray-400 text-center text-sm">Chargement...</p>
</div> </div>
); );
} }
return ( return (
<div className="space-y-6"> <div className="space-y-4 sm:space-y-6">
{/* Statistiques par événement */} {/* Statistiques par événement */}
{statistics.length > 0 && ( {statistics.length > 0 && (
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-6"> <div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-3 sm:p-6">
<h3 className="text-pixel-gold font-bold text-lg mb-4"> <h3 className="text-pixel-gold font-bold text-base sm:text-lg mb-4 break-words">
Statistiques par événement Statistiques par événement
</h3> </h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4">
{statistics.map((stat) => ( {statistics.map((stat) => (
<div <div
key={stat.eventId} key={stat.eventId}
className={`bg-black/40 border rounded p-4 cursor-pointer transition ${ className={`bg-black/40 border rounded p-3 sm:p-4 cursor-pointer transition ${
selectedEvent === stat.eventId selectedEvent === stat.eventId
? "border-pixel-gold bg-pixel-gold/10" ? "border-pixel-gold bg-pixel-gold/10"
: "border-pixel-gold/30 hover:border-pixel-gold/50" : "border-pixel-gold/30 hover:border-pixel-gold/50"
@@ -125,21 +127,21 @@ export default function FeedbackManagement() {
) )
} }
> >
<div className="flex items-start justify-between mb-2"> <div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-2 mb-2">
<h4 className="text-white font-semibold text-sm"> <h4 className="text-white font-semibold text-xs sm:text-sm break-words">
{stat.eventName} {stat.eventName}
</h4> </h4>
<span className="text-pixel-gold text-xs uppercase"> <span className="text-pixel-gold text-[10px] sm:text-xs uppercase whitespace-nowrap flex-shrink-0">
{stat.eventType && getEventTypeLabel(stat.eventType)} {stat.eventType && getEventTypeLabel(stat.eventType)}
</span> </span>
</div> </div>
<div className="flex items-center gap-2 mb-2"> <div className="flex items-center gap-2 mb-2">
{renderStars(Math.round(stat.averageRating))} {renderStars(Math.round(stat.averageRating))}
</div> </div>
<div className="text-gray-400 text-xs"> <div className="text-gray-400 text-[10px] sm:text-xs">
Moyenne: {stat.averageRating.toFixed(2)}/5 Moyenne: {stat.averageRating.toFixed(2)}/5
</div> </div>
<div className="text-gray-400 text-xs"> <div className="text-gray-400 text-[10px] sm:text-xs">
{stat.feedbackCount} feedback {stat.feedbackCount} feedback
{stat.feedbackCount > 1 ? "s" : ""} {stat.feedbackCount > 1 ? "s" : ""}
</div> </div>
@@ -149,7 +151,7 @@ export default function FeedbackManagement() {
{selectedEvent && ( {selectedEvent && (
<button <button
onClick={() => setSelectedEvent(null)} onClick={() => setSelectedEvent(null)}
className="mt-4 text-pixel-gold text-sm hover:text-orange-400 transition" className="mt-4 text-pixel-gold text-xs sm:text-sm hover:text-orange-400 transition"
> >
Voir tous les feedbacks Voir tous les feedbacks
</button> </button>
@@ -158,8 +160,8 @@ export default function FeedbackManagement() {
)} )}
{/* Liste des feedbacks */} {/* Liste des feedbacks */}
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-6"> <div className="bg-black/60 border border-pixel-gold/30 rounded-lg p-3 sm:p-6">
<h3 className="text-pixel-gold font-bold text-lg mb-4"> <h3 className="text-pixel-gold font-bold text-base sm:text-lg mb-4 break-words">
{selectedEvent {selectedEvent
? `Feedbacks pour: ${ ? `Feedbacks pour: ${
statistics.find((s) => s.eventId === selectedEvent)?.eventName statistics.find((s) => s.eventId === selectedEvent)?.eventName
@@ -168,36 +170,36 @@ export default function FeedbackManagement() {
</h3> </h3>
{error && ( {error && (
<div className="bg-red-900/50 border border-red-500/50 text-red-400 px-4 py-3 rounded text-sm mb-4"> <div className="bg-red-900/50 border border-red-500/50 text-red-400 px-3 sm:px-4 py-2 sm:py-3 rounded text-xs sm:text-sm mb-4">
{error} {error}
</div> </div>
)} )}
{filteredFeedbacks.length === 0 ? ( {filteredFeedbacks.length === 0 ? (
<p className="text-gray-400 text-center py-8"> <p className="text-gray-400 text-center py-8 text-sm">
Aucun feedback pour le moment Aucun feedback pour le moment
</p> </p>
) : ( ) : (
<div className="space-y-4"> <div className="space-y-3 sm:space-y-4">
{filteredFeedbacks.map((feedback) => ( {filteredFeedbacks.map((feedback) => (
<div <div
key={feedback.id} key={feedback.id}
className="bg-black/40 border border-pixel-gold/20 rounded p-4" className="bg-black/40 border border-pixel-gold/20 rounded p-3 sm:p-4"
> >
<div className="flex items-start justify-between mb-3"> <div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-3">
<div className="flex-1"> <div className="flex-1 min-w-0">
<div className="flex items-center gap-3 mb-2"> <div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-3 mb-2">
<h4 className="text-white font-semibold"> <h4 className="text-white font-semibold text-sm sm:text-base break-words">
{feedback.user.username} {feedback.user.username}
</h4> </h4>
<span className="text-gray-500 text-xs"> <span className="text-gray-500 text-[10px] sm:text-xs break-all">
{feedback.user.email} {feedback.user.email}
</span> </span>
</div> </div>
<div className="text-pixel-gold text-sm font-semibold mb-2"> <div className="text-pixel-gold text-xs sm:text-sm font-semibold mb-2 break-words">
{feedback.event.name} {feedback.event.name}
</div> </div>
<div className="text-gray-500 text-xs mb-2"> <div className="text-gray-500 text-[10px] sm:text-xs mb-2">
{new Date(feedback.createdAt).toLocaleDateString( {new Date(feedback.createdAt).toLocaleDateString(
"fr-FR", "fr-FR",
{ {
@@ -210,11 +212,13 @@ export default function FeedbackManagement() {
)} )}
</div> </div>
</div> </div>
<div>{renderStars(feedback.rating)}</div> <div className="flex-shrink-0">
{renderStars(feedback.rating)}
</div>
</div> </div>
{feedback.comment && ( {feedback.comment && (
<div className="mt-3 pt-3 border-t border-pixel-gold/20"> <div className="mt-3 pt-3 border-t border-pixel-gold/20">
<p className="text-gray-300 text-sm whitespace-pre-wrap"> <p className="text-gray-300 text-xs sm:text-sm whitespace-pre-wrap break-words">
{feedback.comment} {feedback.comment}
</p> </p>
</div> </div>

View File

@@ -2,34 +2,9 @@
import { useBackgroundImage } from "@/hooks/usePreferences"; import { useBackgroundImage } from "@/hooks/usePreferences";
import Link from "next/link"; import Link from "next/link";
import { useState, useEffect, useRef } from "react";
export default function HeroSection() { export default function HeroSection() {
const backgroundImage = useBackgroundImage("home", "/got-2.jpg"); const backgroundImage = useBackgroundImage("home", "/got-2.jpg");
const titleRef = useRef<HTMLSpanElement>(null);
const [mousePosition, setMousePosition] = useState({ x: 50, y: 50 });
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
if (titleRef.current) {
const rect = titleRef.current.getBoundingClientRect();
const x = ((e.clientX - rect.left) / rect.width) * 100;
const y = ((e.clientY - rect.top) / rect.height) * 100;
setMousePosition({
x: Math.max(0, Math.min(100, x)),
y: Math.max(0, Math.min(100, y)),
});
}
};
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, []);
// Calculer la position du gradient basée sur la souris avec plus d'amplitude
const gradientPosition = mousePosition.x;
const glowIntensity = 12 + mousePosition.x / 5;
const glowOpacity = 0.4 + mousePosition.y / 250;
return ( return (
<section className="relative w-full min-h-screen flex flex-col items-center justify-center overflow-hidden pt-24"> <section className="relative w-full min-h-screen flex flex-col items-center justify-center overflow-hidden pt-24">
@@ -45,49 +20,24 @@ export default function HeroSection() {
</div> </div>
{/* Hero Content */} {/* Hero Content */}
<div className="relative z-10 w-full max-w-5xl xl:max-w-6xl mx-auto px-8 py-16 text-center flex flex-col items-center"> <div className="relative z-10 w-full max-w-5xl xl:max-w-6xl mx-auto px-4 sm:px-8 py-16 text-center flex flex-col items-center">
{/* Game Title */} {/* Game Title */}
<div className="w-full flex justify-center mb-4"> <div className="w-full flex justify-center mb-4 overflow-hidden">
<h1 className="text-6xl md:text-8xl lg:text-9xl xl:text-9xl font-gaming font-black tracking-tight relative"> <h1 className="text-4xl sm:text-5xl md:text-8xl lg:text-9xl xl:text-9xl font-gaming font-black tracking-tight relative break-words">
<span <span
ref={titleRef}
className="title-animated inline-block relative z-10" className="title-animated inline-block relative z-10"
style={{ style={{
backgroundImage: `linear-gradient(90deg, #daa520 0%, #ffa500 ${Math.max( backgroundImage: `linear-gradient(90deg, #daa520 0%, #ffa500 30%, #ff8c00 50%, #ffa500 70%, #daa520 100%)`,
10,
gradientPosition - 20
)}%, #ff8c00 ${gradientPosition}%, #ffa500 ${Math.min(
90,
gradientPosition + 20
)}%, #daa520 100%)`,
backgroundSize: "200% auto", backgroundSize: "200% auto",
WebkitBackgroundClip: "text", WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent", WebkitTextFillColor: "transparent",
backgroundClip: "text", backgroundClip: "text",
color: "transparent", color: "transparent",
transition: "background-image 0.15s ease-out", filter: `drop-shadow(0 0 12px rgba(255, 140, 0, 0.4))`,
filter: `drop-shadow(0 0 ${glowIntensity}px rgba(255, 140, 0, ${glowOpacity}))`,
}} }}
> >
GAME.OF.TECH GAME.OF.TECH
</span> </span>
{/* Glow effect qui suit la souris */}
<span
className="absolute inset-0 pointer-events-none"
style={{
backgroundImage: `linear-gradient(90deg, transparent 0%, rgba(255, 140, 0, 0.3) ${gradientPosition}%, transparent 100%)`,
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
backgroundClip: "text",
filter: `blur(${10 + mousePosition.x / 20}px)`,
opacity: 0.5,
zIndex: 0,
transition: "all 0.15s ease-out",
}}
aria-hidden="true"
>
GAME.OF.TECH
</span>
</h1> </h1>
</div> </div>

View File

@@ -76,13 +76,15 @@ export default function ImageSelector({
return ( return (
<div className="space-y-3"> <div className="space-y-3">
<label className="block text-sm text-gray-300 mb-1">{label}</label> <label className="block text-xs sm:text-sm text-gray-300 mb-1 break-words">
{label}
</label>
<div className="flex gap-4"> <div className="flex flex-col sm:flex-row gap-3 sm:gap-4">
{/* Colonne gauche - Image */} {/* Colonne gauche - Image */}
<div className="flex-shrink-0"> <div className="flex-shrink-0 flex justify-center sm:justify-start">
{value ? ( {value ? (
<div className="relative w-48 h-32 border border-pixel-gold/30 rounded overflow-hidden bg-black/60"> <div className="relative w-full sm:w-48 h-40 sm:h-32 border border-pixel-gold/30 rounded overflow-hidden bg-black/60">
<img <img
src={value} src={value}
alt="Preview" alt="Preview"
@@ -99,34 +101,34 @@ export default function ImageSelector({
</button> </button>
</div> </div>
) : ( ) : (
<div className="w-48 h-32 border border-pixel-gold/30 rounded bg-black/60 flex items-center justify-center"> <div className="w-full sm:w-48 h-40 sm:h-32 border border-pixel-gold/30 rounded bg-black/60 flex items-center justify-center">
<span className="text-xs text-gray-500">Aucune</span> <span className="text-xs text-gray-500">Aucune</span>
</div> </div>
)} )}
</div> </div>
{/* Colonne droite - Contrôles */} {/* Colonne droite - Contrôles */}
<div className="flex-1 space-y-3"> <div className="flex-1 space-y-3 min-w-0">
{/* Input URL */} {/* Input URL */}
<div className="flex gap-2"> <div className="flex flex-col sm:flex-row gap-2">
<input <input
type="text" type="text"
value={urlInput} value={urlInput}
onChange={(e) => setUrlInput(e.target.value)} onChange={(e) => setUrlInput(e.target.value)}
onKeyPress={(e) => e.key === "Enter" && handleUrlSubmit()} onKeyPress={(e) => e.key === "Enter" && handleUrlSubmit()}
placeholder="https://example.com/image.jpg ou /image.jpg" placeholder="https://example.com/image.jpg ou /image.jpg"
className="flex-1 px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm" className="flex-1 px-3 py-2 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm min-w-0"
/> />
<button <button
onClick={handleUrlSubmit} onClick={handleUrlSubmit}
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" 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"
> >
URL URL
</button> </button>
</div> </div>
{/* Upload depuis le disque */} {/* Upload depuis le disque */}
<div className="flex gap-2"> <div className="flex flex-col sm:flex-row gap-2">
<input <input
ref={fileInputRef} ref={fileInputRef}
type="file" type="file"
@@ -137,7 +139,7 @@ export default function ImageSelector({
/> />
<label <label
htmlFor={`file-${label}`} htmlFor={`file-${label}`}
className={`flex-1 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 text-center cursor-pointer ${ className={`flex-1 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 text-center cursor-pointer ${
uploading ? "opacity-50 cursor-not-allowed" : "" uploading ? "opacity-50 cursor-not-allowed" : ""
}`} }`}
> >
@@ -145,22 +147,26 @@ export default function ImageSelector({
</label> </label>
<button <button
onClick={() => setShowGallery(!showGallery)} onClick={() => setShowGallery(!showGallery)}
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" 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"
> >
{showGallery ? "Masquer" : "Galerie"} {showGallery ? "Masquer" : "Galerie"}
</button> </button>
</div> </div>
{/* Chemin de l'image */} {/* Chemin de l'image */}
{value && <p className="text-xs text-gray-400 truncate">{value}</p>} {value && (
<p className="text-xs text-gray-400 truncate break-all">{value}</p>
)}
</div> </div>
</div> </div>
{/* Galerie d'images */} {/* Galerie d'images */}
{showGallery && ( {showGallery && (
<div className="mt-4 p-4 bg-black/40 border border-pixel-gold/20 rounded"> <div className="mt-4 p-3 sm:p-4 bg-black/40 border border-pixel-gold/20 rounded">
<h4 className="text-sm text-gray-300 mb-3">Images disponibles</h4> <h4 className="text-xs sm:text-sm text-gray-300 mb-3">
<div className="grid grid-cols-3 md:grid-cols-4 gap-3 max-h-64 overflow-y-auto"> Images disponibles
</h4>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2 sm:gap-3 max-h-64 overflow-y-auto">
{availableImages.length === 0 ? ( {availableImages.length === 0 ? (
<div className="col-span-full text-center text-gray-400 text-sm py-4"> <div className="col-span-full text-center text-gray-400 text-sm py-4">
Aucune image disponible Aucune image disponible

View File

@@ -45,10 +45,10 @@ export default function LeaderboardSection({
</div> </div>
{/* Content */} {/* Content */}
<div className="relative z-10 w-full max-w-6xl mx-auto px-8 py-16"> <div className="relative z-10 w-full max-w-6xl mx-auto px-4 sm:px-8 py-16">
{/* Title Section */} {/* Title Section */}
<div className="text-center mb-12"> <div className="text-center mb-12 overflow-hidden">
<h1 className="text-5xl md:text-7xl font-gaming font-black mb-4 tracking-tight"> <h1 className="text-3xl sm:text-4xl md:text-7xl font-gaming font-black mb-4 tracking-tight break-words">
<span <span
className="bg-gradient-to-r from-pixel-gold via-orange-400 to-pixel-gold bg-clip-text text-transparent" className="bg-gradient-to-r from-pixel-gold via-orange-400 to-pixel-gold bg-clip-text text-transparent"
style={{ style={{
@@ -66,11 +66,11 @@ export default function LeaderboardSection({
</div> </div>
{/* Leaderboard Table */} {/* Leaderboard Table */}
<div className="bg-black/60 border border-pixel-gold/30 rounded-lg backdrop-blur-sm"> <div className="bg-black/60 border border-pixel-gold/30 rounded-lg backdrop-blur-sm overflow-x-auto">
{/* Header */} {/* Header */}
<div className="bg-gray-900/80 border-b border-pixel-gold/30 grid grid-cols-12 gap-4 p-4 font-bold text-xs uppercase tracking-widest text-gray-300"> <div className="bg-gray-900/80 border-b border-pixel-gold/30 grid grid-cols-12 gap-2 sm:gap-4 p-2 sm:p-4 font-bold text-[10px] sm:text-xs uppercase tracking-widest text-gray-300">
<div className="col-span-1 text-center">Rank</div> <div className="col-span-2 sm:col-span-1 text-center">Rank</div>
<div className="col-span-6">Player</div> <div className="col-span-5 sm:col-span-6">Player</div>
<div className="col-span-3 text-right">Score</div> <div className="col-span-3 text-right">Score</div>
<div className="col-span-2 text-right">Level</div> <div className="col-span-2 text-right">Level</div>
</div> </div>
@@ -80,16 +80,16 @@ export default function LeaderboardSection({
{leaderboard.map((entry) => ( {leaderboard.map((entry) => (
<div <div
key={entry.rank} key={entry.rank}
className={`grid grid-cols-12 gap-4 p-4 hover:bg-gray-900/50 transition relative ${ className={`grid grid-cols-12 gap-2 sm:gap-4 p-2 sm:p-4 hover:bg-gray-900/50 transition relative ${
entry.rank <= 3 entry.rank <= 3
? "bg-gradient-to-r from-pixel-gold/10 via-pixel-gold/5 to-transparent" ? "bg-gradient-to-r from-pixel-gold/10 via-pixel-gold/5 to-transparent"
: "bg-black/40" : "bg-black/40"
}`} }`}
> >
{/* Rank */} {/* Rank */}
<div className="col-span-1 flex items-center justify-center"> <div className="col-span-2 sm:col-span-1 flex items-center justify-center">
<span <span
className={`inline-flex items-center justify-center w-10 h-10 rounded-full font-bold text-sm ${ className={`inline-flex items-center justify-center w-8 h-8 sm:w-10 sm:h-10 rounded-full font-bold text-xs sm:text-sm ${
entry.rank === 1 entry.rank === 1
? "bg-gradient-to-br from-pixel-gold to-orange-500 text-black shadow-lg shadow-pixel-gold/50" ? "bg-gradient-to-br from-pixel-gold to-orange-500 text-black shadow-lg shadow-pixel-gold/50"
: entry.rank === 2 : entry.rank === 2
@@ -104,9 +104,9 @@ export default function LeaderboardSection({
</div> </div>
{/* Player */} {/* Player */}
<div className="col-span-6 flex items-center gap-3"> <div className="col-span-5 sm:col-span-6 flex items-center gap-2 sm:gap-3 min-w-0">
{entry.avatar ? ( {entry.avatar ? (
<div className="w-10 h-10 rounded-full border border-pixel-gold/30 overflow-hidden"> <div className="w-8 h-8 sm:w-10 sm:h-10 rounded-full border border-pixel-gold/30 overflow-hidden flex-shrink-0">
<img <img
src={entry.avatar} src={entry.avatar}
alt={entry.username} alt={entry.username}
@@ -114,18 +114,18 @@ export default function LeaderboardSection({
/> />
</div> </div>
) : ( ) : (
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-gray-800 to-gray-900 border border-pixel-gold/30 flex items-center justify-center"> <div className="w-8 h-8 sm:w-10 sm:h-10 rounded-full bg-gradient-to-br from-gray-800 to-gray-900 border border-pixel-gold/30 flex items-center justify-center flex-shrink-0">
<span className="text-pixel-gold text-xs font-bold"> <span className="text-pixel-gold text-[10px] sm:text-xs font-bold">
{entry.username.charAt(0).toUpperCase()} {entry.username.charAt(0).toUpperCase()}
</span> </span>
</div> </div>
)} )}
<div <div
className="flex items-center gap-2 cursor-pointer hover:opacity-80 transition" className="flex items-center gap-1 sm:gap-2 cursor-pointer hover:opacity-80 transition min-w-0"
onClick={() => setSelectedEntry(entry)} onClick={() => setSelectedEntry(entry)}
> >
<span <span
className={`font-bold ${ className={`font-bold text-xs sm:text-sm truncate ${
entry.rank <= 3 ? "text-pixel-gold" : "text-white" entry.rank <= 3 ? "text-pixel-gold" : "text-white"
}`} }`}
> >
@@ -153,14 +153,14 @@ export default function LeaderboardSection({
{/* Score */} {/* Score */}
<div className="col-span-3 flex items-center justify-end"> <div className="col-span-3 flex items-center justify-end">
<span className="font-mono text-gray-300"> <span className="font-mono text-gray-300 text-xs sm:text-sm">
{formatScore(entry.score)} {formatScore(entry.score)}
</span> </span>
</div> </div>
{/* Level */} {/* Level */}
<div className="col-span-2 flex items-center justify-end"> <div className="col-span-2 flex items-center justify-end">
<span className="font-bold text-gray-400"> <span className="font-bold text-gray-400 text-xs sm:text-sm">
Lv.{entry.level} Lv.{entry.level}
</span> </span>
</div> </div>
@@ -190,10 +190,10 @@ export default function LeaderboardSection({
className="bg-black border-2 border-pixel-gold/70 rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto shadow-2xl" className="bg-black border-2 border-pixel-gold/70 rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto shadow-2xl"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<div className="p-8"> <div className="p-4 sm:p-8">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between mb-6"> <div className="flex items-center justify-between mb-6">
<h2 className="text-3xl font-bold text-pixel-gold uppercase tracking-wider"> <h2 className="text-xl sm:text-3xl font-bold text-pixel-gold uppercase tracking-wider break-words">
{selectedEntry.username} {selectedEntry.username}
</h2> </h2>
<button <button
@@ -205,9 +205,9 @@ export default function LeaderboardSection({
</div> </div>
{/* Avatar and Class */} {/* Avatar and Class */}
<div className="flex items-center gap-6 mb-6"> <div className="flex items-center gap-4 sm:gap-6 mb-6">
{selectedEntry.avatar ? ( {selectedEntry.avatar ? (
<div className="w-24 h-24 rounded-full border-4 border-pixel-gold/50 overflow-hidden"> <div className="w-16 h-16 sm:w-24 sm:h-24 rounded-full border-2 sm:border-4 border-pixel-gold/50 overflow-hidden flex-shrink-0">
<img <img
src={selectedEntry.avatar} src={selectedEntry.avatar}
alt={selectedEntry.username} alt={selectedEntry.username}
@@ -215,8 +215,8 @@ export default function LeaderboardSection({
/> />
</div> </div>
) : ( ) : (
<div className="w-24 h-24 rounded-full border-4 border-pixel-gold/50 bg-gray-900 flex items-center justify-center"> <div className="w-16 h-16 sm:w-24 sm:h-24 rounded-full border-2 sm:border-4 border-pixel-gold/50 bg-gray-900 flex items-center justify-center flex-shrink-0">
<span className="text-pixel-gold text-4xl font-bold"> <span className="text-pixel-gold text-2xl sm:text-4xl font-bold">
{selectedEntry.username.charAt(0).toUpperCase()} {selectedEntry.username.charAt(0).toUpperCase()}
</span> </span>
</div> </div>

View File

@@ -2,6 +2,8 @@
import Link from "next/link"; import Link from "next/link";
import { useSession, signOut } from "next-auth/react"; import { useSession, signOut } from "next-auth/react";
import { useState } from "react";
import { usePathname } from "next/navigation";
import PlayerStats from "./PlayerStats"; import PlayerStats from "./PlayerStats";
interface UserData { interface UserData {
@@ -24,29 +26,37 @@ export default function Navigation({
initialIsAdmin, initialIsAdmin,
}: NavigationProps) { }: NavigationProps) {
const { data: session } = useSession(); const { data: session } = useSession();
const [isMenuOpen, setIsMenuOpen] = useState(false);
const pathname = usePathname();
// Ne pas afficher le profil sur les pages login/register
const isAuthPage = pathname === "/login" || pathname === "/register";
// Utiliser initialUserData pour déterminer l'état de connexion pendant l'hydratation // Utiliser initialUserData pour déterminer l'état de connexion pendant l'hydratation
// Cela évite le clignottement au reload // Cela évite le clignottement au reload
const isAuthenticated = initialUserData !== null || session !== null; // Vérifier explicitement que initialUserData n'est pas undefined
const isAuthenticated =
(initialUserData !== undefined && initialUserData !== null) ||
session !== null;
const isAdmin = initialIsAdmin ?? session?.user?.role === "ADMIN"; const isAdmin = initialIsAdmin ?? session?.user?.role === "ADMIN";
return ( return (
<nav className="w-full fixed top-0 left-0 z-50 px-8 py-3 bg-black/80 backdrop-blur-sm border-b border-gray-800/30"> <nav className="w-full fixed top-0 left-0 z-50 px-4 sm:px-8 py-3 bg-black/80 backdrop-blur-sm border-b border-gray-800/30">
<div className="max-w-7xl mx-auto flex items-center justify-between"> <div className="max-w-7xl mx-auto flex items-center justify-between">
{/* Logo - Left */} {/* Logo - Left */}
<div className="flex flex-col"> <div className="flex flex-col">
<div className="text-white text-xl font-gaming font-bold tracking-tight"> <div className="text-white text-lg sm:text-xl font-gaming font-bold tracking-tight">
GAME.OF.TECH GAME.OF.TECH
</div> </div>
<div className="text-pixel-gold text-xs font-gaming-subtitle font-semibold flex items-center gap-1 tracking-wide"> <div className="text-pixel-gold text-[10px] sm:text-xs font-gaming-subtitle font-semibold flex items-center gap-1 tracking-wide">
<span></span> <span></span>
<span>Peaksys</span> <span>Peaksys</span>
<span></span> <span></span>
</div> </div>
</div> </div>
{/* Navigation Links - Center */} {/* Navigation Links - Center (Desktop) */}
<div className="flex items-center gap-6"> <div className="hidden md:flex items-center gap-6">
<Link <Link
href="/" href="/"
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest" className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest"
@@ -76,35 +86,145 @@ export default function Navigation({
</div> </div>
{/* Right Side */} {/* Right Side */}
<div className="flex items-center gap-4"> <div className="flex items-center gap-2 sm:gap-4">
{isAuthenticated ? ( {/* PlayerStats - Hidden on mobile */}
<> {isAuthenticated && !isAuthPage && (
<div className="hidden lg:block">
<PlayerStats initialUserData={initialUserData} /> <PlayerStats initialUserData={initialUserData} />
</div>
)}
{/* Desktop Auth Buttons */}
<div className="hidden md:flex items-center gap-4">
{isAuthenticated ? (
<button <button
onClick={() => signOut()} onClick={() => signOut()}
className="text-gray-400 hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest" className="text-gray-400 hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest"
> >
Déconnexion Déconnexion
</button> </button>
</> ) : (
) : ( <>
<> <Link
<Link href="/login"
href="/login" className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest"
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest" >
> Connexion
Connexion </Link>
</Link> <Link
<Link href="/register"
href="/register" 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 hover:border-pixel-gold transition"
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 hover:border-pixel-gold transition" >
> Inscription
Inscription </Link>
</Link> </>
</> )}
)} </div>
{/* Mobile Menu Button */}
<button
onClick={() => setIsMenuOpen(!isMenuOpen)}
className="md:hidden text-white hover:text-pixel-gold transition p-2"
aria-label="Toggle menu"
>
<svg
className="w-6 h-6"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
stroke="currentColor"
>
{isMenuOpen ? (
<path d="M6 18L18 6M6 6l12 12" />
) : (
<path d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
</button>
</div> </div>
</div> </div>
{/* Mobile Menu */}
{isMenuOpen && (
<div className="md:hidden absolute top-full left-0 w-full bg-black/95 backdrop-blur-sm border-b border-gray-800/30">
<div className="px-4 py-4 flex flex-col gap-4">
{/* Mobile Navigation Links */}
<div className="flex flex-col gap-3">
<Link
href="/"
onClick={() => setIsMenuOpen(false)}
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest py-2"
>
HOME
</Link>
<Link
href="/events"
onClick={() => setIsMenuOpen(false)}
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest py-2"
>
EVENTS
</Link>
<Link
href="/leaderboard"
onClick={() => setIsMenuOpen(false)}
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest py-2"
>
LEADERBOARD
</Link>
{isAdmin && (
<Link
href="/admin"
onClick={() => setIsMenuOpen(false)}
className="text-pixel-gold hover:text-orange-400 transition text-xs font-normal uppercase tracking-widest py-2"
>
ADMIN
</Link>
)}
</div>
{/* Mobile PlayerStats */}
{isAuthenticated && !isAuthPage && (
<div className="lg:hidden pt-2 border-t border-gray-800/30">
<PlayerStats initialUserData={initialUserData} />
</div>
)}
{/* Mobile Auth Buttons */}
<div className="flex flex-col gap-3 pt-2 border-t border-gray-800/30">
{isAuthenticated ? (
<button
onClick={() => {
signOut();
setIsMenuOpen(false);
}}
className="text-gray-400 hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest text-left py-2"
>
Déconnexion
</button>
) : (
<>
<Link
href="/login"
onClick={() => setIsMenuOpen(false)}
className="text-white hover:text-pixel-gold transition text-xs font-normal uppercase tracking-widest py-2"
>
Connexion
</Link>
<Link
href="/register"
onClick={() => setIsMenuOpen(false)}
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 hover:border-pixel-gold transition text-center"
>
Inscription
</Link>
</>
)}
</div>
</div>
</div>
)}
</nav> </nav>
); );
} }

View File

@@ -156,7 +156,7 @@ export default function PlayerStats({ initialUserData }: PlayerStatsProps) {
</Link> </Link>
{/* Stats */} {/* Stats */}
<div className="flex flex-col gap-1.5 min-w-[200px]"> <div className="flex flex-col gap-1.5 min-w-[180px] sm:min-w-[200px]">
{/* Username & Level */} {/* Username & Level */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Link <Link

View File

@@ -174,12 +174,12 @@ export default function UserManagement() {
return ( return (
<div <div
key={user.id} key={user.id}
className="bg-black/60 border border-pixel-gold/20 rounded p-3" className="bg-black/60 border border-pixel-gold/20 rounded p-3 sm:p-4"
> >
<div className="flex justify-between items-center mb-2"> <div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-2">
<div className="flex gap-3 items-center flex-1 min-w-0"> <div className="flex gap-2 sm:gap-3 items-center flex-1 min-w-0">
{/* Avatar */} {/* Avatar */}
<div className="w-10 h-10 rounded-full border-2 border-pixel-gold/50 overflow-hidden bg-black/60 flex-shrink-0"> <div className="w-8 h-8 sm:w-10 sm:h-10 rounded-full border-2 border-pixel-gold/50 overflow-hidden bg-black/60 flex-shrink-0">
{user.avatar ? ( {user.avatar ? (
<img <img
src={user.avatar} src={user.avatar}
@@ -194,7 +194,7 @@ export default function UserManagement() {
/> />
) : null} ) : null}
<div <div
className={`w-full h-full flex items-center justify-center text-pixel-gold text-sm font-bold ${ className={`w-full h-full flex items-center justify-center text-pixel-gold text-xs sm:text-sm font-bold ${
user.avatar ? "hidden" : "" user.avatar ? "hidden" : ""
}`} }`}
> >
@@ -202,18 +202,18 @@ export default function UserManagement() {
</div> </div>
</div> </div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap"> <div className="flex items-center gap-1.5 sm:gap-2 flex-wrap">
<h3 className="text-pixel-gold font-bold text-base"> <h3 className="text-pixel-gold font-bold text-sm sm:text-base break-words">
{user.username} {user.username}
</h3> </h3>
<span className="text-xs text-gray-500"> <span className="text-[10px] sm:text-xs text-gray-500 whitespace-nowrap">
Niveau {user.level} Niveau {user.level}
</span> </span>
<span className="text-xs text-gray-500"> <span className="text-[10px] sm:text-xs text-gray-500 whitespace-nowrap">
Score: {formatNumber(user.score)} Score: {formatNumber(user.score)}
</span> </span>
<span <span
className={`text-xs ${ className={`text-[10px] sm:text-xs whitespace-nowrap ${
user.role === "ADMIN" user.role === "ADMIN"
? "text-pixel-gold" ? "text-pixel-gold"
: "text-gray-500" : "text-gray-500"
@@ -222,23 +222,23 @@ export default function UserManagement() {
{user.role} {user.role}
</span> </span>
</div> </div>
<p className="text-gray-400 text-xs truncate"> <p className="text-gray-400 text-[10px] sm:text-xs truncate">
{user.email} {user.email}
</p> </p>
</div> </div>
</div> </div>
{!isEditing && ( {!isEditing && (
<div className="flex gap-2 flex-shrink-0 ml-2"> <div className="flex gap-2 flex-shrink-0 sm:ml-2">
<button <button
onClick={() => handleEdit(user)} onClick={() => handleEdit(user)}
className="px-3 py-1.5 border border-pixel-gold/50 bg-black/60 text-white uppercase text-xs tracking-widest rounded hover:bg-pixel-gold/10 transition" className="px-2 sm:px-3 py-1.5 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"
> >
Modifier Modifier
</button> </button>
<button <button
onClick={() => handleDelete(user.id)} onClick={() => handleDelete(user.id)}
disabled={deletingUserId === user.id} disabled={deletingUserId === user.id}
className="px-3 py-1.5 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-xs tracking-widest rounded hover:bg-red-900/30 transition disabled:opacity-50" className="px-2 sm:px-3 py-1.5 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-[10px] sm:text-xs tracking-widest rounded hover:bg-red-900/30 transition disabled:opacity-50 whitespace-nowrap"
> >
{deletingUserId === user.id {deletingUserId === user.id
? "Suppression..." ? "Suppression..."
@@ -253,14 +253,14 @@ export default function UserManagement() {
{/* HP Section */} {/* HP Section */}
<div> <div>
<div className="flex justify-between items-center mb-2"> <div className="flex justify-between items-center mb-2">
<label className="text-sm text-gray-300"> <label className="text-xs sm:text-sm text-gray-300">
Points de Vie (HP) Points de Vie (HP)
</label> </label>
<span className="text-xs text-gray-400"> <span className="text-[10px] sm:text-xs text-gray-400">
{previewHp} / {user.maxHp} {previewHp} / {user.maxHp}
</span> </span>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-1 sm:gap-2 flex-wrap">
<button <button
onClick={() => onClick={() =>
setEditingUser({ setEditingUser({
@@ -268,7 +268,7 @@ export default function UserManagement() {
hpDelta: editingUser.hpDelta - 100, hpDelta: editingUser.hpDelta - 100,
}) })
} }
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition" className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
> >
-100 -100
</button> </button>
@@ -279,7 +279,7 @@ export default function UserManagement() {
hpDelta: editingUser.hpDelta - 10, hpDelta: editingUser.hpDelta - 10,
}) })
} }
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition" className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
> >
-10 -10
</button> </button>
@@ -292,7 +292,7 @@ export default function UserManagement() {
hpDelta: parseInt(e.target.value) || 0, hpDelta: parseInt(e.target.value) || 0,
}) })
} }
className="flex-1 px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm text-center" className="flex-1 min-w-[60px] px-2 sm:px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm text-center"
/> />
<button <button
onClick={() => onClick={() =>
@@ -301,7 +301,7 @@ export default function UserManagement() {
hpDelta: editingUser.hpDelta + 10, hpDelta: editingUser.hpDelta + 10,
}) })
} }
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition" className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
> >
+10 +10
</button> </button>
@@ -312,7 +312,7 @@ export default function UserManagement() {
hpDelta: editingUser.hpDelta + 100, hpDelta: editingUser.hpDelta + 100,
}) })
} }
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition" className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
> >
+100 +100
</button> </button>
@@ -333,14 +333,14 @@ export default function UserManagement() {
{/* XP Section */} {/* XP Section */}
<div> <div>
<div className="flex justify-between items-center mb-2"> <div className="flex justify-between items-center mb-2">
<label className="text-sm text-gray-300"> <label className="text-xs sm:text-sm text-gray-300">
Expérience (XP) Expérience (XP)
</label> </label>
<span className="text-xs text-gray-400"> <span className="text-[10px] sm:text-xs text-gray-400">
{formatNumber(previewXp)} / {formatNumber(user.maxXp)} {formatNumber(previewXp)} / {formatNumber(user.maxXp)}
</span> </span>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-1 sm:gap-2 flex-wrap">
<button <button
onClick={() => onClick={() =>
setEditingUser({ setEditingUser({
@@ -348,7 +348,7 @@ export default function UserManagement() {
xpDelta: editingUser.xpDelta - 1000, xpDelta: editingUser.xpDelta - 1000,
}) })
} }
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition" className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
> >
-1000 -1000
</button> </button>
@@ -359,7 +359,7 @@ export default function UserManagement() {
xpDelta: editingUser.xpDelta - 100, xpDelta: editingUser.xpDelta - 100,
}) })
} }
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition" className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
> >
-100 -100
</button> </button>
@@ -372,7 +372,7 @@ export default function UserManagement() {
xpDelta: parseInt(e.target.value) || 0, xpDelta: parseInt(e.target.value) || 0,
}) })
} }
className="flex-1 px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm text-center" className="flex-1 min-w-[60px] px-2 sm:px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm text-center"
/> />
<button <button
onClick={() => onClick={() =>
@@ -381,7 +381,7 @@ export default function UserManagement() {
xpDelta: editingUser.xpDelta + 100, xpDelta: editingUser.xpDelta + 100,
}) })
} }
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition" className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
> >
+100 +100
</button> </button>
@@ -392,7 +392,7 @@ export default function UserManagement() {
xpDelta: editingUser.xpDelta + 1000, xpDelta: editingUser.xpDelta + 1000,
}) })
} }
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition" className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
> >
+1000 +1000
</button> </button>
@@ -412,10 +412,10 @@ export default function UserManagement() {
{/* Score Section */} {/* Score Section */}
<div> <div>
<label className="block text-sm text-gray-300 mb-2"> <label className="block text-xs sm:text-sm text-gray-300 mb-2">
Score Score
</label> </label>
<div className="flex gap-2"> <div className="flex gap-1 sm:gap-2 flex-wrap">
<button <button
onClick={() => onClick={() =>
setEditingUser({ setEditingUser({
@@ -423,7 +423,7 @@ export default function UserManagement() {
score: (editingUser.score || 0) - 1000, score: (editingUser.score || 0) - 1000,
}) })
} }
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition" className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
> >
-1000 -1000
</button> </button>
@@ -434,7 +434,7 @@ export default function UserManagement() {
score: (editingUser.score || 0) - 100, score: (editingUser.score || 0) - 100,
}) })
} }
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition" className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
> >
-100 -100
</button> </button>
@@ -447,7 +447,7 @@ export default function UserManagement() {
score: parseInt(e.target.value) || 0, score: parseInt(e.target.value) || 0,
}) })
} }
className="flex-1 px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm text-center" className="flex-1 min-w-[60px] px-2 sm:px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm text-center"
/> />
<button <button
onClick={() => onClick={() =>
@@ -456,7 +456,7 @@ export default function UserManagement() {
score: (editingUser.score || 0) + 100, score: (editingUser.score || 0) + 100,
}) })
} }
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition" className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
> >
+100 +100
</button> </button>
@@ -467,7 +467,7 @@ export default function UserManagement() {
score: (editingUser.score || 0) + 1000, score: (editingUser.score || 0) + 1000,
}) })
} }
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition" className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
> >
+1000 +1000
</button> </button>
@@ -476,10 +476,10 @@ export default function UserManagement() {
{/* Level Section */} {/* Level Section */}
<div> <div>
<label className="block text-sm text-gray-300 mb-2"> <label className="block text-xs sm:text-sm text-gray-300 mb-2">
Niveau Niveau
</label> </label>
<div className="flex gap-2"> <div className="flex gap-1 sm:gap-2">
<button <button
onClick={() => onClick={() =>
setEditingUser({ setEditingUser({
@@ -487,7 +487,7 @@ export default function UserManagement() {
level: Math.max(1, (editingUser.level || 1) - 1), level: Math.max(1, (editingUser.level || 1) - 1),
}) })
} }
className="px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-xs rounded hover:bg-red-900/30 transition" className="px-2 sm:px-3 py-1 border border-red-500/50 bg-red-900/20 text-red-400 text-[10px] sm:text-xs rounded hover:bg-red-900/30 transition flex-shrink-0"
> >
-1 -1
</button> </button>
@@ -501,7 +501,7 @@ export default function UserManagement() {
level: Math.max(1, parseInt(e.target.value) || 1), level: Math.max(1, parseInt(e.target.value) || 1),
}) })
} }
className="flex-1 px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-sm text-center" className="flex-1 min-w-[60px] px-2 sm:px-3 py-1 bg-black/60 border border-pixel-gold/30 rounded text-white text-xs sm:text-sm text-center"
/> />
<button <button
onClick={() => onClick={() =>
@@ -510,7 +510,7 @@ export default function UserManagement() {
level: (editingUser.level || 1) + 1, level: (editingUser.level || 1) + 1,
}) })
} }
className="px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-xs rounded hover:bg-green-900/30 transition" className="px-2 sm:px-3 py-1 border border-green-500/50 bg-green-900/20 text-green-400 text-[10px] sm:text-xs rounded hover:bg-green-900/30 transition flex-shrink-0"
> >
+1 +1
</button> </button>
@@ -519,7 +519,7 @@ export default function UserManagement() {
{/* Role Section */} {/* Role Section */}
<div> <div>
<label className="block text-sm text-gray-300 mb-2"> <label className="block text-xs sm:text-sm text-gray-300 mb-2">
Rôle Rôle
</label> </label>
<div className="flex gap-2"> <div className="flex gap-2">
@@ -530,7 +530,7 @@ export default function UserManagement() {
role: "USER", role: "USER",
}) })
} }
className={`flex-1 px-4 py-2 border rounded text-xs uppercase tracking-widest transition ${ className={`flex-1 px-3 sm:px-4 py-2 border rounded text-[10px] sm:text-xs uppercase tracking-widest transition ${
editingUser.role === "USER" editingUser.role === "USER"
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold" ? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold"
: "border-gray-600/50 bg-gray-900/20 text-gray-400 hover:bg-gray-900/30" : "border-gray-600/50 bg-gray-900/20 text-gray-400 hover:bg-gray-900/30"
@@ -545,7 +545,7 @@ export default function UserManagement() {
role: "ADMIN", role: "ADMIN",
}) })
} }
className={`flex-1 px-4 py-2 border rounded text-xs uppercase tracking-widest transition ${ className={`flex-1 px-3 sm:px-4 py-2 border rounded text-[10px] sm:text-xs uppercase tracking-widest transition ${
editingUser.role === "ADMIN" editingUser.role === "ADMIN"
? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold" ? "border-pixel-gold bg-pixel-gold/20 text-pixel-gold"
: "border-gray-600/50 bg-gray-900/20 text-gray-400 hover:bg-gray-900/30" : "border-gray-600/50 bg-gray-900/20 text-gray-400 hover:bg-gray-900/30"
@@ -556,7 +556,7 @@ export default function UserManagement() {
</div> </div>
</div> </div>
<div className="flex gap-2 pt-2"> <div className="flex flex-col sm:flex-row gap-2 pt-2">
<button <button
onClick={handleSave} onClick={handleSave}
disabled={saving} disabled={saving}
@@ -573,7 +573,7 @@ export default function UserManagement() {
</div> </div>
</div> </div>
) : ( ) : (
<div className="flex gap-4 text-xs"> <div className="flex flex-col sm:flex-row gap-3 sm:gap-4 text-[10px] sm:text-xs">
<div className="flex-1"> <div className="flex-1">
<div className="flex justify-between items-center mb-0.5"> <div className="flex justify-between items-center mb-0.5">
<span className="text-gray-400">HP</span> <span className="text-gray-400">HP</span>