page admin avec user et adminobjet

This commit is contained in:
Arcade69 2025-04-08 10:15:52 +02:00 committed by GitHub
parent eee571713f
commit 453a7f571f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 847 additions and 0 deletions

View 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;

View 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;

View 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;

View 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;