From 917016a7cf3e08bdf0f9da64eee5feebe2954e9e Mon Sep 17 00:00:00 2001 From: Esteban Date: Wed, 17 Dec 2025 13:18:43 -0600 Subject: [PATCH] Device Management section --- src/App.tsx | 10 +- src/pages/AreaManagement.tsx | 10 +- src/pages/DeviceManagement.tsx | 670 +++++++++++++++++++++++---------- 3 files changed, 481 insertions(+), 209 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 21ce922..638dd0a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,10 +8,6 @@ import DataMonitoring from "./pages/DataMonitoring"; import DataQuery from "./pages/DataQuery"; import Home from "./pages/Home"; -// Tipos para las páginas que reciben subPage -interface PageProps { - subPage: string; -} export default function App() { const [page, setPage] = useState("home"); @@ -22,11 +18,11 @@ export default function App() { case "home": return ; case "area": - return ; // ahora tipado correctamente + return ; case "operator": - return ; // también + return ; case "device-management": - return ; + return ; case "data-monitoring": return ; case "data-query": diff --git a/src/pages/AreaManagement.tsx b/src/pages/AreaManagement.tsx index c2be672..f504ee3 100644 --- a/src/pages/AreaManagement.tsx +++ b/src/pages/AreaManagement.tsx @@ -153,8 +153,14 @@ export default function AreaManagement() { diff --git a/src/pages/DeviceManagement.tsx b/src/pages/DeviceManagement.tsx index eaef2de..805ec64 100644 --- a/src/pages/DeviceManagement.tsx +++ b/src/pages/DeviceManagement.tsx @@ -1,233 +1,503 @@ -import { useState } from "react"; -import { DataGrid, GridColDef } from "@mui/x-data-grid"; -import { Add, Delete, Refresh, Edit } from "@mui/icons-material"; -import { Button, IconButton, Dialog, DialogTitle, DialogContent, DialogActions, TextField, CircularProgress } from "@mui/material"; +import { useEffect, useState } from "react"; +import { Plus, Trash2, Pencil, RefreshCcw } from "lucide-react"; +import MaterialTable from "@material-table/core"; interface Device { - id: number; - areaName: string; - deviceSn: string; - deviceName: string; - deviceType: string; - deviceStatus: string; - operator: string; - installedTime: string; - communicationTime: string; + id: string; + "Area Name": string; + "Account Number": string; + "User Name": string; + "User Address": string; + "Meter S/N": string; + "Meter Name": string; + "Meter Status": string; + "Protocol Type": string; + "Price No.": string; + "Price Name": string; + "DMA Partition": string; + "Supply Types": string; + "Device ID": string; + "Device Name": string; + "Device Type": string; + "Usage Analysis Type": string; + "Installed Time": string; } -interface DeviceManagementProps { - subPage: string; +interface ApiResponse { + records: Device[]; + next?: string; + prev?: string; + nestedNext?: string; + nestedPrev?: string; } -export default function DeviceManagement({ subPage: _subPage }: DeviceManagementProps) { - const [rows, setRows] = useState([ - { - id: 1, - areaName: "Operaciones", - deviceSn: "DEV001", - deviceName: "Water Meter A1", - deviceType: "Flow Sensor", - deviceStatus: "Installed", - operator: "Juan Pérez", - installedTime: "2024-01-15 10:30:00", - communicationTime: "2024-12-16 14:25:00" - }, - { - id: 2, - areaName: "Calidad", - deviceSn: "DEV002", - deviceName: "Pressure Monitor B2", - deviceType: "Pressure Sensor", - deviceStatus: "Installed", - operator: "María García", - installedTime: "2024-02-20 09:15:00", - communicationTime: "2024-12-16 13:45:00" - }, - { - id: 3, - areaName: "Mantenimiento", - deviceSn: "DEV003", - deviceName: "Temperature Sensor C3", - deviceType: "Temp Sensor", - deviceStatus: "Uninstalled", - operator: "Carlos López", - installedTime: "2024-03-10 11:00:00", - communicationTime: "2024-12-15 16:30:00" - }, - ]); - - const [dialogOpen, setDialogOpen] = useState(false); - const [editMode, setEditMode] = useState(false); - const [currentDevice, setCurrentDevice] = useState({ - id: 0, - areaName: "", - deviceSn: "", - deviceName: "", - deviceType: "", - deviceStatus: "", - operator: "", - installedTime: "", - communicationTime: "", - }); - +export default function DeviceManagement() { + const [devices, setDevices] = useState([]); + const [search, setSearch] = useState(""); + const [showModal, setShowModal] = useState(false); + const [editingId, setEditingId] = useState(null); + const [activeDevice, setActiveDevice] = useState(null); const [loading, setLoading] = useState(false); - const columns: GridColDef[] = [ - { field: "areaName", headerName: "Area Name", width: 150 }, - { field: "deviceSn", headerName: "Device S/N", width: 130 }, - { field: "deviceName", headerName: "Device Name", width: 180 }, - { field: "deviceType", headerName: "Device Type", width: 130 }, - { field: "deviceStatus", headerName: "Device Status", width: 130 }, - { field: "operator", headerName: "Operator", width: 150 }, - { field: "installedTime", headerName: "Installed Time", width: 180 }, - { field: "communicationTime", headerName: "Communication Time", width: 180 }, - { - field: "actions", - headerName: "Actions", - width: 150, - renderCell: (params) => ( -
- handleEdit(params.row)}> - - - handleDelete(params.row.id)}> - - -
- ), - }, - ]; + const emptyDevice: Omit = { + "Area Name": "", + "Account Number": "", + "User Name": "", + "User Address": "", + "Meter S/N": "", + "Meter Name": "", + "Meter Status": "", + "Protocol Type": "", + "Price No.": "", + "Price Name": "", + "DMA Partition": "", + "Supply Types": "", + "Device ID": "", + "Device Name": "", + "Device Type": "", + "Usage Analysis Type": "", + "Installed Time": "", + }; - const handleDelete = (id: number) => { - if (confirm("¿Deseas eliminar este dispositivo?")) { - setRows(rows.filter(row => row.id !== id)); + const [form, setForm] = useState>(emptyDevice); + + const loadData = async () => { + setLoading(true); + try { + const response = await fetch( + "/api/v3/data/ppfu31vhv5gf6i0/mp1izvcpok5rk6s/records" + ); + const data: ApiResponse = await response.json(); + setDevices(data.records); + setActiveDevice(null); + } catch (error) { + console.error("Error loading devices:", error); + const mockData: Device[] = [ + { + id: "1", + "Area Name": "Operaciones", + "Account Number": "ACC001", + "User Name": "Juan Pérez", + "User Address": "Calle Principal 123", + "Meter S/N": "DEV001", + "Meter Name": "Water Meter A1", + "Meter Status": "Active", + "Protocol Type": "MQTT", + "Price No.": "P001", + "Price Name": "Standard Rate", + "DMA Partition": "Zone A", + "Supply Types": "Water", + "Device ID": "D001", + "Device Name": "Flow Sensor", + "Device Type": "Flow Sensor", + "Usage Analysis Type": "Daily", + "Installed Time": "2024-01-15 10:30:00", + }, + { + id: "2", + "Area Name": "Calidad", + "Account Number": "ACC002", + "User Name": "María García", + "User Address": "Avenida Central 456", + "Meter S/N": "DEV002", + "Meter Name": "Pressure Monitor B2", + "Meter Status": "Active", + "Protocol Type": "LoRa", + "Price No.": "P002", + "Price Name": "Premium Rate", + "DMA Partition": "Zone B", + "Supply Types": "Water", + "Device ID": "D002", + "Device Name": "Pressure Sensor", + "Device Type": "Pressure Sensor", + "Usage Analysis Type": "Hourly", + "Installed Time": "2024-02-20 09:15:00", + }, + ]; + setDevices(mockData); + } finally { + setLoading(false); } }; - const handleEdit = (device: Device) => { - setCurrentDevice(device); - setEditMode(true); - setDialogOpen(true); + useEffect(() => { + loadData(); + }, []); + + const handleSave = () => { + if (editingId) { + setDevices((prev) => + prev.map((device) => + device.id === editingId ? { ...device, ...form } : device + ) + ); + } else { + const newDevice: Device = { + id: Date.now().toString(), + ...form, + }; + setDevices((prev) => [...prev, newDevice]); + } + + setShowModal(false); + setEditingId(null); + setForm(emptyDevice); }; - const handleAdd = () => { - const newId = rows.length ? Math.max(...rows.map(r => r.id)) + 1 : 1; - setRows([...rows, { ...currentDevice, id: newId }]); - setDialogOpen(false); - resetForm(); + const handleEdit = () => { + if (!activeDevice) return; + setEditingId(activeDevice.id); + setForm({ ...activeDevice }); + setShowModal(true); }; - const handleUpdate = () => { - setRows(rows.map(r => (r.id === currentDevice.id ? currentDevice : r))); - setDialogOpen(false); - resetForm(); + const handleDelete = () => { + if (!activeDevice) return; + + if (confirm("¿Deseas eliminar este dispositivo?")) { + setDevices((prev) => + prev.filter((device) => device.id !== activeDevice.id) + ); + setActiveDevice(null); + } }; - const resetForm = () => { - setCurrentDevice({ - id: 0, - areaName: "", - deviceSn: "", - deviceName: "", - deviceType: "", - deviceStatus: "", - operator: "", - installedTime: "", - communicationTime: "", - }); - setEditMode(false); - }; - - const handleRefresh = () => { - setLoading(true); - setTimeout(() => { - setRows([...rows]); - setLoading(false); - }, 1000); - }; + const filteredDevices = devices.filter((device) => { + const q = search.toLowerCase(); + return ( + device["Area Name"].toLowerCase().includes(q) || + device["User Name"].toLowerCase().includes(q) || + device["Meter S/N"].toLowerCase().includes(q) || + device["Device Name"].toLowerCase().includes(q) + ); + }); return ( -
+
+
+
+
+

Device Management

+

Water Meter Devices

+
-
-

Device Management

-
- +
+ - + + + + + +
-
-
- setSearch(e.target.value)} + /> + + ( + + {rowData["Meter Status"]} + + ), + }, + { title: "Protocol Type", field: "Protocol Type" }, + { title: "Price No.", field: "Price No." }, + { title: "Price Name", field: "Price Name" }, + { title: "DMA Partition", field: "DMA Partition" }, + { title: "Supply Types", field: "Supply Types" }, + { title: "Device ID", field: "Device ID" }, + { title: "Device Name", field: "Device Name" }, + { title: "Device Type", field: "Device Type" }, + { title: "Usage Analysis Type", field: "Usage Analysis Type" }, + { + title: "Installed Time", + field: "Installed Time", + type: "datetime", + }, + ]} + data={filteredDevices} + onRowClick={(_event, rowData) => { + setActiveDevice(rowData as Device); + }} + actions={[ + { + icon: () => , + tooltip: "Edit Device", + onClick: (_event, rowData) => { + setActiveDevice(rowData as Device); + setEditingId((rowData as Device).id); + setForm({ ...(rowData as Device) }); + setShowModal(true); }, }, + { + icon: () => , + tooltip: "Delete Device", + onClick: (_event, rowData) => { + setActiveDevice(rowData as Device); + handleDelete(); + }, + }, + ]} + options={{ + actionsColumnIndex: -1, + search: false, + paging: true, + sorting: true, + headerStyle: { + textAlign: "center", + fontWeight: 600, + }, + maxBodyHeight: "500px", + tableLayout: "fixed", + rowStyle: (rowData) => ({ + backgroundColor: + activeDevice?.id === (rowData as Device).id + ? "#EEF2FF" + : "#FFFFFF", + }), }} - pageSizeOptions={[5]} - sx={{ border: "none", "& .MuiDataGrid-row:hover": { backgroundColor: "rgba(0,0,0,0.03)" } }} + isLoading={loading} />
- { setDialogOpen(false); resetForm(); }}> - {editMode ? "Editar Dispositivo" : "Agregar Nuevo Dispositivo"} - - {["areaName","deviceSn","deviceName","deviceType","deviceStatus","operator","installedTime","communicationTime"].map((field) => ( - str.toUpperCase())} - type="text" - value={String(currentDevice[field as keyof Device] || "")} - onChange={(e) => setCurrentDevice({ ...currentDevice, [field]: e.target.value })} - fullWidth - /> - ))} - - - - - - + {showModal && ( +
+
+

+ {editingId ? "Edit Device" : "Add Device"} +

+ +
+ + setForm({ ...form, "Area Name": e.target.value }) + } + /> + + + setForm({ ...form, "Account Number": e.target.value }) + } + /> + + + setForm({ ...form, "User Name": e.target.value }) + } + /> + + + setForm({ ...form, "User Address": e.target.value }) + } + /> + + + setForm({ ...form, "Meter S/N": e.target.value }) + } + /> + + + setForm({ ...form, "Meter Name": e.target.value }) + } + /> + + + + + setForm({ ...form, "Protocol Type": e.target.value }) + } + /> + + + setForm({ ...form, "Price No.": e.target.value }) + } + /> + + + setForm({ ...form, "Price Name": e.target.value }) + } + /> + + + setForm({ ...form, "DMA Partition": e.target.value }) + } + /> + + + setForm({ ...form, "Supply Types": e.target.value }) + } + /> + + + setForm({ ...form, "Device ID": e.target.value }) + } + /> + + + setForm({ ...form, "Device Name": e.target.value }) + } + /> + + + setForm({ ...form, "Device Type": e.target.value }) + } + /> + + + setForm({ ...form, "Usage Analysis Type": e.target.value }) + } + /> + + + setForm({ ...form, "Installed Time": e.target.value }) + } + /> +
+ +
+ + +
+
+
+ )}