diff --git a/src/pages/OperatorManagement.tsx b/src/pages/OperatorManagement.tsx index 19ca95e..9cb4f12 100644 --- a/src/pages/OperatorManagement.tsx +++ b/src/pages/OperatorManagement.tsx @@ -1,131 +1,493 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; +import { + Plus, + Trash2, + Pencil, + RefreshCcw, + ChevronRight, + ChevronDown, +} from "lucide-react"; +import MaterialTable from "@material-table/core"; -interface OperatorManagementProps { - subPage: string; + +/* ================= TYPES ================= */ +interface Operator { + id: number; + loginName: string; + isSuperAdmin: boolean; + isDisabled: boolean; + userName: string; + cellPhone: string; + createdAt: string; } -export default function OperatorManagement({ subPage }: OperatorManagementProps) { +interface Area { + id: number; + name: string; + operators: Operator[]; + children?: Area[]; +} + +/* ================= COMPONENT ================= */ +export default function OperatorManagement() { + const [areas, setAreas] = useState([]); + const [selectedArea, setSelectedArea] = useState(null); + const [expandedIds, setExpandedIds] = useState([]); const [search, setSearch] = useState(""); + const [showModal, setShowModal] = useState(false); + const [editingId, setEditingId] = useState(null); + const [activeOperator, setActiveOperator] = useState(null); - const users = [ - { id: 1, name: "Neil Sims", email: "neil.sims@flowbite.com", role: "React Developer", status: "Online", img: "https://randomuser.me/api/portraits/men/1.jpg" }, - { id: 2, name: "Bonnie Green", email: "bonnie@flowbite.com", role: "Designer", status: "Online", img: "https://randomuser.me/api/portraits/women/2.jpg" }, - { id: 3, name: "Jese Leos", email: "jese@flowbite.com", role: "Vue JS Developer", status: "Online", img: "https://randomuser.me/api/portraits/men/3.jpg" }, - { id: 4, name: "Thomas Lean", email: "thames@flowbite.com", role: "UI/UX Engineer", status: "Online", img: "https://randomuser.me/api/portraits/men/4.jpg" }, - { id: 5, name: "Leslie Livingston", email: "leslie@flowbite.com", role: "SEO Specialist", status: "Offline", img: "https://randomuser.me/api/portraits/women/5.jpg" }, - ]; + const emptyOperator: Omit = { + loginName: "", + isSuperAdmin: false, + isDisabled: false, + userName: "", + cellPhone: "", + createdAt: new Date().toISOString().slice(0, 10), + }; - const filteredUsers = users.filter( - (user) => - user.name.toLowerCase().includes(search.toLowerCase()) || - user.email.toLowerCase().includes(search.toLowerCase()) - ); + const [form, setForm] = useState>(emptyOperator); - return ( -
- {/* HEADER ANIMADO */} -
-

Gestión de Usuarios

+ /* ================= DATA ================= */ + const loadData = () => { + const mock: Area[] = [ + { + id: 1, + name: "GRH", + operators: [ + { + id: 1, + loginName: "admin_grh", + isSuperAdmin: true, + isDisabled: false, + userName: "Juan Pérez", + cellPhone: "664-123-4567", + createdAt: "2024-01-10", + }, + ], + children: [ + { + id: 2, + name: "CESPT", + operators: [ + { + id: 2, + loginName: "cespt_admin", + isSuperAdmin: false, + isDisabled: false, + userName: "Carlos Ruiz", + cellPhone: "664-555-8899", + createdAt: "2024-02-02", + }, + ], + }, + ], + }, + ]; - {/* BOTONES ESTILO GHOST */} -
- - - + setAreas(mock); + setSelectedArea(mock[0]); + setExpandedIds([1]); + setActiveOperator(null); + }; + + useEffect(() => { + loadData(); + }, []); + + /* ================= TREE ================= */ + const toggleExpand = (id: number) => { + setExpandedIds(prev => + prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id] + ); + }; + + const updateArea = (list: Area[]): Area[] => + list.map(area => { + if (area.id === selectedArea?.id) { + const operators = editingId + ? area.operators.map(op => + op.id === editingId ? { ...op, ...form } : op + ) + : [...area.operators, { id: Date.now(), ...form }]; + + return { ...area, operators }; + } + if (area.children) { + return { ...area, children: updateArea(area.children) }; + } + return area; + }); + + /* ================= CRUD ================= */ + const handleSave = () => { + setAreas(prev => { + const updated = updateArea(prev); + + // 🔑 volver a apuntar al área actual actualizada + const refreshedArea = updated.find( + a => a.id === selectedArea?.id + ) || null; + + setSelectedArea(refreshedArea); + return updated; + }); + + setShowModal(false); + setEditingId(null); + setForm(emptyOperator); + }; + + const handleEdit = () => { + if (!activeOperator) return; + setEditingId(activeOperator.id); + setForm({ ...activeOperator }); + setShowModal(true); + }; + + const handleDelete = () => { + if (!selectedArea || !activeOperator) return; + + const deleteFromTree = (list: Area[]): Area[] => + list.map(area => { + if (area.id === selectedArea.id) { + return { + ...area, + operators: area.operators.filter( + op => op.id !== activeOperator.id + ), + }; + } + if (area.children) { + return { ...area, children: deleteFromTree(area.children) }; + } + return area; + }); + + setAreas(prev => deleteFromTree(prev)); + setActiveOperator(null); + }; + + /* ================= FILTER ================= */ + const filtered = + selectedArea?.operators.filter( + op => + op.loginName.toLowerCase().includes(search.toLowerCase()) || + op.userName.toLowerCase().includes(search.toLowerCase()) + ) || []; + + /* ================= TREE RENDER ================= */ + const renderTree = (area: Area, level = 0) => { + const expanded = expandedIds.includes(area.id); + + return ( +
+
setSelectedArea(area)} + > + {area.children && ( + + )} + {area.name}
+ + {expanded && + area.children?.map(child => renderTree(child, level + 1))} +
+ ); + }; + + const filteredOperators: Operator[] = + selectedArea?.operators.filter(op => { + const q = search.toLowerCase(); + return ( + op.loginName.toLowerCase().includes(q) || + op.userName.toLowerCase().includes(q) || + op.cellPhone.toLowerCase().includes(q) + ); + }) || []; + + /* ================= UI ================= */ + return ( +
+ {/* SIDEBAR */} +
+

+ Organizational Structure +

+ {areas.map(a => renderTree(a))}
- {/* TABLA */} -
+ {/* MAIN */} +
+ {/* HEADER */} +
+
+

Operator Management

+

{selectedArea?.name}

+
+ +
+ {/* ADD */} + + + {/* EDIT */} + + + {/* DELETE */} + + + {/* REFRESH */} + +
+ + +
+ {/* SEARCH */} -
-
+ setSearch(e.target.value)} + /> + + ( + + {rowData.isSuperAdmin ? "Yes" : "No"} + + ), + }, + { + title: "Status", + field: "isDisabled", + render: rowData => ( + + {rowData.isDisabled ? "Off" : "Active"} + + ), + }, + { title: "User", field: "userName" }, + { title: "Phone", field: "cellPhone" }, + { title: "Created", field: "createdAt", type: "date" }, + ]} + data={filtered} + onRowClick={(event, rowData) => { + setActiveOperator(rowData as Operator); + }} + actions={[ + { + icon: () => , + tooltip: "Add Operator", + isFreeAction: true, + onClick: () => { + setForm(emptyOperator); + setEditingId(null); + setShowModal(true); + }, + }, + { + icon: () => , + tooltip: "Edit Operator", + onClick: (event, rowData) => { + setActiveOperator(rowData as Operator); + setEditingId((rowData as Operator).id); + setForm({ ...(rowData as Operator) }); + setShowModal(true); + }, + }, + { + icon: () => , + tooltip: "Delete Operator", + onClick: (event, rowData) => { + setActiveOperator(rowData as Operator); + handleDelete(); + }, + }, + ]} + options={{ + actionsColumnIndex: -1, + search: false, + paging: true, + sorting: true, + headerStyle: { + textAlign: "center", + fontWeight: 600, + }, + cellStyle: { + textAlign: "center", + }, + maxBodyHeight: "400px", + tableLayout: "fixed", + rowStyle: rowData => ({ + backgroundColor: + activeOperator?.id === (rowData as Operator).id + ? "#EEF2FF" + : "#FFFFFF", + }), + }} +/> + + + +
+ + {/* MODAL */} + {showModal && ( +
+
+

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

+ setSearch(e.target.value)} - className="w-full pl-9 pr-3 py-2 border border-gray-300 rounded shadow-sm text-gray-700 text-sm focus:outline-none focus:ring-2 focus:ring-blue-300" + className="w-full border px-3 py-2 rounded" + placeholder="Login Name" + value={form.loginName} + onChange={e => + setForm({ ...form, loginName: e.target.value }) + } /> -
- - - + + + + + + + setForm({ ...form, userName: e.target.value }) + } + /> + + + setForm({ ...form, cellPhone: e.target.value }) + } + /> + + + setForm({ ...form, createdAt: e.target.value }) + } + /> + +
+ +
- - - - - - - - - - - - - {filteredUsers.map((user, index) => ( - - - - - - - - ))} - -
- - NombreRolEstadoAcción
- - - {user.name} -
-
{user.name}
-
{user.email}
-
-
{user.role} -
-
- {user.status} -
-
- -
-
- - + )}
); }