page admin avec user et adminobjet
This commit is contained in:
parent
eee571713f
commit
453a7f571f
443
Front-end/src/pages/Admin/AdminObjet.jsx
Normal file
443
Front-end/src/pages/Admin/AdminObjet.jsx
Normal file
@ -0,0 +1,443 @@
|
||||
import React, { useState } from "react";
|
||||
import Sidebar from "./sidebar.jsx";
|
||||
|
||||
function AdminObjet() {
|
||||
// Gestion des catégories
|
||||
const [categories, setCategories] = useState(["Catégorie 1", "Catégorie 2"]);
|
||||
const [newCategory, setNewCategory] = useState("");
|
||||
|
||||
const handleAddCategory = () => {
|
||||
const trimmed = newCategory.trim();
|
||||
if (trimmed !== "" && !categories.includes(trimmed)) {
|
||||
setCategories([...categories, trimmed]);
|
||||
setNewCategory("");
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteCategory = (categoryToDelete) => {
|
||||
setCategories(categories.filter((cat) => cat !== categoryToDelete));
|
||||
};
|
||||
|
||||
// Gestion des objets et outils/services
|
||||
// On ajoute maintenant le champ "propriétaire"
|
||||
const [objects, setObjects] = useState([]);
|
||||
|
||||
// Champs du formulaire d'ajout d'objet (inspiré de AddObject.jsx)
|
||||
const [nom, setNom] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [type, setType] = useState("");
|
||||
const [localisation, setLocalisation] = useState("");
|
||||
const [proprietaire, setProprietaire] = useState("");
|
||||
const [status, setStatus] = useState("active");
|
||||
const [isActive, setIsActive] = useState(true);
|
||||
const [verif, setVerif] = useState(false);
|
||||
const [enregistre, setEnregistre] = useState(false);
|
||||
const [messRequete, setMessRequete] = useState("");
|
||||
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
if (verif) {
|
||||
const newObj = {
|
||||
id: Date.now(),
|
||||
nom: nom.trim(),
|
||||
description: description.trim(),
|
||||
type: type.trim(),
|
||||
localisation: localisation.trim(),
|
||||
proprietaire: proprietaire.trim(),
|
||||
status: status,
|
||||
};
|
||||
setObjects([...objects, newObj]);
|
||||
setMessRequete("Votre objet a bien été enregistré !");
|
||||
setEnregistre(true);
|
||||
setVerif(false);
|
||||
resetForm();
|
||||
} else {
|
||||
setVerif(true);
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setNom("");
|
||||
setDescription("");
|
||||
setType("");
|
||||
setLocalisation("");
|
||||
setProprietaire("");
|
||||
setStatus("active");
|
||||
setIsActive(true);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
if (verif) {
|
||||
setVerif(false);
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
};
|
||||
|
||||
const handleStatusChange = () => {
|
||||
setIsActive((prev) => {
|
||||
const newIsActive = !prev;
|
||||
setStatus(newIsActive ? "active" : "inactive");
|
||||
return newIsActive;
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteObject = (id) => {
|
||||
setObjects(objects.filter((obj) => obj.id !== id));
|
||||
};
|
||||
|
||||
// Tri des objets en fonction d'une catégorie sélectionnée
|
||||
const [sortCriteria, setSortCriteria] = useState("");
|
||||
|
||||
const sortedObjects = [...objects].sort((a, b) => {
|
||||
if (!sortCriteria) return 0;
|
||||
let fieldA = a[sortCriteria] || "";
|
||||
let fieldB = b[sortCriteria] || "";
|
||||
return fieldA.localeCompare(fieldB);
|
||||
});
|
||||
|
||||
// Règles globales
|
||||
const [energyPriority, setPriority] = useState("");
|
||||
const [alertSettings, setAlertSettings] = useState("");
|
||||
|
||||
const handleSaveGlobalRules = () => {
|
||||
console.log("Règles globales enregistrées :", {
|
||||
energyPriority,
|
||||
alertSettings,
|
||||
});
|
||||
alert("Les règles globales ont été enregistrées");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-screen">
|
||||
<Sidebar />
|
||||
<div className="flex-1 bg-gradient-to-br from-blue-50 to-indigo-50 p-8 overflow-auto">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<h1 className="text-4xl font-bold text-gray-900 text-center mb-12">
|
||||
Administration des Objets et Outils/Services
|
||||
</h1>
|
||||
|
||||
{/* Gestion des catégories */}
|
||||
<section className="bg-white p-6 rounded-xl shadow-md mb-12">
|
||||
<h2 className="text-2xl font-semibold mb-4">
|
||||
Gestion des Catégories
|
||||
</h2>
|
||||
<div className="flex items-center mb-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Nouvelle catégorie"
|
||||
value={newCategory}
|
||||
onChange={(e) => setNewCategory(e.target.value)}
|
||||
className="flex-1 border border-gray-300 rounded-lg p-2 mr-4"
|
||||
/>
|
||||
<button
|
||||
onClick={handleAddCategory}
|
||||
className="bg-indigo-600 text-white px-4 py-2 rounded-lg"
|
||||
>
|
||||
Ajouter
|
||||
</button>
|
||||
</div>
|
||||
<ul>
|
||||
{categories.map((cat, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className="flex justify-between items-center border-b border-gray-200 py-2"
|
||||
>
|
||||
<span>{cat}</span>
|
||||
<button
|
||||
onClick={() => handleDeleteCategory(cat)}
|
||||
className="text-red-600 hover:underline"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{/* Formulaire d'ajout d'objet */}
|
||||
<section className="bg-white p-6 rounded-xl shadow-md mb-12">
|
||||
<div className="flex items-center gap-4 mb-5">
|
||||
<div className="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center">
|
||||
<span className="text-indigo-600 text-xl">+</span>
|
||||
</div>
|
||||
<h2 className="text-2xl font-bold text-gray-900">
|
||||
{!verif
|
||||
? "Entrez les données de votre nouvel objet"
|
||||
: "Êtes-vous sûr de ces données ?"}
|
||||
</h2>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit} className="space-y-5">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="nom"
|
||||
className="block mb-2 text-sm font-medium text-gray-900"
|
||||
>
|
||||
Nom :
|
||||
</label>
|
||||
<input
|
||||
id="nom"
|
||||
type="text"
|
||||
value={nom}
|
||||
onChange={(e) => setNom(e.target.value)}
|
||||
required
|
||||
disabled={verif}
|
||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="description"
|
||||
className="block mb-2 text-sm font-medium text-gray-900"
|
||||
>
|
||||
Description :
|
||||
</label>
|
||||
<input
|
||||
id="description"
|
||||
type="text"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
required
|
||||
disabled={verif}
|
||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="type"
|
||||
className="block mb-2 text-sm font-medium text-gray-900"
|
||||
>
|
||||
Type :
|
||||
</label>
|
||||
<input
|
||||
id="type"
|
||||
type="text"
|
||||
value={type}
|
||||
onChange={(e) => setType(e.target.value)}
|
||||
required
|
||||
disabled={verif}
|
||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="localisation"
|
||||
className="block mb-2 text-sm font-medium text-gray-900"
|
||||
>
|
||||
Localisation :
|
||||
</label>
|
||||
<input
|
||||
id="localisation"
|
||||
type="text"
|
||||
value={localisation}
|
||||
onChange={(e) => setLocalisation(e.target.value)}
|
||||
required
|
||||
disabled={verif}
|
||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="proprietaire"
|
||||
className="block mb-2 text-sm font-medium text-gray-900"
|
||||
>
|
||||
Propriétaire :
|
||||
</label>
|
||||
<input
|
||||
id="proprietaire"
|
||||
type="text"
|
||||
value={proprietaire}
|
||||
onChange={(e) => setProprietaire(e.target.value)}
|
||||
required
|
||||
disabled={verif}
|
||||
className="w-full p-2 border border-gray-300 rounded-lg text-gray-600"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900">
|
||||
Status :
|
||||
</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<label
|
||||
htmlFor="switch-component-on"
|
||||
className="text-slate-600 text-sm cursor-pointer"
|
||||
>
|
||||
Inactive
|
||||
</label>
|
||||
<div className="relative inline-block w-11 h-5">
|
||||
<input
|
||||
id="switch-component-on"
|
||||
type="checkbox"
|
||||
checked={isActive}
|
||||
onChange={handleStatusChange}
|
||||
disabled={verif}
|
||||
className="peer appearance-none w-11 h-5 bg-slate-100 rounded-full cursor-pointer transition-colors duration-300"
|
||||
/>
|
||||
<label
|
||||
htmlFor="switch-component-on"
|
||||
className="absolute top-0 left-0 w-5 h-5 bg-white rounded-full border border-slate-300 shadow-sm transition-transform duration-300 peer-checked:translate-x-6 peer-checked:border-slate-800 cursor-pointer"
|
||||
></label>
|
||||
</div>
|
||||
<label
|
||||
htmlFor="switch-component-on"
|
||||
className="text-slate-600 text-sm cursor-pointer"
|
||||
>
|
||||
Active
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<button
|
||||
type="submit"
|
||||
className="text-blue-500 hover:underline mb-2"
|
||||
>
|
||||
{!verif ? "Confirmer les informations" : "Oui je suis sûr !"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCancel}
|
||||
className="text-red-500 hover:underline"
|
||||
>
|
||||
{!verif
|
||||
? "Supprimer les informations"
|
||||
: "Non je veux changer !"}
|
||||
</button>
|
||||
</div>
|
||||
<p className={enregistre ? "text-green-700" : "text-red-700"}>
|
||||
{messRequete}
|
||||
</p>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
{/* Tri des objets */}
|
||||
<section className="bg-white p-6 rounded-xl shadow-md mb-12">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h2 className="text-2xl font-semibold">
|
||||
Liste des Objets et Outils/Services
|
||||
</h2>
|
||||
<select
|
||||
value={sortCriteria}
|
||||
onChange={(e) => setSortCriteria(e.target.value)}
|
||||
className="border border-gray-300 rounded-lg p-2"
|
||||
>
|
||||
<option value="">-- Trier par --</option>
|
||||
<option value="proprietaire">Propriétaire</option>
|
||||
<option value="localisation">Lieux</option>
|
||||
<option value="type">Type</option>
|
||||
<option value="status">Status</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Nom
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Description
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Type
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Localisation
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Propriétaire
|
||||
</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
Status
|
||||
</th>
|
||||
<th className="px-6 py-3"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white divide-y divide-gray-200">
|
||||
{sortedObjects.map((obj) => (
|
||||
<tr key={obj.id}>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
{obj.nom}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{obj.description}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{obj.type}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{obj.localisation}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{obj.proprietaire}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||
{obj.status}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<button
|
||||
onClick={() => handleDeleteObject(obj.id)}
|
||||
className="text-red-600 hover:underline"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{objects.length === 0 && (
|
||||
<tr>
|
||||
<td
|
||||
colSpan="7"
|
||||
className="px-6 py-4 text-center text-sm text-gray-500"
|
||||
>
|
||||
Aucun objet ou service disponible.
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Règles globales */}
|
||||
<section className="bg-white p-6 rounded-xl shadow-md mt-12">
|
||||
<h2 className="text-2xl font-semibold mb-4">Règles Globales</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
||||
<div className="flex flex-col">
|
||||
<label className="mb-2 font-medium text-gray-700">
|
||||
Priorité
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Définir la priorité énergétique"
|
||||
value={energyPriority}
|
||||
onChange={(e) => setPriority(e.target.value)}
|
||||
className="border border-gray-300 rounded-lg p-2"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<label className="mb-2 font-medium text-gray-700">
|
||||
Gestion des alertes
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Définir les règles d'alerte"
|
||||
value={alertSettings}
|
||||
onChange={(e) => setAlertSettings(e.target.value)}
|
||||
className="border border-gray-300 rounded-lg p-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleSaveGlobalRules}
|
||||
className="bg-green-600 text-white px-4 py-2 rounded-lg"
|
||||
>
|
||||
Enregistrer les règles globales
|
||||
</button>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminObjet;
|
||||
118
Front-end/src/pages/Admin/Dashboard.jsx
Normal file
118
Front-end/src/pages/Admin/Dashboard.jsx
Normal file
@ -0,0 +1,118 @@
|
||||
import React, { useState } from 'react';
|
||||
import Sidebar from './sidebar.jsx';
|
||||
|
||||
const dashboardStyles = {
|
||||
mainContent: {
|
||||
flexGrow: 1,
|
||||
padding: '20px',
|
||||
},
|
||||
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() {
|
||||
// États simulés (dans une vraie application, ils viendraient d'une API ou d'un store global)
|
||||
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, username: 'Alice', action: 'User added', timestamp: new Date().toLocaleString() },
|
||||
{ id: 2, username: 'Bob', action: 'Access assigned', timestamp: new Date().toLocaleString() },
|
||||
]);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', minHeight: '100vh' }}>
|
||||
<Sidebar />
|
||||
<main style={dashboardStyles.mainContent}>
|
||||
<h1>Dashboard</h1>
|
||||
<div style={dashboardStyles.summaryContainer}>
|
||||
<div style={dashboardStyles.summaryCard}>
|
||||
<h2>Total Users</h2>
|
||||
<p>{users.length}</p>
|
||||
</div>
|
||||
<div style={dashboardStyles.summaryCard}>
|
||||
<h2>Dernier Log</h2>
|
||||
{logs.length > 0 ? (
|
||||
<p>
|
||||
{logs[logs.length - 1].username} - {logs[logs.length - 1].action}
|
||||
</p>
|
||||
) : (
|
||||
<p>Aucun log</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<h2>Aperçu des Utilisateurs</h2>
|
||||
<table style={dashboardStyles.table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={dashboardStyles.tableHeader}>Username</th>
|
||||
<th style={dashboardStyles.tableHeader}>Email</th>
|
||||
<th style={dashboardStyles.tableHeader}>Access Level</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.slice(0, 5).map(user => (
|
||||
<tr key={user.id}>
|
||||
<td style={dashboardStyles.tableCell}>{user.username}</td>
|
||||
<td style={dashboardStyles.tableCell}>{user.email}</td>
|
||||
<td style={dashboardStyles.tableCell}>{user.accessLevel}</td>
|
||||
</tr>
|
||||
))}
|
||||
{users.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan="3" style={dashboardStyles.tableCell}>Aucun utilisateur disponible</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
{/* Bouton pour accéder à la page complète */}
|
||||
<button style={dashboardStyles.viewMoreButton} onClick={() => window.location.href = '/user'}>
|
||||
Voir plus
|
||||
</button>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Dashboard;
|
||||
231
Front-end/src/pages/Admin/User.jsx
Normal file
231
Front-end/src/pages/Admin/User.jsx
Normal file
@ -0,0 +1,231 @@
|
||||
import React, { useState } from 'react';
|
||||
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() {
|
||||
// États pour la gestion des utilisateurs, des logs, des champs du formulaire et des ajustements de points
|
||||
const [users, setUsers] = useState([]);
|
||||
const [logs, setLogs] = useState([]);
|
||||
const [username, setUsername] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [pointsInput, setPointsInput] = useState({});
|
||||
|
||||
// Ajout d'un utilisateur
|
||||
const handleAddUser = (e) => {
|
||||
e.preventDefault();
|
||||
const newUser = {
|
||||
id: Date.now(),
|
||||
username,
|
||||
email,
|
||||
accessLevel: 'User', // Niveau d'accès par défaut
|
||||
points: 0,
|
||||
};
|
||||
setUsers([...users, newUser]);
|
||||
logAction(username, 'User added');
|
||||
setUsername('');
|
||||
setEmail('');
|
||||
};
|
||||
|
||||
// Suppression d'un utilisateur (fonction présente dans script.js)
|
||||
const handleDeleteUser = (userId) => {
|
||||
const user = users.find(u => u.id === userId);
|
||||
if (user) {
|
||||
logAction(user.username, 'User deleted');
|
||||
}
|
||||
setUsers(users.filter(u => u.id !== userId));
|
||||
};
|
||||
|
||||
// Changement du niveau d'accès via le menu déroulant (fonction issue de script.js)
|
||||
const handleChangeAccessLevel = (userId, newLevel) => {
|
||||
setUsers(users.map(user => {
|
||||
if (user.id === userId) {
|
||||
const oldLevel = user.accessLevel;
|
||||
user.accessLevel = newLevel;
|
||||
logAction(user.username, `Access level changed from ${oldLevel} to ${newLevel}`);
|
||||
}
|
||||
return user;
|
||||
}));
|
||||
};
|
||||
|
||||
// Ajustement des points d'un utilisateur (fonction issue de script.js)
|
||||
const handleAdjustPoints = (userId) => {
|
||||
const pointsToAdd = parseInt(pointsInput[userId]) || 0;
|
||||
setUsers(users.map(user => {
|
||||
if (user.id === userId) {
|
||||
user.points += pointsToAdd;
|
||||
logAction(user.username, `Points adjusted by ${pointsToAdd}`);
|
||||
}
|
||||
return user;
|
||||
}));
|
||||
// Réinitialiser la valeur de l'input pour cet utilisateur
|
||||
setPointsInput({ ...pointsInput, [userId]: '' });
|
||||
};
|
||||
|
||||
// Fonction de journalisation des actions (définie dans script.js)
|
||||
const logAction = (username, action) => {
|
||||
const timestamp = new Date().toLocaleString();
|
||||
setLogs([...logs, { id: Date.now(), username, action, timestamp }]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', minHeight: '100vh' }}>
|
||||
<Sidebar />
|
||||
<main style={styles.mainContent}>
|
||||
<section style={styles.userManagement}>
|
||||
<h1>User Management</h1>
|
||||
<p>Manage users from this panel.</p>
|
||||
{/* Formulaire d'ajout d'utilisateur */}
|
||||
<form style={styles.userForm} onSubmit={handleAddUser}>
|
||||
<input
|
||||
style={styles.input}
|
||||
type="text"
|
||||
id="username"
|
||||
placeholder="Username"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<input
|
||||
style={styles.input}
|
||||
type="email"
|
||||
id="email"
|
||||
placeholder="Email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<button style={styles.button} type="submit">Add User</button>
|
||||
</form>
|
||||
{/* Tableau des utilisateurs */}
|
||||
<table style={styles.userTable}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ ...styles.thTd, ...styles.th }}>Username</th>
|
||||
<th style={{ ...styles.thTd, ...styles.th }}>Email</th>
|
||||
<th style={{ ...styles.thTd, ...styles.th }}>Access Level</th>
|
||||
<th style={{ ...styles.thTd, ...styles.th }}>Points</th>
|
||||
<th style={{ ...styles.thTd, ...styles.th }}>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map(user => (
|
||||
<tr key={user.id}>
|
||||
<td style={styles.thTd}>{user.username}</td>
|
||||
<td style={styles.thTd}>{user.email}</td>
|
||||
<td style={styles.thTd}>
|
||||
{/* Menu déroulant pour changer le niveau d'accès */}
|
||||
<select
|
||||
value={user.accessLevel}
|
||||
onChange={(e) => handleChangeAccessLevel(user.id, e.target.value)}
|
||||
style={{ padding: '5px', borderRadius: '5px' }}
|
||||
>
|
||||
<option value="Admin">Admin</option>
|
||||
<option value="User">User</option>
|
||||
<option value="Guest">Guest</option>
|
||||
</select>
|
||||
</td>
|
||||
<td style={styles.thTd}>
|
||||
<span>{user.points}</span>
|
||||
{/* Input et bouton pour ajuster les points */}
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
style={{ width: '60px', marginLeft: '10px' }}
|
||||
placeholder="Adjust"
|
||||
value={pointsInput[user.id] || ''}
|
||||
onChange={(e) =>
|
||||
setPointsInput({ ...pointsInput, [user.id]: e.target.value })
|
||||
}
|
||||
/>
|
||||
<button
|
||||
style={{ ...styles.button, padding: '5px 10px', marginLeft: '5px' }}
|
||||
onClick={() => handleAdjustPoints(user.id)}
|
||||
>
|
||||
Adjust
|
||||
</button>
|
||||
</td>
|
||||
<td style={styles.thTd}>
|
||||
{/* Bouton de suppression */}
|
||||
<button
|
||||
style={{ ...styles.button, backgroundColor: '#dc3545', padding: '5px 10px' }}
|
||||
onClick={() => handleDeleteUser(user.id)}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
{/* Tableau des logs */}
|
||||
<section className="user-logs" style={{ marginTop: '40px' }}>
|
||||
<h2>Login History and Action Logs</h2>
|
||||
<table style={styles.userTable}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ ...styles.thTd, ...styles.th }}>Username</th>
|
||||
<th style={{ ...styles.thTd, ...styles.th }}>Action</th>
|
||||
<th style={{ ...styles.thTd, ...styles.th }}>Timestamp</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{logs.map(log => (
|
||||
<tr key={log.id}>
|
||||
<td style={styles.thTd}>{log.username}</td>
|
||||
<td style={styles.thTd}>{log.action}</td>
|
||||
<td style={styles.thTd}>{log.timestamp}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default User;
|
||||
55
Front-end/src/pages/Admin/sidebar.jsx
Normal file
55
Front-end/src/pages/Admin/sidebar.jsx
Normal file
@ -0,0 +1,55 @@
|
||||
import React from "react";
|
||||
|
||||
function Sidebar() {
|
||||
return (
|
||||
<aside className="w-[250px] bg-gray-800 text-white p-5 h-screen box-border">
|
||||
<h2 className="text-xl font-bold mb-4">Admin Panel</h2>
|
||||
<nav>
|
||||
<ul className="list-none p-0">
|
||||
<li className="mb-3">
|
||||
<a
|
||||
className="text-white no-underline hover:underline"
|
||||
href="/dashboard"
|
||||
>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-3">
|
||||
<a className="text-white no-underline hover:underline" href="/user">
|
||||
Users
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-3">
|
||||
<a
|
||||
className="text-white no-underline hover:underline"
|
||||
href="/adminobjet"
|
||||
>
|
||||
AdminObjet
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-3">
|
||||
<a className="text-white no-underline hover:underline" href="#">
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
<li className="mb-3">
|
||||
<a className="text-white no-underline hover:underline" href="#">
|
||||
Reports
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
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;
|
||||
Loading…
Reference in New Issue
Block a user