zkt26/z3/Front-end/src/pages/Admin/Dashboard.jsx
2026-05-12 18:11:00 +02:00

409 lines
16 KiB
JavaScript

import React, { useState, useEffect } from "react";
import Sidebar from "./sidebar.jsx";
import { RadioTower,Minus, ArrowRight, BadgePlus, Settings } from "lucide-react";
import { useTranslation } from "react-i18next";
import { API_BASE_URL } from "../../config.js";
import axios from "axios";
const exportCSV = () => {
const headers = ["Catégorie", "Valeur"];
const rows = [
["Consommation énergétique", "1372 kWh"],
["Taux de connexion", "87%"],
["Service", "Consultation des données météo"],
["Service", "Alertes et suivi de consommation"],
["Service", "Ajout d'objets connectés"],
];
const csvContent =
"\uFEFF" +
[headers, ...rows]
.map((row) => row.map((val) => `"${val.replace(/"/g, '""')}"`).join(","))
.join("\n");
const blob = new Blob([csvContent], {
type: "text/csv;charset=utf-8;",
});
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.setAttribute("download", "rapport_plateforme.csv");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
const initialWidgets = [
{ id: 1, type: "summary" },
{ id: 2, type: "users" },
{ id: 3, type: "reporting" },
{ id: 4, type: "adminobjet" },
{ id: 5, type: "objects" },
];
function Dashboard() {
const { t } = useTranslation();
const [users, setUsers] = useState([]);
const [logs, setLogs] = useState([
{
id: 1,
username: "complexe",
action: "Accès attribué",
timestamp: new Date().toLocaleString(),
},
{
id: 2,
username: "admin",
action: "Accès attribué",
timestamp: new Date().toLocaleString(),
},
]);
useEffect(() => {
axios.get(`${API_BASE_URL}/users`).then((response) => {
setUsers(response.data);
});
axios.get(`${API_BASE_URL}/objets`).then((response) => {
setAdminObjects(response.data);
});
}, []);
const [adminObjects, setAdminObjects] = useState([]);
const [manageMode, setManageMode] = useState(false);
const [widgets, setWidgets] = useState(initialWidgets);
const [showAddWidgetModal, setShowAddWidgetModal] = useState(false);
const handleDeleteWidget = (id) => {
setWidgets(widgets.filter((widget) => widget.id !== id));
};
const openAddWidgetModal = () => {
setShowAddWidgetModal(true);
};
const handleWidgetSelection = (widgetType) => {
const newWidget = { id: Date.now(), type: widgetType };
setWidgets([...widgets, newWidget]);
setShowAddWidgetModal(false);
};
return (
<div className="flex min-h-screen">
<Sidebar />
<main className="flex-1 bg-gradient-to-br from-blue-50 to-indigo-50 p-8 overflow-auto">
<div className="flex items-center justify-between mb-6">
<h1 className="text-3xl font-bold truncate mr-2">{t('admin.dashboard.title')}</h1>
<button
onClick={() => setManageMode(!manageMode)}
className="flex items-center justify-center rounded-md hover:bg-gray-300"
aria-label={
manageMode ? t('admin.dashboard.manageWidgetsEnd') : t('admin.dashboard.manageWidgets')
}
>
<span className="p-2 sm:bg-gray-200 sm:px-4 sm:py-2 sm:rounded-md flex items-center">
<Settings size={20} className="sm:mr-2" />
<span className="hidden sm:inline">
{manageMode ? t('admin.dashboard.manageWidgetsEnd') : t('admin.dashboard.manageWidgets')}
</span>
</span>
</button>
</div>
<section>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{widgets.map((widget) => (
<div
key={widget.id}
className="relative bg-white p-6 rounded-xl shadow hover:shadow-md"
>
{manageMode && (
<button
onClick={() => handleDeleteWidget(widget.id)}
className="absolute top-2 right-2 bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center"
>
<Minus />
</button>
)}
{widget.type === "summary" && (
<div>
<h2 className="text-xl font-semibold mb-4">
{t('admin.dashboard.summary')}
</h2>
<div className="mb-4">
<h3 className="text-lg font-medium">{t('admin.dashboard.totalUsers')}</h3>
<p className="text-2xl">{users.length}</p>
</div>
<div>
<h3 className="text-lg font-medium">{t('admin.dashboard.lastLog')}</h3>
{logs.length > 0 ? (
<p>
{logs[logs.length - 1].username} -{" "}
{logs[logs.length - 1].action}
</p>
) : (
<p>{t('admin.dashboard.noLog')}</p>
)}
</div>
</div>
)}
{widget.type === "users" && (
<div>
<h2 className="text-xl font-semibold mb-4">
{t('admin.dashboard.usersList')}
</h2>
<div className="overflow-x-auto">
<table className="min-w-[320px] w-full border border-gray-200">
<thead>
<tr>
<th className="px-2 py-1 border border-gray-200 bg-gray-100 text-left">
{t('admin.dashboard.username')}
</th>
<th className="px-2 py-1 border border-gray-200 bg-gray-100 text-left">
{t('admin.dashboard.email')}
</th>
<th className="px-2 py-1 border border-gray-200 bg-gray-100 text-left">
{t('admin.dashboard.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.pseudo}
</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.role}
</td>
</tr>
))}
{users.length === 0 && (
<tr>
<td
colSpan="3"
className="px-2 py-1 border border-gray-200 text-center"
>
{t('admin.dashboard.noUser')}
</td>
</tr>
)}
</tbody>
</table>
</div>
<button
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-md"
onClick={() => (window.location.href = "/user")}
>
{t('admin.dashboard.seeMore')}
</button>
</div>
)}
{widget.type === "objects" && (
<div>
<h2 className="text-xl font-semibold mb-4">
{t('admin.dashboard.objectsManagement')}
</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" />
{t('admin.dashboard.consultObjects')}
<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" />
{t('admin.dashboard.addObject')}
<ArrowRight size={16} className="ml-2" />
</a>
</div>
</div>
)}
{widget.type === "adminobjet" && (
<div>
<h2 className="text-xl font-semibold mb-4">
{t('admin.dashboard.objectsList')}
</h2>
<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.name}</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"
>
{t('admin.dashboard.seeMore')}
</button>
</div>
)}
{widget.type === "requestObject" && (
<div>
<h2 className="text-xl font-semibold mb-4">
{t('admin.dashboard.requestDelete')}
</h2>
<div className="mb-4">
<p className="text-gray-700 mb-2">
{t('admin.dashboard.generateReports')}
</p>
<div className="flex gap-4">
<button
className="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700"
onClick={() => exportCSV()}
>
{t('admin.dashboard.requestObjects')}
</button>
</div>
</div>
</div>
)}
{widget.type === "reporting" && (
<div>
<h2 className="text-xl font-semibold mb-4">
{t('admin.dashboard.reportsStats')}
</h2>
<div className="mb-4">
<p className="text-gray-700 mb-2">
{t('admin.dashboard.generateReports')}
</p>
<div className="flex gap-4">
<button
className="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700"
onClick={() => exportCSV()}
>
{t('admin.dashboard.exportCsv')}
</button>
</div>
</div>
<div className="mt-4 space-y-2">
<div>
<h4 className="text-md font-medium">
{t('admin.dashboard.energyConsumption')}
</h4>
<p className="text-gray-600">
{t('admin.dashboard.energyConsumptionDesc')}
</p>
</div>
<div>
<h4 className="text-md font-medium">
{t('admin.dashboard.connectionRate')}
</h4>
<p className="text-gray-600">
{t('admin.dashboard.connectionRateDesc')}
</p>
</div>
<div>
<h4 className="text-md font-medium">
{t('admin.dashboard.mostUsedServices')}
</h4>
<ul className="list-disc ml-6 text-gray-600">
<li>Consultation des données météo</li>
<li>Alertes et suivi de consommation</li>
<li>Ajout d'objets connectés</li>
</ul>
</div>
</div>
</div>
)}
</div>
))}
<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>{t('admin.dashboard.addWidget')}</span>
</button>
</div>
</div>
</section>
{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">
{t('admin.dashboard.chooseWidget')}
</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"
>
{t('admin.dashboard.widgetSummary')}
</button>
<button
onClick={() => handleWidgetSelection("users")}
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
>
{t('admin.dashboard.widgetUsers')}
</button>
<button
onClick={() => handleWidgetSelection("objects")}
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
>
{t('admin.dashboard.widgetObjects')}
</button>
<button
onClick={() => handleWidgetSelection("adminobjet")}
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
>
{t('admin.dashboard.widgetObjectsList')}
</button>
<button
onClick={() => handleWidgetSelection("reporting")}
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
>
{t('admin.dashboard.widgetReports')}
</button>
<button
onClick={() => handleWidgetSelection("requestObject")}
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded-md text-left"
>
{t('admin.dashboard.widgetDelete')}
</button>
</div>
<button
onClick={() => setShowAddWidgetModal(false)}
className="mt-4 px-4 py-2 bg-red-500 text-white rounded-md w-full"
>
{t('admin.dashboard.cancel')}
</button>
</div>
</div>
)}
</main>
</div>
);
}
export default Dashboard;