mise a jours de User et le Dashboard
This commit is contained in:
parent
922af8455d
commit
daa1460283
@ -1,51 +1,118 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState } from "react";
|
||||||
import { LogIn, UserPlus, LogOut, Settings } from "lucide-react";
|
import { LogIn, UserPlus, LogOut, Settings } from "lucide-react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useAuth } from "../AuthContext";
|
import { useAuth } from "../AuthContext";
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
const { token, logout } = useAuth();
|
const { token, logout } = useAuth();
|
||||||
|
const [showAdminDropdown, setShowAdminDropdown] = useState(false);
|
||||||
|
|
||||||
|
const toggleAdminDropdown = () => {
|
||||||
|
setShowAdminDropdown((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="bg-white shadow-sm">
|
<header className="bg-white shadow-sm relative">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<h1 className="text-2xl font-bold text-indigo-600">VigiMétéo</h1>
|
<h1 className="text-2xl font-bold text-indigo-600">VigiMétéo</h1>
|
||||||
<nav>
|
<nav>
|
||||||
<ul className="flex gap-4">
|
<ul className="flex gap-4 relative">
|
||||||
<li>
|
<li>
|
||||||
<Link to="/" className="text-gray-600 hover:text-indigo-600">Accueil</Link>
|
<Link to="/" className="text-gray-600 hover:text-indigo-600">
|
||||||
|
Accueil
|
||||||
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/about" className="text-gray-600 hover:text-indigo-600">A propos</Link>
|
<Link
|
||||||
|
to="/about"
|
||||||
|
className="text-gray-600 hover:text-indigo-600"
|
||||||
|
>
|
||||||
|
A propos
|
||||||
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Link to="/gestion" className="text-gray-600 hover:text-indigo-600">Gestion</Link>
|
<Link
|
||||||
|
to="/gestion"
|
||||||
|
className="text-gray-600 hover:text-indigo-600"
|
||||||
|
>
|
||||||
|
Gestion
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
{/* Onglet déroulant "Admin" */}
|
||||||
|
<li className="relative">
|
||||||
|
<button
|
||||||
|
onClick={toggleAdminDropdown}
|
||||||
|
className="flex items-center text-gray-600 hover:text-indigo-600 focus:outline-none"
|
||||||
|
>
|
||||||
|
Admin
|
||||||
|
<svg
|
||||||
|
className="ml-1 h-4 w-4 fill-current"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{showAdminDropdown && (
|
||||||
|
<div className="absolute top-full left-0 mt-2 w-48 bg-white border border-gray-200 rounded-md shadow-lg z-50">
|
||||||
|
{/* En cliquant sur le lien "Dashboard", on ferme le menu */}
|
||||||
|
<Link
|
||||||
|
to="/dashboard"
|
||||||
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
|
>
|
||||||
|
Dashboard
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to="/user"
|
||||||
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
|
>
|
||||||
|
Gestion des Utilisateurs
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to="/adminobjet"
|
||||||
|
className="block px-4 py-2 text-gray-700 hover:bg-gray-100"
|
||||||
|
onClick={() => setShowAdminDropdown(false)}
|
||||||
|
>
|
||||||
|
Gestion des Objets Connectés
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
{token ? (
|
{token ? (
|
||||||
<>
|
<>
|
||||||
<Link to="/settings" className="flex items-center gap-2 text-gray-600 hover:text-indigo-600">
|
<Link
|
||||||
<Settings size={20} />
|
to="/settings"
|
||||||
<span></span>
|
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
||||||
</Link>
|
>
|
||||||
<button
|
<Settings size={20} />
|
||||||
onClick={logout}
|
<span></span>
|
||||||
className="flex items-center gap-2 text-gray-600 hover:text-red-600"
|
</Link>
|
||||||
>
|
<button
|
||||||
<LogOut size={20} />
|
onClick={logout}
|
||||||
<span>Déconnexion</span>
|
className="flex items-center gap-2 text-gray-600 hover:text-red-600"
|
||||||
</button>
|
>
|
||||||
|
<LogOut size={20} />
|
||||||
|
<span>Déconnexion</span>
|
||||||
|
</button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Link to="/login" className="flex items-center gap-2 text-gray-600 hover:text-indigo-600">
|
<Link
|
||||||
|
to="/login"
|
||||||
|
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
|
||||||
|
>
|
||||||
<LogIn size={20} />
|
<LogIn size={20} />
|
||||||
<span>Connexion</span>
|
<span>Connexion</span>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/signup" className="flex items-center gap-2 bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700">
|
<Link
|
||||||
|
to="/signup"
|
||||||
|
className="flex items-center gap-2 bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700"
|
||||||
|
>
|
||||||
<UserPlus size={20} />
|
<UserPlus size={20} />
|
||||||
<span>Inscription</span>
|
<span>Inscription</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@ -1,50 +1,16 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Sidebar from "./sidebar.jsx";
|
import Sidebar from "./sidebar.jsx";
|
||||||
|
import { RadioTower, ArrowRight, BadgePlus, Settings } from "lucide-react";
|
||||||
|
|
||||||
const dashboardStyles = {
|
// Widgets initiaux pour le dashboard
|
||||||
mainContent: {
|
const initialWidgets = [
|
||||||
flexGrow: 1,
|
{ id: 1, type: "summary" },
|
||||||
padding: "20px",
|
{ id: 2, type: "users" },
|
||||||
},
|
{ id: 3, type: "objects" },
|
||||||
summaryContainer: {
|
];
|
||||||
display: "flex",
|
|
||||||
gap: "20px",
|
|
||||||
marginBottom: "20px",
|
|
||||||
},
|
|
||||||
summaryCard: {
|
|
||||||
background: "#f4f4f4",
|
|
||||||
padding: "20px",
|
|
||||||
flex: 1,
|
|
||||||
borderRadius: "5px",
|
|
||||||
textAlign: "center",
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
width: "100%",
|
|
||||||
borderCollapse: "collapse",
|
|
||||||
},
|
|
||||||
tableHeader: {
|
|
||||||
padding: "10px",
|
|
||||||
border: "1px solid #ccc",
|
|
||||||
backgroundColor: "#f4f4f4",
|
|
||||||
},
|
|
||||||
tableCell: {
|
|
||||||
padding: "10px",
|
|
||||||
border: "1px solid #ccc",
|
|
||||||
textAlign: "left",
|
|
||||||
},
|
|
||||||
viewMoreButton: {
|
|
||||||
marginTop: "10px",
|
|
||||||
padding: "10px 15px",
|
|
||||||
backgroundColor: "#007bff",
|
|
||||||
color: "#fff",
|
|
||||||
border: "none",
|
|
||||||
borderRadius: "5px",
|
|
||||||
cursor: "pointer",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function Dashboard() {
|
function Dashboard() {
|
||||||
// États simulés (dans une vraie application, ils viendraient d'une API ou d'un store global)
|
// États simulés (données fictives pour l'exemple)
|
||||||
const [users, setUsers] = useState([
|
const [users, setUsers] = useState([
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@ -73,6 +39,7 @@ function Dashboard() {
|
|||||||
accessLevel: "Admin",
|
accessLevel: "Admin",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const [logs, setLogs] = useState([
|
const [logs, setLogs] = useState([
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@ -88,64 +55,285 @@ function Dashboard() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// État pour simuler les objets présents dans la section AdminObjet.jsx
|
||||||
|
const [adminObjects, setAdminObjects] = useState([
|
||||||
|
{
|
||||||
|
id: 101,
|
||||||
|
nom: "Objet A",
|
||||||
|
description: "Description A",
|
||||||
|
type: "Type A",
|
||||||
|
localisation: "Localisation A",
|
||||||
|
proprietaire: "Propriétaire A",
|
||||||
|
status: "active",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 102,
|
||||||
|
nom: "Objet B",
|
||||||
|
description: "Description B",
|
||||||
|
type: "Type B",
|
||||||
|
localisation: "Localisation B",
|
||||||
|
proprietaire: "Propriétaire B",
|
||||||
|
status: "inactive",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 103,
|
||||||
|
nom: "Objet C",
|
||||||
|
description: "Description C",
|
||||||
|
type: "Type C",
|
||||||
|
localisation: "Localisation C",
|
||||||
|
proprietaire: "Propriétaire C",
|
||||||
|
status: "active",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Gestion du mode de gestion et des widgets
|
||||||
|
const [manageMode, setManageMode] = useState(false);
|
||||||
|
const [widgets, setWidgets] = useState(initialWidgets);
|
||||||
|
|
||||||
|
// Contrôle d'affichage du modal de sélection de widget
|
||||||
|
const [showAddWidgetModal, setShowAddWidgetModal] = useState(false);
|
||||||
|
|
||||||
|
// Suppression d'un widget
|
||||||
|
const handleDeleteWidget = (id) => {
|
||||||
|
setWidgets(widgets.filter((widget) => widget.id !== id));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ouvre le modal pour ajouter un widget
|
||||||
|
const openAddWidgetModal = () => {
|
||||||
|
setShowAddWidgetModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ajoute le widget sélectionné en fonction du type choisi
|
||||||
|
const handleWidgetSelection = (widgetType) => {
|
||||||
|
const newWidget = { id: Date.now(), type: widgetType };
|
||||||
|
setWidgets([...widgets, newWidget]);
|
||||||
|
setShowAddWidgetModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", minHeight: "100vh" }}>
|
<div className="flex min-h-screen">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<main style={dashboardStyles.mainContent}>
|
<main className="flex-1 bg-gradient-to-br from-blue-50 to-indigo-50 p-8 overflow-auto">
|
||||||
<h1>Dashboard</h1>
|
{/* En-tête : titre + bouton pour activer/désactiver le mode gestion */}
|
||||||
<div style={dashboardStyles.summaryContainer}>
|
<div className="flex items-center justify-between mb-6">
|
||||||
<div style={dashboardStyles.summaryCard}>
|
<h1 className="text-3xl font-bold">Dashboard</h1>
|
||||||
<h2>Total Users</h2>
|
<button
|
||||||
<p>{users.length}</p>
|
onClick={() => setManageMode(!manageMode)}
|
||||||
</div>
|
className="flex items-center px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md"
|
||||||
<div style={dashboardStyles.summaryCard}>
|
>
|
||||||
<h2>Dernier Log</h2>
|
<Settings className="mr-2" size={20} />
|
||||||
{logs.length > 0 ? (
|
{manageMode ? "Terminer la gestion" : "Gérer les widgets"}
|
||||||
<p>
|
</button>
|
||||||
{logs[logs.length - 1].username} -{" "}
|
|
||||||
{logs[logs.length - 1].action}
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
<p>Aucun log</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Grille des widgets */}
|
||||||
<section>
|
<section>
|
||||||
<h2>Aperçu des Utilisateurs</h2>
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
<table style={dashboardStyles.table}>
|
{widgets.map((widget) => (
|
||||||
<thead>
|
<div
|
||||||
<tr>
|
key={widget.id}
|
||||||
<th style={dashboardStyles.tableHeader}>Username</th>
|
className="relative bg-white p-6 rounded-xl shadow hover:shadow-md"
|
||||||
<th style={dashboardStyles.tableHeader}>Email</th>
|
>
|
||||||
<th style={dashboardStyles.tableHeader}>Access Level</th>
|
{/* Bouton de suppression, visible en mode gestion */}
|
||||||
</tr>
|
{manageMode && (
|
||||||
</thead>
|
<button
|
||||||
<tbody>
|
onClick={() => handleDeleteWidget(widget.id)}
|
||||||
{users.slice(0, 5).map((user) => (
|
className="absolute top-2 right-2 bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
|
||||||
<tr key={user.id}>
|
>
|
||||||
<td style={dashboardStyles.tableCell}>{user.username}</td>
|
–
|
||||||
<td style={dashboardStyles.tableCell}>{user.email}</td>
|
</button>
|
||||||
<td style={dashboardStyles.tableCell}>{user.accessLevel}</td>
|
)}
|
||||||
</tr>
|
|
||||||
))}
|
{/* Contenu du widget selon son type */}
|
||||||
{users.length === 0 && (
|
{widget.type === "summary" && (
|
||||||
<tr>
|
<div>
|
||||||
<td colSpan="3" style={dashboardStyles.tableCell}>
|
<h2 className="text-xl font-semibold mb-4">
|
||||||
Aucun utilisateur disponible
|
Dashboard Summary
|
||||||
</td>
|
</h2>
|
||||||
</tr>
|
<div className="mb-4">
|
||||||
)}
|
<h3 className="text-lg font-medium">Total Users</h3>
|
||||||
</tbody>
|
<p className="text-2xl">{users.length}</p>
|
||||||
</table>
|
</div>
|
||||||
{/* Bouton pour accéder à la page complète */}
|
<div>
|
||||||
<button
|
<h3 className="text-lg font-medium">Dernier Log</h3>
|
||||||
style={dashboardStyles.viewMoreButton}
|
{logs.length > 0 ? (
|
||||||
onClick={() => (window.location.href = "/user")}
|
<p>
|
||||||
>
|
{logs[logs.length - 1].username} -{" "}
|
||||||
Voir plus
|
{logs[logs.length - 1].action}
|
||||||
</button>
|
</p>
|
||||||
|
) : (
|
||||||
|
<p>Aucun log</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{widget.type === "users" && (
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-semibold mb-4">
|
||||||
|
Gestion des Utilisateurs
|
||||||
|
</h2>
|
||||||
|
<table className="w-full border border-gray-200">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className="px-2 py-1 border border-gray-200 bg-gray-100 text-left">
|
||||||
|
Username
|
||||||
|
</th>
|
||||||
|
<th className="px-2 py-1 border border-gray-200 bg-gray-100 text-left">
|
||||||
|
Email
|
||||||
|
</th>
|
||||||
|
<th className="px-2 py-1 border border-gray-200 bg-gray-100 text-left">
|
||||||
|
Access
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{users.slice(0, 5).map((user) => (
|
||||||
|
<tr key={user.id}>
|
||||||
|
<td className="px-2 py-1 border border-gray-200">
|
||||||
|
{user.username}
|
||||||
|
</td>
|
||||||
|
<td className="px-2 py-1 border border-gray-200">
|
||||||
|
{user.email}
|
||||||
|
</td>
|
||||||
|
<td className="px-2 py-1 border border-gray-200">
|
||||||
|
{user.accessLevel}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
{users.length === 0 && (
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan="3"
|
||||||
|
className="px-2 py-1 border border-gray-200 text-center"
|
||||||
|
>
|
||||||
|
Aucun utilisateur disponible
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<button
|
||||||
|
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-md"
|
||||||
|
onClick={() => (window.location.href = "/user")}
|
||||||
|
>
|
||||||
|
Voir plus
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{widget.type === "objects" && (
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-semibold mb-4">
|
||||||
|
Gestion des Objets Connectés
|
||||||
|
</h2>
|
||||||
|
<div className="mb-4">
|
||||||
|
<a
|
||||||
|
href="/gestionObjets"
|
||||||
|
className="flex items-center text-indigo-600 hover:text-indigo-700"
|
||||||
|
>
|
||||||
|
<RadioTower size={24} className="mr-2" />
|
||||||
|
Consulter les objets connectés
|
||||||
|
<ArrowRight size={16} className="ml-2" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a
|
||||||
|
href="/adminobjet"
|
||||||
|
className="flex items-center text-indigo-600 hover:text-indigo-700"
|
||||||
|
>
|
||||||
|
<BadgePlus size={24} className="mr-2" />
|
||||||
|
Ajouter un nouvel objet
|
||||||
|
<ArrowRight size={16} className="ml-2" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{widget.type === "adminobjet" && (
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-semibold mb-4">
|
||||||
|
Liste des Objets et Outils/Services
|
||||||
|
</h2>
|
||||||
|
{/* Afficher seulement les 2 premiers objets */}
|
||||||
|
<ul className="mb-4 space-y-2">
|
||||||
|
{adminObjects.slice(0, 2).map((obj) => (
|
||||||
|
<li
|
||||||
|
key={obj.id}
|
||||||
|
className="border border-gray-200 p-2 rounded"
|
||||||
|
>
|
||||||
|
<p className="font-medium">{obj.nom}</p>
|
||||||
|
<p className="text-sm text-gray-500">{obj.type}</p>
|
||||||
|
<p className="text-sm text-gray-500">{obj.status}</p>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<button
|
||||||
|
onClick={() => (window.location.href = "/adminobjet")}
|
||||||
|
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-md"
|
||||||
|
>
|
||||||
|
Voir plus
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Case pour ajouter un widget */}
|
||||||
|
<div
|
||||||
|
onClick={openAddWidgetModal}
|
||||||
|
className="flex items-center justify-center border-2 border-dashed border-gray-300 rounded-xl p-6 hover:bg-gray-50 cursor-pointer"
|
||||||
|
>
|
||||||
|
<button className="flex items-center">
|
||||||
|
<span className="text-3xl font-bold mr-2">+</span>
|
||||||
|
<span>Ajouter un widget</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Modal de sélection du type de widget */}
|
||||||
|
{showAddWidgetModal && (
|
||||||
|
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
|
||||||
|
<div className="bg-white rounded-lg p-6 w-80">
|
||||||
|
<h3 className="text-xl font-semibold mb-4">
|
||||||
|
Choisir un type de widget
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<button
|
||||||
|
onClick={() => handleWidgetSelection("summary")}
|
||||||
|
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
|
||||||
|
>
|
||||||
|
Dashboard Summary
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleWidgetSelection("users")}
|
||||||
|
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
|
||||||
|
>
|
||||||
|
Gestion des Utilisateurs
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleWidgetSelection("objects")}
|
||||||
|
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
|
||||||
|
>
|
||||||
|
Gestion des Objets Connectés
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleWidgetSelection("adminobjet")}
|
||||||
|
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
|
||||||
|
>
|
||||||
|
Liste des Objets et Outils/Services
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowAddWidgetModal(false)}
|
||||||
|
className="mt-4 px-4 py-2 bg-red-500 text-white rounded-md w-full"
|
||||||
|
>
|
||||||
|
Annuler
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,52 +1,8 @@
|
|||||||
|
// User.jsx
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Sidebar from "./sidebar.jsx";
|
import Sidebar from "./sidebar.jsx";
|
||||||
|
|
||||||
const styles = {
|
|
||||||
mainContent: {
|
|
||||||
flexGrow: 1,
|
|
||||||
padding: "20px",
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
marginBottom: "20px",
|
|
||||||
},
|
|
||||||
userManagement: {
|
|
||||||
marginTop: "20px",
|
|
||||||
},
|
|
||||||
userForm: {
|
|
||||||
display: "grid",
|
|
||||||
gridTemplateColumns: "1fr 1fr auto",
|
|
||||||
gap: "10px",
|
|
||||||
marginBottom: "20px",
|
|
||||||
},
|
|
||||||
input: {
|
|
||||||
padding: "10px",
|
|
||||||
border: "1px solid #ccc",
|
|
||||||
borderRadius: "5px",
|
|
||||||
},
|
|
||||||
button: {
|
|
||||||
padding: "10px",
|
|
||||||
backgroundColor: "#28a745",
|
|
||||||
color: "white",
|
|
||||||
border: "none",
|
|
||||||
borderRadius: "5px",
|
|
||||||
cursor: "pointer",
|
|
||||||
},
|
|
||||||
userTable: {
|
|
||||||
width: "100%",
|
|
||||||
borderCollapse: "collapse",
|
|
||||||
},
|
|
||||||
thTd: {
|
|
||||||
padding: "10px",
|
|
||||||
border: "1px solid #ccc",
|
|
||||||
textAlign: "left",
|
|
||||||
},
|
|
||||||
th: {
|
|
||||||
backgroundColor: "#f4f4f4",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function User() {
|
function User() {
|
||||||
// États pour la gestion des utilisateurs, des logs, des champs du formulaire et des ajustements de points
|
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState([]);
|
||||||
const [logs, setLogs] = useState([]);
|
const [logs, setLogs] = useState([]);
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
@ -69,7 +25,7 @@ function User() {
|
|||||||
setEmail("");
|
setEmail("");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Suppression d'un utilisateur (fonction présente dans script.js)
|
// Suppression d'un utilisateur
|
||||||
const handleDeleteUser = (userId) => {
|
const handleDeleteUser = (userId) => {
|
||||||
const user = users.find((u) => u.id === userId);
|
const user = users.find((u) => u.id === userId);
|
||||||
if (user) {
|
if (user) {
|
||||||
@ -78,7 +34,7 @@ function User() {
|
|||||||
setUsers(users.filter((u) => u.id !== userId));
|
setUsers(users.filter((u) => u.id !== userId));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Changement du niveau d'accès via le menu déroulant (fonction issue de script.js)
|
// Changement du niveau d'accès via le menu déroulant
|
||||||
const handleChangeAccessLevel = (userId, newLevel) => {
|
const handleChangeAccessLevel = (userId, newLevel) => {
|
||||||
setUsers(
|
setUsers(
|
||||||
users.map((user) => {
|
users.map((user) => {
|
||||||
@ -95,7 +51,7 @@ function User() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ajustement des points d'un utilisateur (fonction issue de script.js)
|
// Ajustement des points d'un utilisateur
|
||||||
const handleAdjustPoints = (userId) => {
|
const handleAdjustPoints = (userId) => {
|
||||||
const pointsToAdd = parseInt(pointsInput[userId]) || 0;
|
const pointsToAdd = parseInt(pointsInput[userId]) || 0;
|
||||||
setUsers(
|
setUsers(
|
||||||
@ -111,80 +67,97 @@ function User() {
|
|||||||
setPointsInput({ ...pointsInput, [userId]: "" });
|
setPointsInput({ ...pointsInput, [userId]: "" });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fonction de journalisation des actions (définie dans script.js)
|
// Fonction de journalisation des actions
|
||||||
const logAction = (username, action) => {
|
const logAction = (username, action) => {
|
||||||
const timestamp = new Date().toLocaleString();
|
const timestamp = new Date().toLocaleString();
|
||||||
setLogs([...logs, { id: Date.now(), username, action, timestamp }]);
|
setLogs([...logs, { id: Date.now(), username, action, timestamp }]);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", minHeight: "100vh" }}>
|
<div className="flex min-h-screen">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<main style={styles.mainContent}>
|
<main className="flex-grow p-5">
|
||||||
<section style={styles.userManagement}>
|
<section className="mt-5">
|
||||||
<h1>User Management</h1>
|
<h1 className="text-2xl font-bold mb-4">User Management</h1>
|
||||||
<p>Manage users from this panel.</p>
|
<p className="mb-5">Manage users from this panel.</p>
|
||||||
{/* Formulaire d'ajout d'utilisateur */}
|
{/* Formulaire d'ajout d'utilisateur */}
|
||||||
<form style={styles.userForm} onSubmit={handleAddUser}>
|
<form
|
||||||
|
className="grid grid-cols-[1fr_1fr_auto] gap-[10px] mb-5"
|
||||||
|
onSubmit={handleAddUser}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
style={styles.input}
|
|
||||||
type="text"
|
type="text"
|
||||||
id="username"
|
id="username"
|
||||||
placeholder="Username"
|
placeholder="Username"
|
||||||
value={username}
|
value={username}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
required
|
required
|
||||||
|
className="p-2.5 border border-gray-300 rounded-md"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
style={styles.input}
|
|
||||||
type="email"
|
type="email"
|
||||||
id="email"
|
id="email"
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
required
|
required
|
||||||
|
className="p-2.5 border border-gray-300 rounded-md"
|
||||||
/>
|
/>
|
||||||
<button style={styles.button} type="submit">
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="p-2.5 bg-green-600 text-white rounded-md cursor-pointer"
|
||||||
|
>
|
||||||
Add User
|
Add User
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{/* Tableau des utilisateurs */}
|
{/* Tableau des utilisateurs */}
|
||||||
<table style={styles.userTable}>
|
<table className="w-full border-collapse">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ ...styles.thTd, ...styles.th }}>Username</th>
|
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
||||||
<th style={{ ...styles.thTd, ...styles.th }}>Email</th>
|
Username
|
||||||
<th style={{ ...styles.thTd, ...styles.th }}>Access Level</th>
|
</th>
|
||||||
<th style={{ ...styles.thTd, ...styles.th }}>Points</th>
|
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
||||||
<th style={{ ...styles.thTd, ...styles.th }}>Actions</th>
|
Email
|
||||||
|
</th>
|
||||||
|
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
||||||
|
Access Level
|
||||||
|
</th>
|
||||||
|
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
||||||
|
Points
|
||||||
|
</th>
|
||||||
|
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
||||||
|
Actions
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{users.map((user) => (
|
{users.map((user) => (
|
||||||
<tr key={user.id}>
|
<tr key={user.id}>
|
||||||
<td style={styles.thTd}>{user.username}</td>
|
<td className="p-2.5 border border-gray-300 text-left">
|
||||||
<td style={styles.thTd}>{user.email}</td>
|
{user.username}
|
||||||
<td style={styles.thTd}>
|
</td>
|
||||||
{/* Menu déroulant pour changer le niveau d'accès */}
|
<td className="p-2.5 border border-gray-300 text-left">
|
||||||
|
{user.email}
|
||||||
|
</td>
|
||||||
|
<td className="p-2.5 border border-gray-300 text-left">
|
||||||
<select
|
<select
|
||||||
value={user.accessLevel}
|
value={user.accessLevel}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleChangeAccessLevel(user.id, e.target.value)
|
handleChangeAccessLevel(user.id, e.target.value)
|
||||||
}
|
}
|
||||||
style={{ padding: "5px", borderRadius: "5px" }}
|
className="p-1 rounded-md border border-gray-300"
|
||||||
>
|
>
|
||||||
<option value="Admin">Admin</option>
|
<option value="Admin">Admin</option>
|
||||||
<option value="User">User</option>
|
<option value="User">User</option>
|
||||||
<option value="Guest">Guest</option>
|
<option value="Guest">Guest</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td style={styles.thTd}>
|
<td className="p-2.5 border border-gray-300 text-left">
|
||||||
<span>{user.points}</span>
|
<span>{user.points}</span>
|
||||||
{/* Input et bouton pour ajuster les points */}
|
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
style={{ width: "60px", marginLeft: "10px" }}
|
|
||||||
placeholder="Adjust"
|
placeholder="Adjust"
|
||||||
value={pointsInput[user.id] || ""}
|
value={pointsInput[user.id] || ""}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@ -193,27 +166,19 @@ function User() {
|
|||||||
[user.id]: e.target.value,
|
[user.id]: e.target.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
className="w-[60px] ml-2.5 p-1 border border-gray-300 rounded-md"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
style={{
|
|
||||||
...styles.button,
|
|
||||||
padding: "5px 10px",
|
|
||||||
marginLeft: "5px",
|
|
||||||
}}
|
|
||||||
onClick={() => handleAdjustPoints(user.id)}
|
onClick={() => handleAdjustPoints(user.id)}
|
||||||
|
className="py-1 px-2.5 ml-2 bg-green-600 text-white rounded-md cursor-pointer"
|
||||||
>
|
>
|
||||||
Adjust
|
Adjust
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
<td style={styles.thTd}>
|
<td className="p-2.5 border border-gray-300 text-left">
|
||||||
{/* Bouton de suppression */}
|
|
||||||
<button
|
<button
|
||||||
style={{
|
|
||||||
...styles.button,
|
|
||||||
backgroundColor: "#dc3545",
|
|
||||||
padding: "5px 10px",
|
|
||||||
}}
|
|
||||||
onClick={() => handleDeleteUser(user.id)}
|
onClick={() => handleDeleteUser(user.id)}
|
||||||
|
className="py-1 px-2.5 bg-red-600 text-white rounded-md cursor-pointer"
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
@ -224,22 +189,36 @@ function User() {
|
|||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
{/* Tableau des logs */}
|
{/* Tableau des logs */}
|
||||||
<section className="user-logs" style={{ marginTop: "40px" }}>
|
<section className="mt-10">
|
||||||
<h2>Login History and Action Logs</h2>
|
<h2 className="text-xl font-bold mb-4">
|
||||||
<table style={styles.userTable}>
|
Login History and Action Logs
|
||||||
|
</h2>
|
||||||
|
<table className="w-full border-collapse">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ ...styles.thTd, ...styles.th }}>Username</th>
|
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
||||||
<th style={{ ...styles.thTd, ...styles.th }}>Action</th>
|
Username
|
||||||
<th style={{ ...styles.thTd, ...styles.th }}>Timestamp</th>
|
</th>
|
||||||
|
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
||||||
|
Action
|
||||||
|
</th>
|
||||||
|
<th className="p-2.5 border border-gray-300 bg-gray-100 text-left">
|
||||||
|
Timestamp
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{logs.map((log) => (
|
{logs.map((log) => (
|
||||||
<tr key={log.id}>
|
<tr key={log.id}>
|
||||||
<td style={styles.thTd}>{log.username}</td>
|
<td className="p-2.5 border border-gray-300 text-left">
|
||||||
<td style={styles.thTd}>{log.action}</td>
|
{log.username}
|
||||||
<td style={styles.thTd}>{log.timestamp}</td>
|
</td>
|
||||||
|
<td className="p-2.5 border border-gray-300 text-left">
|
||||||
|
{log.action}
|
||||||
|
</td>
|
||||||
|
<td className="p-2.5 border border-gray-300 text-left">
|
||||||
|
{log.timestamp}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@ -1,9 +1,27 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Menu, X } from "lucide-react";
|
||||||
|
|
||||||
function Sidebar() {
|
function Sidebar({ isOpen, toggleSidebar }) {
|
||||||
return (
|
return (
|
||||||
<aside className="w-[250px] bg-gray-800 text-white p-5 h-screen box-border">
|
<aside
|
||||||
<h2 className="text-xl font-bold mb-4">Admin Panel</h2>
|
className={`
|
||||||
|
bg-gray-800 text-white p-5 h-screen w-64 fixed top-0 left-0 z-40
|
||||||
|
transform transition-transform duration-200 ease-in-out
|
||||||
|
${isOpen ? "translate-x-0" : "-translate-x-full"}
|
||||||
|
md:static md:translate-x-0
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{/* En-tête visible sur mobile avec bouton de fermeture */}
|
||||||
|
<div className="flex justify-between items-center md:hidden mb-4">
|
||||||
|
<h2 className="text-xl font-bold">Admin Panel</h2>
|
||||||
|
<button onClick={toggleSidebar} className="focus:outline-none">
|
||||||
|
<X size={24} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/* En-tête pour les écrans md+ */}
|
||||||
|
<div className="hidden md:block mb-4">
|
||||||
|
<h2 className="text-xl font-bold">Admin Panel</h2>
|
||||||
|
</div>
|
||||||
<nav>
|
<nav>
|
||||||
<ul className="list-none p-0">
|
<ul className="list-none p-0">
|
||||||
<li className="mb-3">
|
<li className="mb-3">
|
||||||
@ -43,13 +61,4 @@ function Sidebar() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function App() {
|
export default Sidebar;
|
||||||
return (
|
|
||||||
<div className="flex h-screen m-0 p-0">
|
|
||||||
<Sidebar />
|
|
||||||
<main className="flex-1 ">{/* Ajoutez ici le contenu principal */}</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import { Calendar, Settings, LayoutDashboard } from "lucide-react";
|
|
||||||
|
|
||||||
function AdminDashboard() {
|
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState('dashboard');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
||||||
{/* SideMenu */}
|
|
||||||
<div className="w-64 bg-white rounded-lg shadow-sm p-4">
|
|
||||||
<h2 className="text-lg font-semibold text-gray-800 mb-4">
|
|
||||||
Administration
|
|
||||||
</h2>
|
|
||||||
<nav className="flex flex-col space-y-2">
|
|
||||||
<button
|
|
||||||
onClick={() => setActiveTab('events')}
|
|
||||||
className={`w-full flex items-center gap-2 px-4 py-2 rounded-lg ${
|
|
||||||
activeTab === 'events'
|
|
||||||
? 'bg-red-50 text-red-600'
|
|
||||||
: 'text-gray-600 hover:bg-gray-50'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<Calendar size={20} />
|
|
||||||
Events
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button onClick="" className="">
|
|
||||||
<LayoutDashboard size="15" />
|
|
||||||
Layout
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button onClick="">
|
|
||||||
<Settings size="15" />
|
|
||||||
Settings
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
<h2>Test</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AdminDashboard;
|
|
||||||
Loading…
Reference in New Issue
Block a user