fullstack-form-app-sinclqir
Version:
Application de gestion des utilisateurs avec authentification JWT - Frontend React + Backend Python FastAPI
206 lines (183 loc) • 6.72 kB
JSX
"use client"
import { useState, useEffect } from "react"
import axios from "axios"
import { Users, Calendar, MapPin, Hash } from "lucide-react"
import { API_ENDPOINTS } from "../../../config/api"
import "./UsersList.css"
const UsersList = ({ currentUser, token }) => {
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState("")
const [deletingUser, setDeletingUser] = useState(null)
const isAdmin = currentUser?.role === "admin"
useEffect(() => {
fetchUsers()
}, [])
const fetchUsers = async () => {
try {
setLoading(true)
setError("")
console.log("Fetching users...")
console.log("Current user:", currentUser)
console.log("Token:", token)
console.log("Is admin:", isAdmin)
if (isAdmin) {
// Admin : récupère tous les utilisateurs
console.log("Récupération en tant qu'admin...")
const response = await axios.get(API_ENDPOINTS.USERS, {
headers: {
Authorization: `Bearer ${token}`,
},
})
console.log("Réponse utilisateurs (admin):", response.data)
setUsers(response.data)
} else {
console.log("Récupération en tant qu'utilisateur...")
const response = await axios.get(API_ENDPOINTS.PUBLIC_USERS)
console.log("Réponse utilisateurs (public):", response.data)
setUsers(response.data)
}
} catch (err) {
console.error("Erreur lors du fetch des utilisateurs:", err.response?.data || err.message)
setError(err.response?.data?.detail || "Erreur lors du chargement des utilisateurs")
} finally {
setLoading(false)
}
}
const handleDeleteUser = async (userId) => {
if (!isAdmin) return
if (!window.confirm("Êtes-vous sûr de vouloir supprimer cet utilisateur ?")) {
return
}
try {
setDeletingUser(userId)
await axios.delete(`${API_ENDPOINTS.USERS}/${userId}`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
setUsers(users.filter((user) => user.id !== userId))
} catch (err) {
alert(err.response?.data?.detail || "Erreur lors de la suppression")
} finally {
setDeletingUser(null)
}
}
const formatDate = (dateString) => {
if (!dateString) return "Non renseigné"
return new Date(dateString).toLocaleDateString("fr-FR")
}
if (loading) {
return (
<div className="users-list">
<div className="users-header">
<div className="users-title-section">
<Users className="users-icon" />
<h2 className="users-title">Gestion des utilisateurs</h2>
</div>
</div>
<div className="loading-container">
<p className="loading-text">Chargement en cours...</p>
</div>
</div>
)
}
if (error) {
return (
<div className="users-list">
<div className="users-header">
<div className="users-title-section">
<Users className="users-icon" />
<h2 className="users-title">Gestion des utilisateurs</h2>
</div>
</div>
<div className="error-container">
<div className="error-message">{error}</div>
<button onClick={fetchUsers} className="retry-btn">
Réessayer
</button>
</div>
</div>
)
}
return (
<div className="users-list">
<div className="users-header">
<div className="users-title-section">
<Users className="users-icon" />
<h2 className="users-title">Gestion des utilisateurs</h2>
</div>
<div className="users-count-badge">
{users.length} utilisateur{users.length > 1 ? "s" : ""}
</div>
</div>
{users.length === 0 ? (
<div className="no-users-card">
<div className="no-users-content">
<Users className="no-users-icon" />
<p className="no-users-text">Aucun utilisateur trouvé.</p>
</div>
</div>
) : (
<div className="users-grid">
{users.map((user) => (
<div key={user.id} className="user-card">
<div className="user-card-header">
<div className="user-header-content">
<div className="user-header-info">
<Users className="user-avatar-icon" />
<span className="user-email">{user.email}</span>
</div>
</div>
</div>
<div className="user-card-content">
<div className="user-details">
{isAdmin && (
<>
{user.birth_date && (
<div className="user-detail-item">
<Calendar className="detail-icon" />
<span>{formatDate(user.birth_date)}</span>
</div>
)}
{user.city && (
<div className="user-detail-item">
<MapPin className="detail-icon" />
<span>{user.city}</span>
</div>
)}
{user.postal_code && (
<div className="user-detail-item">
<Hash className="detail-icon" />
<span>{user.postal_code}</span>
</div>
)}
{user.created_at && (
<>
<div className="detail-separator"></div>
<p className="detail-date">Inscrit le {formatDate(user.created_at)}</p>
</>
)}
</>
)}
</div>
</div>
{isAdmin && user.id !== currentUser?.id && (
<div className="user-card-footer">
<button
onClick={() => handleDeleteUser(user.id)}
disabled={deletingUser === user.id}
className="delete-btn"
>
{deletingUser === user.id ? "Suppression..." : "Supprimer l'utilisateur"}
</button>
</div>
)}
</div>
))}
</div>
)}
</div>
)
}
export default UsersList