Merge pull request #3 from Charles40130:Ruben

Ruben
This commit is contained in:
Arcade69 2025-04-10 15:12:57 +02:00 committed by GitHub
commit 9690d44ce2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 2429 additions and 10 deletions

File diff suppressed because it is too large Load Diff

View File

@ -26,12 +26,13 @@
"@eslint/js": "^9.9.1", "@eslint/js": "^9.9.1",
"@vitejs/plugin-react": "^4.3.1", "@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.18", "autoprefixer": "^10.4.18",
"eslint": "^9.9.1", "eslint": "^9.23.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.11", "eslint-plugin-react-refresh": "^0.4.11",
"globals": "^15.9.0", "globals": "^15.9.0",
"postcss": "^8.4.35", "postcss": "^8.4.35",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.17",
"vite": "^5.4.2" "vite": "^5.4.2"
}, },
"description": "Bienvenue dans le projet **DevWeb** ! Ce projet utilise **Vite** et **React** pour créer une application web moderne et performante.", "description": "Bienvenue dans le projet **DevWeb** ! Ce projet utilise **Vite** et **React** pour créer une application web moderne et performante.",

View File

@ -1,5 +1,5 @@
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { AuthProvider } from './AuthContext.jsx'; import { AuthProvider } from "./AuthContext.jsx";
import Home from "./pages/Home.jsx"; import Home from "./pages/Home.jsx";
import About from "./pages/About.jsx"; import About from "./pages/About.jsx";
import Gestion from "./pages/Gestion/Gestion.jsx"; import Gestion from "./pages/Gestion/Gestion.jsx";
@ -7,13 +7,19 @@ import Header from "./components/Header.jsx";
import ObjectManagement from "./pages/Gestion/ObjectManagement.jsx"; import ObjectManagement from "./pages/Gestion/ObjectManagement.jsx";
import Objet from "./pages/Gestion/Objet.jsx"; import Objet from "./pages/Gestion/Objet.jsx";
import AddObject from "./pages/Gestion/AddObject.jsx"; import AddObject from "./pages/Gestion/AddObject.jsx";
import Signup from './pages/Signup.jsx'; import Signup from "./pages/Signup.jsx";
import Login from './pages/Login.jsx'; import Login from "./pages/Login.jsx";
import Settings from './pages/Settings.jsx'; import Settings from "./pages/Settings.jsx";
import Sidebar from "./pages/Admin/sidebar.jsx";
import User from "./pages/Admin/User.jsx";
import Dashboard from "./pages/Admin/Dashboard.jsx";
import AdminObjet from "./pages/Admin/AdminObjet.jsx";
function App() { function App() {
return ( return (
<AuthProvider> {/* Enveloppe l'application avec AuthProvider */} <AuthProvider>
{" "}
{/* Enveloppe l'application avec AuthProvider */}
<Router> <Router>
<div> <div>
<Header /> <Header />
@ -27,6 +33,10 @@ function App() {
<Route path="/login" element={<Login />} /> <Route path="/login" element={<Login />} />
<Route path="/ajouterObjet" element={<AddObject />} /> <Route path="/ajouterObjet" element={<AddObject />} />
<Route path="/settings" element={<Settings />} /> <Route path="/settings" element={<Settings />} />
<Route path="/sidebar" element={<Sidebar />} />
<Route path="/user" element={<User />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/adminobjet" element={<AdminObjet />} />
</Routes> </Routes>
</div> </div>
</Router> </Router>

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,154 @@
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,253 @@
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;