Refactor UserManagement component layout: Update user display to a grid format for improved responsiveness, enhance user information presentation with clearer stats and action buttons, and streamline the overall UI for better user experience.
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m3s

This commit is contained in:
Julien Froidefond
2025-12-16 16:55:40 +01:00
parent ec965cd59d
commit 5eddf36121

View File

@@ -196,108 +196,117 @@ export default function UserManagement() {
Aucun utilisateur trouvé
</div>
) : (
users.map((user) => {
return (
<Card key={user.id} variant="default" className="p-3 sm:p-4">
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 mb-2">
<div className="flex gap-2 sm:gap-3 items-center flex-1 min-w-0">
{/* Avatar */}
<Avatar
src={user.avatar}
username={user.username}
size="sm"
className="flex-shrink-0"
borderClassName="border-2 border-pixel-gold/50"
/>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-1.5 sm:gap-2 flex-wrap">
<h3 className="text-pixel-gold font-bold text-sm sm:text-base break-words">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3 sm:gap-4">
{users.map((user) => {
return (
<Card key={user.id} variant="default" className="p-3">
<div className="flex flex-col gap-2">
{/* Header avec avatar et nom */}
<div className="flex items-center gap-2">
<Avatar
src={user.avatar}
username={user.username}
size="sm"
className="flex-shrink-0"
borderClassName="border-2 border-pixel-gold/50"
/>
<div className="flex-1 min-w-0">
<h3 className="text-pixel-gold font-bold text-sm truncate">
{user.username}
</h3>
<span className="text-[10px] sm:text-xs text-gray-500 whitespace-nowrap">
Niveau {user.level}
</span>
<span className="text-[10px] sm:text-xs text-gray-500 whitespace-nowrap">
Score: {formatNumber(user.score)}
</span>
<span
className={`text-[10px] sm:text-xs whitespace-nowrap ${
user.role === "ADMIN"
? "text-pixel-gold"
: "text-gray-500"
}`}
>
{user.role}
</span>
<div className="flex items-center gap-1.5 mt-0.5">
<span className="text-[10px] text-gray-500">
Niv. {user.level}
</span>
<span
className={`text-[10px] font-bold px-1.5 py-0.5 rounded border ${
user.role === "ADMIN"
? "text-pixel-gold border-pixel-gold/50 bg-pixel-gold/10"
: "text-gray-500 border-gray-500/30 bg-gray-500/10"
}`}
>
{user.role}
</span>
</div>
</div>
<p className="text-gray-400 text-[10px] sm:text-xs truncate">
{user.email}
</p>
</div>
</div>
<div className="flex gap-2 flex-shrink-0 sm:ml-2">
<button
onClick={() => handleEdit(user)}
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
</button>
<button
onClick={() => handleDelete(user.id)}
disabled={deletingUserId === user.id}
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
? "Suppression..."
: "Supprimer"}
</button>
</div>
</div>
{/* Affichage des stats */}
<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 justify-between items-center mb-0.5">
<span className="text-gray-400">HP</span>
<span className="text-gray-400">
{user.hp}/{user.maxHp}
{/* Score en évidence */}
<div className="flex items-baseline gap-1.5 px-1">
<span className="text-[10px] text-gray-400">Score:</span>
<span className="text-lg font-bold text-pixel-gold">
{formatNumber(user.score)}
</span>
</div>
<div className="h-1.5 bg-black/60 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-red-600 to-green-500"
style={{
width: `${Math.min(
100,
(user.hp / user.maxHp) * 100
)}%`,
}}
/>
{/* Stats HP et XP */}
<div className="space-y-1.5 text-[10px]">
<div>
<div className="flex justify-between items-center mb-0.5">
<span className="text-gray-400">HP</span>
<span className="text-gray-400">
{user.hp}/{user.maxHp}
</span>
</div>
<div className="h-1 bg-black/60 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-red-600 to-green-500"
style={{
width: `${Math.min(
100,
(user.hp / user.maxHp) * 100
)}%`,
}}
/>
</div>
</div>
<div>
<div className="flex justify-between items-center mb-0.5">
<span className="text-gray-400">XP</span>
<span className="text-gray-400">
{formatNumber(user.xp)}/{formatNumber(user.maxXp)}
</span>
</div>
<div className="h-1 bg-black/60 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-blue-600 to-purple-500"
style={{
width: `${Math.min(
100,
(user.xp / user.maxXp) * 100
)}%`,
}}
/>
</div>
</div>
</div>
{/* Email */}
<p className="text-gray-400 text-[10px] truncate px-1">
{user.email}
</p>
{/* Boutons d'action */}
<div className="flex gap-2 pt-1">
<button
onClick={() => handleEdit(user)}
className="flex-1 px-2 py-1 border border-pixel-gold/50 bg-black/60 text-white uppercase text-[10px] tracking-widest rounded hover:bg-pixel-gold/10 transition"
>
Modifier
</button>
<button
onClick={() => handleDelete(user.id)}
disabled={deletingUserId === user.id}
className="flex-1 px-2 py-1 border border-red-500/50 bg-red-900/20 text-red-400 uppercase text-[10px] tracking-widest rounded hover:bg-red-900/30 transition disabled:opacity-50"
>
{deletingUserId === user.id ? "..." : "Suppr."}
</button>
</div>
</div>
<div className="flex-1">
<div className="flex justify-between items-center mb-0.5">
<span className="text-gray-400">XP</span>
<span className="text-gray-400">
{formatNumber(user.xp)}/{formatNumber(user.maxXp)}
</span>
</div>
<div className="h-1.5 bg-black/60 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-blue-600 to-purple-500"
style={{
width: `${Math.min(
100,
(user.xp / user.maxXp) * 100
)}%`,
}}
/>
</div>
</div>
</div>
</Card>
);
})
</Card>
);
})}
</div>
)}
{/* Modal d'édition */}