"use client"; import { useState, useEffect, useTransition } from "react"; import { Avatar, Input, Button, Card, Modal, CloseButton, } from "@/components/ui"; import { updateUser, deleteUser } from "@/actions/admin/users"; interface User { id: string; username: string; email: string; role: string; score: number; level: number; hp: number; maxHp: number; xp: number; maxXp: number; avatar: string | null; createdAt: string; } interface EditingUser { userId: string; username: string | null; avatar: string | null; hpDelta: number; xpDelta: number; score: number | null; level: number | null; role: string | null; } interface UserManagementProps { initialUsers: User[]; } export default function UserManagement({ initialUsers }: UserManagementProps) { const [users, setUsers] = useState(initialUsers); const [loading, setLoading] = useState(false); const [editingUser, setEditingUser] = useState(null); const [saving, setSaving] = useState(false); const [deletingUserId, setDeletingUserId] = useState(null); const [, startTransition] = useTransition(); const [uploadingAvatar, setUploadingAvatar] = useState(null); const fetchUsers = async () => { try { const response = await fetch("/api/admin/users"); if (response.ok) { const data = await response.json(); setUsers(data); } } catch (error) { console.error("Error fetching users:", error); } }; const handleEdit = (user: User) => { setEditingUser({ userId: user.id, username: user.username, avatar: user.avatar, hpDelta: 0, xpDelta: 0, score: user.score, level: user.level, role: user.role, }); }; const handleSave = async () => { if (!editingUser) return; setSaving(true); startTransition(async () => { try { const body: { username?: string; avatar?: string | null; hpDelta?: number; xpDelta?: number; score?: number; level?: number; role?: string; } = {}; if (editingUser.username !== null) { body.username = editingUser.username; } if (editingUser.avatar !== undefined) { body.avatar = editingUser.avatar; } if (editingUser.hpDelta !== 0) { body.hpDelta = editingUser.hpDelta; } if (editingUser.xpDelta !== 0) { body.xpDelta = editingUser.xpDelta; } if (editingUser.score !== null) { body.score = editingUser.score; } if (editingUser.level !== null) { body.level = editingUser.level; } if (editingUser.role !== null) { body.role = editingUser.role; } const result = await updateUser(editingUser.userId, body); if (result.success) { await fetchUsers(); setEditingUser(null); } else { alert(result.error || "Erreur lors de la mise à jour"); } } catch (error) { console.error("Error updating user:", error); alert("Erreur lors de la mise à jour"); } finally { setSaving(false); } }); }; const handleCancel = () => { setEditingUser(null); }; const handleDelete = async (userId: string) => { if ( !confirm( "Êtes-vous sûr de vouloir supprimer cet utilisateur ? Cette action est irréversible." ) ) { return; } setDeletingUserId(userId); try { const result = await deleteUser(userId); if (result.success) { await fetchUsers(); } else { alert(result.error || "Erreur lors de la suppression"); } } catch (error) { console.error("Error deleting user:", error); alert("Erreur lors de la suppression"); } finally { setDeletingUserId(null); } }; const formatNumber = (num: number) => { return num.toLocaleString("en-US"); }; // Trouver l'utilisateur en cours d'édition pour les previews const currentEditingUserData = editingUser ? users.find((u) => u.id === editingUser.userId) : null; const previewHp = currentEditingUserData && editingUser ? Math.max( 0, Math.min( currentEditingUserData.maxHp, currentEditingUserData.hp + editingUser.hpDelta ) ) : 0; const previewXp = currentEditingUserData && editingUser ? Math.max(0, currentEditingUserData.xp + editingUser.xpDelta) : 0; if (loading) { return
Chargement...
; } return (
{users.length === 0 ? (
Aucun utilisateur trouvé
) : (
{users.map((user) => { return (
{/* Header avec avatar et nom */}

{user.username}

Niv. {user.level} {user.role}
{/* Score en évidence */}
Score: {formatNumber(user.score)}
{/* Stats HP et XP */}
HP {user.hp}/{user.maxHp}
XP {formatNumber(user.xp)}/{formatNumber(user.maxXp)}
{/* Email */}

{user.email}

{/* Boutons d'action */}
); })}
)} {/* Modal d'édition */} {editingUser && currentEditingUserData && (

Modifier l'utilisateur

{/* Username Section */} setEditingUser({ ...editingUser, username: e.target.value, }) } placeholder="Nom d'utilisateur" className="text-xs sm:text-sm px-2 sm:px-3 py-1" /> {/* Avatar Section */}
{/* Preview */}
{uploadingAvatar === editingUser.userId && (
Upload...
)}
{/* Avatars par défaut */}
{[ "/avatar-1.jpg", "/avatar-2.jpg", "/avatar-3.jpg", "/avatar-4.jpg", "/avatar-5.jpg", "/avatar-6.jpg", ].map((defaultAvatar) => ( ))}
{/* Custom Upload */}
{ const file = e.target.files?.[0]; if (!file) return; setUploadingAvatar(editingUser.userId); try { const formData = new FormData(); formData.append("file", file); const response = await fetch( "/api/admin/avatars/upload", { method: "POST", body: formData, } ); if (response.ok) { const data = await response.json(); setEditingUser({ ...editingUser, avatar: data.url, }); } else { alert("Erreur lors de l'upload de l'image"); } } catch (error) { console.error("Error uploading image:", error); alert("Erreur lors de l'upload de l'image"); } finally { setUploadingAvatar(null); if (e.target) { e.target.value = ""; } } }} className="hidden" id={`avatar-upload-${editingUser.userId}`} />
{/* HP Section */}
{previewHp} / {currentEditingUserData.maxHp}
setEditingUser({ ...editingUser, hpDelta: parseInt(e.target.value) || 0, }) } 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" />
{/* XP Section */}
{formatNumber(previewXp)} /{" "} {formatNumber(currentEditingUserData.maxXp)}
setEditingUser({ ...editingUser, xpDelta: parseInt(e.target.value) || 0, }) } 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" />
{/* Score Section */}
setEditingUser({ ...editingUser, score: parseInt(e.target.value) || 0, }) } 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" />
{/* Level Section */}
setEditingUser({ ...editingUser, level: Math.max(1, parseInt(e.target.value) || 1), }) } 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" />
{/* Role Section */}
)}
); }