diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 38932c8..391e496 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -11,6 +11,7 @@ import { } from "recharts"; import { fetchMeters, type Meter } from "../api/meters"; import { getAuditLogs, type AuditLog } from "../api/audit"; +import { fetchNotifications, type Notification } from "../api/notifications"; import { getCurrentUserRole } from "../api/auth"; import type { Page } from "../App"; import grhWatermark from "../assets/images/grhWatermark.png"; @@ -175,11 +176,62 @@ export default function Home({ return organismsData.filter((o) => o.name.toLowerCase().includes(q)); }, [organismQuery]); - const alerts: AlertItem[] = [ - { company: "Empresa A", type: "Fuga", time: "Hace 2 horas" }, - { company: "Empresa C", type: "Consumo alto", time: "Hace 5 horas" }, - { company: "Empresa B", type: "Inactividad", time: "Hace 8 horas" }, - ]; + const [notifications, setNotifications] = useState([]); + const [loadingNotifications, setLoadingNotifications] = useState(false); + + const loadNotifications = async () => { + setLoadingNotifications(true); + try { + const response = await fetchNotifications({ limit: 10, page: 1 }); + setNotifications(response.data); + } catch (err) { + console.error("Error loading notifications:", err); + setNotifications([]); + } finally { + setLoadingNotifications(false); + } + }; + + useEffect(() => { + if (!isOperator) { + loadNotifications(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const formatNotificationType = (type: string): string => { + const typeMap: Record = { + NEGATIVE_FLOW: "Flujo Negativo", + SYSTEM_ALERT: "Alerta del Sistema", + MAINTENANCE: "Mantenimiento", + }; + return typeMap[type] || type; + }; + + const formatNotificationTime = (dateString: string): string => { + const date = new Date(dateString); + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMins = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMs / 3600000); + const diffDays = Math.floor(diffMs / 86400000); + + if (diffMins < 1) return "Hace un momento"; + if (diffMins < 60) return `Hace ${diffMins} minuto${diffMins > 1 ? "s" : ""}`; + if (diffHours < 24) return `Hace ${diffHours} hora${diffHours > 1 ? "s" : ""}`; + if (diffDays < 7) return `Hace ${diffDays} día${diffDays > 1 ? "s" : ""}`; + return date.toLocaleDateString(); + }; + + const alerts: AlertItem[] = useMemo( + () => + notifications.map((n) => ({ + company: n.meter_serial_number || "Sistema", + type: formatNotificationType(n.notification_type), + time: formatNotificationTime(n.created_at), + })), + [notifications] + ); const formatAuditAction = (action: string): string => { const actionMap: Record = { @@ -547,20 +599,35 @@ export default function Home({ )} - {/* Últimas alertas */} -
-

Últimas Alertas

-
    - {alerts.map((a, i) => ( -
  • - - {a.company} - {a.type} - - {a.time} -
  • - ))} -
-
+ {!isOperator && ( +
+

Últimas Alertas

+ {loadingNotifications ? ( +
+
+
+ ) : alerts.length === 0 ? ( +

+ No hay alertas disponibles +

+ ) : ( +
    + {alerts.map((a, i) => ( +
  • +
    + + {a.company} - {a.type} + +
    + + {a.time} + +
  • + ))} +
+ )} +
+ )} ); } diff --git a/src/pages/projects/ProjectsPage.tsx b/src/pages/projects/ProjectsPage.tsx index 44f4abc..083f9e0 100644 --- a/src/pages/projects/ProjectsPage.tsx +++ b/src/pages/projects/ProjectsPage.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, useMemo } from "react"; import { Plus, Trash2, Pencil, RefreshCcw } from "lucide-react"; import MaterialTable from "@material-table/core"; import { @@ -10,8 +10,13 @@ import { deleteProject as apiDeleteProject, } from "../../api/projects"; import { fetchMeterTypes, type MeterType } from "../../api/meterTypes"; +import { getCurrentUserRole, getCurrentUserProjectId } from "../../api/auth"; export default function ProjectsPage() { + const userRole = useMemo(() => getCurrentUserRole(), []); + const userProjectId = useMemo(() => getCurrentUserProjectId(), []); + const isOperator = userRole?.toUpperCase() === 'OPERATOR'; + const [projects, setProjects] = useState([]); const [loading, setLoading] = useState(true); const [activeProject, setActiveProject] = useState(null); @@ -46,6 +51,18 @@ export default function ProjectsPage() { } }; + const visibleProjects = useMemo(() => { + if (!isOperator) { + return projects; + } + + if (userProjectId) { + return projects.filter(p => p.id === userProjectId); + } + + return []; + }, [projects, isOperator, userProjectId]); + const loadMeterTypesData = async () => { try { const types = await fetchMeterTypes(); @@ -130,7 +147,7 @@ export default function ProjectsPage() { setShowModal(true); }; - const filtered = projects.filter((p) => + const filtered = visibleProjects.filter((p) => `${p.name} ${p.areaName} ${p.description ?? ""}` .toLowerCase() .includes(search.toLowerCase()) @@ -152,28 +169,34 @@ export default function ProjectsPage() {
- + {!isOperator && ( + + )} - + {!isOperator && ( + + )} - + {!isOperator && ( + + )}