diff --git a/Front-end/src/components/Header.jsx b/Front-end/src/components/Header.jsx index 8b1773c..48ca0c5 100644 --- a/Front-end/src/components/Header.jsx +++ b/Front-end/src/components/Header.jsx @@ -6,9 +6,18 @@ import { useAuth } from "../AuthContext"; function Header() { const { token, user, logout } = useAuth(); const [isMenuOpen, setIsMenuOpen] = useState(false); + const [showAdminDropdown, setShowAdminDropdown] = useState(false); + // La fonction toggleAdminDropdown permet d'ouvrir/fermer le menu déroulant + const toggleAdminDropdown = () => { + setShowAdminDropdown((prev) => !prev); + }; + + // Pour l'instant, le menu "Admin" est toujours affiché. + // TODO: Par la suite, ajoutez une vérification du rôle utilisateur (ex: token && user.role === "admin") + // afin d'afficher ce menu uniquement aux administrateurs. return ( -
+
VigiMétéo @@ -20,6 +29,7 @@ function Header() { {isMenuOpen ? : } + {/* Navigation */} {!token ? ( @@ -152,8 +210,42 @@ function Header() { className="flex items-center gap-2 text-gray-600 hover:text-red-600" > - Déconnexion + Déconnexion + {/* Menu déroulant Admin visible sur sm+ */} +
+ + {showAdminDropdown && ( +
+ setShowAdminDropdown(false)} + > + Dashboard + + setShowAdminDropdown(false)} + > + Gestion des Utilisateurs + + setShowAdminDropdown(false)} + > + Gestion des Objets Connectés + +
+ )} +
)} diff --git a/Front-end/src/pages/Admin/AdminObjet.jsx b/Front-end/src/pages/Admin/AdminObjet.jsx index 336f876..7471ffb 100644 --- a/Front-end/src/pages/Admin/AdminObjet.jsx +++ b/Front-end/src/pages/Admin/AdminObjet.jsx @@ -100,7 +100,7 @@ function AdminObjet() { return (
-
+

Administration des Objets et Outils/Services @@ -163,9 +163,9 @@ function AdminObjet() {

- + {/* Conteneur pour le scroll horizontal */}
- +
@@ -234,8 +234,7 @@ function AdminObjet() {
- - {/* Règles globales */} + {/* RÈGLES GLOBALES */}

Règles Globales

diff --git a/Front-end/src/pages/Admin/Dashboard.jsx b/Front-end/src/pages/Admin/Dashboard.jsx index 3e29bcf..0d823f4 100644 --- a/Front-end/src/pages/Admin/Dashboard.jsx +++ b/Front-end/src/pages/Admin/Dashboard.jsx @@ -1,10 +1,47 @@ -import React, { useState, useEffect } from "react"; +import React, { useState } from "react"; import Sidebar from "./sidebar.jsx"; +import { RadioTower, ArrowRight, BadgePlus, Settings } from "lucide-react"; import { API_BASE_URL } from "../../config.js"; import axios from "axios"; +// Widgets initiaux pour le dashboard +const initialWidgets = [ + { id: 1, type: "summary" }, + { id: 2, type: "users" }, + { id: 3, type: "objects" }, +]; + function Dashboard() { - const [users, setUsers] = useState([]); + // États simulés (données fictives pour l'exemple) + const [users, setUsers] = useState([ + { + id: 1, + username: "Alice", + email: "alice@example.com", + accessLevel: "Admin", + }, + { id: 2, username: "Bob", email: "bob@example.com", accessLevel: "User" }, + { + id: 3, + username: "Charlie", + email: "charlie@example.com", + accessLevel: "Guest", + }, + { + id: 4, + username: "David", + email: "david@example.com", + accessLevel: "User", + }, + { id: 5, username: "Eva", email: "eva@example.com", accessLevel: "User" }, + { + id: 6, + username: "Frank", + email: "frank@example.com", + accessLevel: "Admin", + }, + ]); + const [logs, setLogs] = useState([ { id: 1, @@ -20,71 +57,293 @@ 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); + }; + /* useEffect(() => { axios.get(`${API_BASE_URL}/users`).then((response) => { setUsers(response.data); }); }, []); - + */ return ( -
+
-
-

Dashboard

- -
-
-

Total Users

-

{users.length}

-
-
-

Dernier Log

- {logs.length > 0 ? ( -

- {logs[logs.length - 1].username} - {logs[logs.length - 1].action} -

- ) : ( -

Aucun log

- )} -
+
+ {/* En-tête : titre + bouton pour activer/désactiver le mode gestion */} +
+

Dashboard

+
+ {/* Grille des widgets */}
-

Aperçu des Utilisateurs

-
- - - - - - - - - - {users.slice(0, 5).map((user) => ( - - - - - - ))} - {users.length === 0 && ( - - - +
+ {widgets.map((widget) => ( +
+ {/* Bouton de suppression, visible en mode gestion */} + {manageMode && ( + )} -
-
UsernameEmailNiveau d'accès
{user.name}{user.email}{user.role}
- Aucun utilisateur disponible -
+ + {/* Contenu du widget selon son type */} + {widget.type === "summary" && ( +
+

+ Résumé du tableau de bord +

+
+

Total Utilisateur

+

{users.length}

+
+
+

Dernier Log

+ {logs.length > 0 ? ( +

+ {logs[logs.length - 1].username} -{" "} + {logs[logs.length - 1].action} +

+ ) : ( +

Aucun log

+ )} +
+
+ )} + + {widget.type === "users" && ( +
+

+ Gestion des Utilisateurs +

+
+ + + + + + + + + + {users.slice(0, 5).map((user) => ( + + + + + + ))} + {users.length === 0 && ( + + + + )} + +
+ Username + + Email + + Access +
+ {user.username} + + {user.email} + + {user.accessLevel} +
+ Aucun utilisateur disponible +
+
+ +
+ )} + + {widget.type === "objects" && ( + + )} + + {widget.type === "adminobjet" && ( +
+

+ Liste des Objets et Outils/Services +

+ {/* Afficher seulement les 2 premiers objets */} +
    + {adminObjects.slice(0, 2).map((obj) => ( +
  • +

    {obj.nom}

    +

    {obj.type}

    +

    {obj.status}

    +
  • + ))} +
+ +
+ )} +
+ ))} + + {/* Case pour ajouter un widget */} +
+ +
-
+ + {/* Modal de sélection du type de widget */} + {showAddWidgetModal && ( +
+
+

+ Choisir un type de widget +

+
+ + + + +
+ +
+
+ )}
); diff --git a/Front-end/src/pages/Admin/User.jsx b/Front-end/src/pages/Admin/User.jsx index 7ea7585..63ca0c1 100644 --- a/Front-end/src/pages/Admin/User.jsx +++ b/Front-end/src/pages/Admin/User.jsx @@ -3,35 +3,45 @@ import Sidebar from "./sidebar.jsx"; import { API_BASE_URL } from "../../config.js"; import axios from "axios"; +// Définition de styles utilisés (si nécessaire – vous pouvez convertir ces styles en classes Tailwind) const thTd = "p-2 border border-gray-300 text-left"; const th = `${thTd} bg-gray-100`; function User() { const [users, setUsers] = useState([]); const [logs, setLogs] = useState([]); - const [name, setname] = useState(""); + const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [pointsInput, setPointsInput] = useState({}); + // Ajout d'un utilisateur const handleAddUser = (e) => { e.preventDefault(); const newUser = { - id: Date.now(), + id: Date.now(), // ID généré temporairement ; en production, il sera géré par la BDD. name, email, accessLevel: "User", points: 0, }; setUsers([...users, newUser]); - logAction(name, "Utilisateur ajouté"); - setname(""); + logAction(name, "User added"); + setName(""); setEmail(""); + // TODO : Envoyer newUser à l'API si nécessaire. }; + + // Chargement des utilisateurs depuis l'API au montage du composant useEffect(() => { - axios.get(`${API_BASE_URL}/users`).then((response) => { - setUsers(response.data); - }); + axios + .get(`${API_BASE_URL}/users`) + .then((response) => setUsers(response.data)) + .catch((error) => + console.error("Erreur lors de la récupération des utilisateurs:", error) + ); }, []); + + // Suppression d'un utilisateur const handleDeleteUser = (userId) => { const user = users.find((u) => u.id === userId); if (user) { @@ -55,19 +65,20 @@ function User() { setUsers(users.filter((u) => u.id !== userId)); }; + // Changement du niveau d'accès const handleChangeAccessLevel = (userId, newLevel) => { setUsers( users.map((user) => { - if (user.id === userId && newLevel!=user.role) { - const oldLevel = user.role; - user.role = newLevel; - /*ToDO*/ - if (user.role === "user") { + if (user.id === userId && newLevel !== user.accessLevel) { + const oldLevel = user.accessLevel; + user.accessLevel = newLevel; + // Exemple de remise à zéro ou affectation de points en fonction du rôle : + if (newLevel === "user") { + user.points = 0; + } else if (newLevel === "complexe") { user.points = 60; - } else if (user.role === "complexe") { + } else if (newLevel === "admin") { user.points = 100; - } else if (user.role === "admin") { - user.points = 200; } axios .post(`${API_BASE_URL}/setUserPoints`, { @@ -76,42 +87,42 @@ function User() { }) .then((response) => { alert("Le changement de niveau a bien été enregistré !"); - console.log("Changement de niveau réussit :", response.data); + console.log("Niveau changé:", response.data); }) .catch((error) => { - alert("Il y a eu une erreur dans le changement de niveau !"); - console.error("Erreur lors du changement de niveau :", error); + alert("Erreur lors du changement de niveau !"); + console.error(error); }); - logAction( - user.name, - `Niveau d'accés changé de ${oldLevel} à ${newLevel}` - ); + logAction(user.name, `Access level changed from ${oldLevel} to ${newLevel}`); } return user; }) ); }; + // Ajustement des points : additionne les points saisis aux points existants const handleAdjustPoints = (userId) => { const pointsToAdd = parseInt(pointsInput[userId]) || 0; setUsers( users.map((user) => { if (user.id === userId) { user.points = pointsToAdd; + // On additionne au lieu de remplacer + user.points = (user.points || 0) + pointsToAdd; axios .post(`${API_BASE_URL}/setUserPoints`, { id: user.id, points: user.points, }) .then((response) => { - alert("Les points ont bien été enregistré !"); - console.log("Ajout des points réussit :", response.data); + alert("Les points ont bien été enregistrés !"); + console.log("Points mis à jour :", response.data); }) .catch((error) => { - alert("Il y a eu une erreur dans l'ajout des points!"); - console.error("Erreur lors de l'ajout des points :", error); + alert("Erreur lors de l'ajustement des points !"); + console.error(error); }); - logAction(user.name, `Points ajustés par ${pointsToAdd}`); + logAction(user.name, `Points adjusted by ${pointsToAdd}, new total: ${user.points}`); } return user; }) @@ -119,107 +130,121 @@ function User() { setPointsInput({ ...pointsInput, [userId]: "" }); }; + // Fonction de journalisation des actions const logAction = (name, action) => { - /*TODO*/ - /*Ajouter le suivi dans un journal de log*/ const timestamp = new Date().toLocaleString(); setLogs([...logs, { id: Date.now(), name, action, timestamp }]); }; + // Fonction pour générer et télécharger les logs dans un fichier texte + const downloadLogs = () => { + const logText = logs + .map((log) => `${log.timestamp} - ${log.name} - ${log.action}`) + .join("\n"); + const blob = new Blob([logText], { type: "text/plain;charset=utf-8" }); + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = "logs.txt"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }; + return ( -
+
-

- User Management -

-

Manage users from this panel.

+

Gestion des utilisateurs

+

Gérez les utilisateurs à partir de ce panneau.

{/* Formulaire d'ajout d'utilisateur */}
setname(e.target.value)} + onChange={(e) => setName(e.target.value)} required + className="p-2 border border-gray-300 rounded-md" /> setEmail(e.target.value)} required + className="p-2 border border-gray-300 rounded-md" />
{/* Tableau des utilisateurs */} - +
- - - - - + + + + + {users.map((user) => ( - - - + + - - @@ -228,28 +253,34 @@ function User() {
NomEmailNiveau d'accèsPointsActionsNomEmailNiveau d'accèsPointsActions
{user.name}{user.email} + {user.name}{user.email} + setPointsInput({ ...pointsInput, [user.id]: e.target.value, }) } + className="w-16 ml-2 p-1 border border-gray-300 rounded-md" /> +
{/* Tableau des logs */} -
-

- Historique des connexions et journal des logs{" "} +
+

+ Historique des connexions et journal des logs

- +
- - - + + + {logs.map((log) => ( - - - + + + ))}
NomActionTimestampNomActionTimestamp
{log.name}{log.action}{log.timestamp}{log.name}{log.action}{log.timestamp}
+

diff --git a/Front-end/src/pages/Admin/sidebar.jsx b/Front-end/src/pages/Admin/sidebar.jsx index dbaf762..a47390d 100644 --- a/Front-end/src/pages/Admin/sidebar.jsx +++ b/Front-end/src/pages/Admin/sidebar.jsx @@ -1,9 +1,27 @@ import React from "react"; +import { Menu, X } from "lucide-react"; -function Sidebar() { +function Sidebar({ isOpen, toggleSidebar }) { return ( -