Update OperatorManagement page
This commit is contained in:
@@ -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 {
|
||||||
const [search, setSearch] = useState("");
|
id: number;
|
||||||
|
name: string;
|
||||||
|
operators: Operator[];
|
||||||
|
children?: Area[];
|
||||||
|
}
|
||||||
|
|
||||||
const users = [
|
/* ================= COMPONENT ================= */
|
||||||
{ id: 1, name: "Neil Sims", email: "neil.sims@flowbite.com", role: "React Developer", status: "Online", img: "https://randomuser.me/api/portraits/men/1.jpg" },
|
export default function OperatorManagement() {
|
||||||
{ id: 2, name: "Bonnie Green", email: "bonnie@flowbite.com", role: "Designer", status: "Online", img: "https://randomuser.me/api/portraits/women/2.jpg" },
|
const [areas, setAreas] = useState<Area[]>([]);
|
||||||
{ id: 3, name: "Jese Leos", email: "jese@flowbite.com", role: "Vue JS Developer", status: "Online", img: "https://randomuser.me/api/portraits/men/3.jpg" },
|
const [selectedArea, setSelectedArea] = useState<Area | null>(null);
|
||||||
{ id: 4, name: "Thomas Lean", email: "thames@flowbite.com", role: "UI/UX Engineer", status: "Online", img: "https://randomuser.me/api/portraits/men/4.jpg" },
|
const [expandedIds, setExpandedIds] = useState<number[]>([]);
|
||||||
{ id: 5, name: "Leslie Livingston", email: "leslie@flowbite.com", role: "SEO Specialist", status: "Offline", img: "https://randomuser.me/api/portraits/women/5.jpg" },
|
const [search, setSearch] = useState("");
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
const [editingId, setEditingId] = useState<number | null>(null);
|
||||||
|
const [activeOperator, setActiveOperator] = useState<Operator | null>(null);
|
||||||
|
|
||||||
|
const emptyOperator: Omit<Operator, "id"> = {
|
||||||
|
loginName: "",
|
||||||
|
isSuperAdmin: false,
|
||||||
|
isDisabled: false,
|
||||||
|
userName: "",
|
||||||
|
cellPhone: "",
|
||||||
|
createdAt: new Date().toISOString().slice(0, 10),
|
||||||
|
};
|
||||||
|
|
||||||
|
const [form, setForm] = useState<Omit<Operator, "id">>(emptyOperator);
|
||||||
|
|
||||||
|
/* ================= 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",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const filteredUsers = users.filter(
|
setAreas(mock);
|
||||||
(user) =>
|
setSelectedArea(mock[0]);
|
||||||
user.name.toLowerCase().includes(search.toLowerCase()) ||
|
setExpandedIds([1]);
|
||||||
user.email.toLowerCase().includes(search.toLowerCase())
|
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 (
|
return (
|
||||||
<div className="flex flex-col gap-6 p-6">
|
<div key={area.id}>
|
||||||
{/* HEADER ANIMADO */}
|
<div
|
||||||
<div className="flex flex-col md:flex-row justify-between items-center p-5 rounded-xl relative overflow-hidden"
|
className={`flex items-center gap-1 px-2 py-1 rounded cursor-pointer text-sm
|
||||||
|
${
|
||||||
|
selectedArea?.id === area.id
|
||||||
|
? "bg-blue-50 text-blue-700 font-semibold"
|
||||||
|
: "hover:bg-gray-50"
|
||||||
|
}`}
|
||||||
|
style={{ marginLeft: level * 12 }}
|
||||||
|
onClick={() => setSelectedArea(area)}
|
||||||
|
>
|
||||||
|
{area.children && (
|
||||||
|
<button onClick={() => toggleExpand(area.id)}>
|
||||||
|
{expanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{area.name}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{expanded &&
|
||||||
|
area.children?.map(child => renderTree(child, level + 1))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div className="flex gap-6 p-6 w-full bg-gray-100">
|
||||||
|
{/* SIDEBAR */}
|
||||||
|
<div className="w-72 bg-white rounded-xl shadow p-4">
|
||||||
|
<h3 className="text-xs font-semibold text-gray-500 mb-3">
|
||||||
|
Organizational Structure
|
||||||
|
</h3>
|
||||||
|
{areas.map(a => renderTree(a))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* MAIN */}
|
||||||
|
<div className="flex-1 flex flex-col gap-6">
|
||||||
|
{/* HEADER */}
|
||||||
|
<div
|
||||||
|
className="rounded-xl shadow p-6 text-white flex justify-between items-center"
|
||||||
style={{
|
style={{
|
||||||
background: "linear-gradient(135deg, #4c5f9e, #2a355d, #566bb8, #3d4e87)",
|
background:
|
||||||
|
"linear-gradient(135deg, #4c5f9e, #2a355d, #566bb8, #3d4e87)",
|
||||||
backgroundSize: "350% 350%",
|
backgroundSize: "350% 350%",
|
||||||
animation: "gradientMove 10s ease infinite",
|
animation: "gradientMove 10s ease infinite",
|
||||||
color: "white",
|
|
||||||
backdropFilter: "blur(10px)",
|
|
||||||
border: "1px solid rgba(255,255,255,0.25)",
|
|
||||||
boxShadow: "0px 8px 22px rgba(0,0,0,0.25)",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<h1 className="text-2xl font-medium mb-3 md:mb-0">Gestión de Usuarios</h1>
|
<div>
|
||||||
|
<h1 className="text-2xl font-bold">Operator Management</h1>
|
||||||
{/* BOTONES ESTILO GHOST */}
|
<p className="text-sm text-blue-100">{selectedArea?.name}</p>
|
||||||
<div className="flex gap-3">
|
|
||||||
<button className="px-4 py-2 border border-white/40 rounded-lg text-white hover:bg-white/15 hover:border-white transition">
|
|
||||||
Agregar
|
|
||||||
</button>
|
|
||||||
<button className="px-4 py-2 border border-white/40 rounded-lg text-white hover:bg-white/15 hover:border-white transition">
|
|
||||||
Borrar
|
|
||||||
</button>
|
|
||||||
<button className="px-4 py-2 border border-white/40 rounded-lg text-white hover:bg-white/15 hover:border-white transition">
|
|
||||||
Refrescar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* TABLA */}
|
<div className="flex items-center gap-3">
|
||||||
<div className="relative overflow-x-auto shadow-sm rounded-lg border border-gray-300 bg-white">
|
{/* ADD */}
|
||||||
{/* SEARCH */}
|
<button
|
||||||
<div className="flex flex-col md:flex-row items-center justify-between p-4 space-y-4 md:space-y-0">
|
onClick={() => {
|
||||||
<div className="relative w-full max-w-xs">
|
setForm(emptyOperator);
|
||||||
<input
|
setEditingId(null);
|
||||||
type="text"
|
setShowModal(true);
|
||||||
placeholder="Search"
|
}}
|
||||||
value={search}
|
className="flex items-center gap-2 px-4 py-2 bg-white text-[#4c5f9e] rounded-lg"
|
||||||
onChange={(e) => 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"
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-y-0 left-2 flex items-center pointer-events-none">
|
|
||||||
<svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-3.5-3.5M17 10a7 7 0 1 1-14 0 7 7 0 0 1 14 0Z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table className="w-full text-sm text-left text-gray-700">
|
|
||||||
<thead className="bg-gray-200 border-b border-gray-300">
|
|
||||||
<tr>
|
|
||||||
<th className="p-4">
|
|
||||||
<input type="checkbox" className="w-4 h-4 border rounded" />
|
|
||||||
</th>
|
|
||||||
<th className="px-6 py-3 font-medium">Nombre</th>
|
|
||||||
<th className="px-6 py-3 font-medium">Rol</th>
|
|
||||||
<th className="px-6 py-3 font-medium">Estado</th>
|
|
||||||
<th className="px-6 py-3 font-medium">Acción</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{filteredUsers.map((user, index) => (
|
|
||||||
<tr
|
|
||||||
key={user.id}
|
|
||||||
className={`border-b border-gray-300 ${index % 2 === 0 ? "bg-gray-50" : "bg-white"} hover:bg-gray-100`}
|
|
||||||
>
|
>
|
||||||
<td className="p-4">
|
<Plus size={16} /> Add
|
||||||
<input type="checkbox" className="w-4 h-4 border rounded" />
|
</button>
|
||||||
</td>
|
|
||||||
<th className="flex items-center px-6 py-4 font-medium whitespace-nowrap">
|
{/* EDIT */}
|
||||||
<img className="w-10 h-10 rounded-full" src={user.img} alt={user.name} />
|
<button
|
||||||
<div className="ml-3">
|
onClick={handleEdit}
|
||||||
<div className="text-base font-semibold">{user.name}</div>
|
disabled={!activeOperator}
|
||||||
<div className="text-gray-500 text-sm">{user.email}</div>
|
className={`flex items-center gap-2 px-4 py-2 border border-white/40 rounded-lg
|
||||||
</div>
|
${
|
||||||
</th>
|
!activeOperator
|
||||||
<td className="px-6 py-4">{user.role}</td>
|
? "opacity-70 cursor-not-allowed"
|
||||||
<td className="px-6 py-4">
|
: "hover:bg-white/10"
|
||||||
<div className="flex items-center">
|
}`}
|
||||||
<div
|
>
|
||||||
className={`h-2.5 w-2.5 rounded-full mr-2 ${user.status === "Online" ? "bg-green-500" : "bg-red-500"}`}
|
<Pencil size={16} /> Edit
|
||||||
></div>
|
</button>
|
||||||
{user.status}
|
|
||||||
</div>
|
{/* DELETE */}
|
||||||
</td>
|
<button
|
||||||
<td className="px-6 py-4">
|
onClick={handleDelete}
|
||||||
<button className="text-blue-600 font-medium hover:underline">Editar</button>
|
disabled={!activeOperator}
|
||||||
</td>
|
className={`flex items-center gap-2 px-4 py-2 border border-white/40 rounded-lg
|
||||||
</tr>
|
${
|
||||||
))}
|
!activeOperator
|
||||||
</tbody>
|
? "opacity-70 cursor-not-allowed"
|
||||||
</table>
|
: "hover:bg-white/10"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Trash2 size={16} /> Delete
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* REFRESH */}
|
||||||
|
<button
|
||||||
|
onClick={loadData}
|
||||||
|
className="flex items-center gap-2 px-4 py-2 border border-white/40 rounded-lg hover:bg-white/10"
|
||||||
|
>
|
||||||
|
<RefreshCcw size={16} /> Refresh
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
{/* SEARCH */}
|
||||||
{`
|
<input
|
||||||
@keyframes gradientMove {
|
className="bg-white rounded-lg shadow px-4 py-2 text-sm"
|
||||||
0% {background-position: 0% 50%;}
|
placeholder="Search operator..."
|
||||||
50% {background-position: 100% 50%;}
|
value={search}
|
||||||
100% {background-position: 0% 50%;}
|
onChange={e => setSearch(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MaterialTable
|
||||||
|
title={selectedArea?.name || "Operators"}
|
||||||
|
|
||||||
|
columns={[
|
||||||
|
{ title: "Login", field: "loginName" },
|
||||||
|
{
|
||||||
|
title: "Super Admin",
|
||||||
|
field: "isSuperAdmin",
|
||||||
|
render: rowData => (
|
||||||
|
<span
|
||||||
|
className={`px-3 py-1 rounded-full text-xs font-semibold border ${
|
||||||
|
rowData.isSuperAdmin
|
||||||
|
? "text-blue-600 border-blue-600"
|
||||||
|
: "text-red-600 border-red-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{rowData.isSuperAdmin ? "Yes" : "No"}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Status",
|
||||||
|
field: "isDisabled",
|
||||||
|
render: rowData => (
|
||||||
|
<span
|
||||||
|
className={`px-3 py-1 rounded-full text-xs font-semibold border ${
|
||||||
|
rowData.isDisabled
|
||||||
|
? "text-red-600 border-red-600"
|
||||||
|
: "text-blue-600 border-blue-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{rowData.isDisabled ? "Off" : "Active"}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ 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: () => <Plus size={16} />,
|
||||||
|
tooltip: "Add Operator",
|
||||||
|
isFreeAction: true,
|
||||||
|
onClick: () => {
|
||||||
|
setForm(emptyOperator);
|
||||||
|
setEditingId(null);
|
||||||
|
setShowModal(true);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: () => <Pencil size={16} />,
|
||||||
|
tooltip: "Edit Operator",
|
||||||
|
onClick: (event, rowData) => {
|
||||||
|
setActiveOperator(rowData as Operator);
|
||||||
|
setEditingId((rowData as Operator).id);
|
||||||
|
setForm({ ...(rowData as Operator) });
|
||||||
|
setShowModal(true);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: () => <Trash2 size={16} />,
|
||||||
|
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",
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* MODAL */}
|
||||||
|
{showModal && (
|
||||||
|
<div className="fixed inset-0 bg-black/40 flex items-center justify-center">
|
||||||
|
<div className="bg-white rounded-xl p-6 w-96 space-y-3">
|
||||||
|
<h2 className="text-lg font-semibold">
|
||||||
|
{editingId ? "Edit Operator" : "Add Operator"}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<input
|
||||||
|
className="w-full border px-3 py-2 rounded"
|
||||||
|
placeholder="Login Name"
|
||||||
|
value={form.loginName}
|
||||||
|
onChange={e =>
|
||||||
|
setForm({ ...form, loginName: e.target.value })
|
||||||
}
|
}
|
||||||
`}
|
/>
|
||||||
</style>
|
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
setForm({ ...form, isSuperAdmin: !form.isSuperAdmin })
|
||||||
|
}
|
||||||
|
className={`w-full border rounded px-3 py-2 ${
|
||||||
|
form.isSuperAdmin
|
||||||
|
? "text-blue-600 border-blue-600"
|
||||||
|
: "text-red-600 border-red-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Super Admin: {form.isSuperAdmin ? "Yes" : "No"}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
setForm({ ...form, isDisabled: !form.isDisabled })
|
||||||
|
}
|
||||||
|
className={`w-full border rounded px-3 py-2 ${
|
||||||
|
form.isDisabled
|
||||||
|
? "text-red-600 border-red-600"
|
||||||
|
: "text-blue-600 border-blue-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Status: {form.isDisabled ? "Off" : "Active"}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<input
|
||||||
|
className="w-full border px-3 py-2 rounded"
|
||||||
|
placeholder="User Name"
|
||||||
|
value={form.userName}
|
||||||
|
onChange={e =>
|
||||||
|
setForm({ ...form, userName: e.target.value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
className="w-full border px-3 py-2 rounded"
|
||||||
|
placeholder="Cell Phone"
|
||||||
|
value={form.cellPhone}
|
||||||
|
onChange={e =>
|
||||||
|
setForm({ ...form, cellPhone: e.target.value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
className="w-full border px-3 py-2 rounded"
|
||||||
|
value={form.createdAt}
|
||||||
|
onChange={e =>
|
||||||
|
setForm({ ...form, createdAt: e.target.value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex justify-end gap-2 pt-3">
|
||||||
|
<button onClick={() => setShowModal(false)}>Cancel</button>
|
||||||
|
<button
|
||||||
|
onClick={handleSave}
|
||||||
|
className="bg-[#4c5f9e] text-white px-4 py-2 rounded"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user