157 lines
6.6 KiB
TypeScript
157 lines
6.6 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState } from "react";
|
|
import { Check } from "lucide-react";
|
|
import Button from "@/components/common/button";
|
|
import { initialPermissions, rolesList } from "@/constants/constant";
|
|
|
|
|
|
|
|
export default function RolesAccessPortal() {
|
|
const [activeTopTab, setActiveTopTab] = useState("Roles & Permissions");
|
|
const [selectedRole, setSelectedRole] = useState("mne_supervisor");
|
|
const [permissions, setPermissions] = useState(initialPermissions);
|
|
|
|
|
|
return (
|
|
<div className="my-15 text-slate-100 font-sans">
|
|
{/* --- BREADCRUMB --- */}
|
|
<div className="flex items-center gap-2 text-[12px] font-bold tracking-widest text-emerald-400 uppercase font-mono">
|
|
<span>APPLE ONE — HQ TOWER</span>
|
|
<span className="text-slate-600">•</span>
|
|
<span className="text-slate-400">CONFIGURE</span>
|
|
<span className="text-slate-600">•</span>
|
|
<span className="text-slate-400">ROLES & ACCESS</span>
|
|
</div>
|
|
|
|
{/* --- PAGE HEADER --- */}
|
|
<h1 className="text-2xl font-bold text-white tracking-tight mt-1">
|
|
Roles & access
|
|
</h1>
|
|
<p className="text-sm font-medium text-slate-400 mt-2 max-w-2xl leading-relaxed">
|
|
Per-tenant role permissions, which platform users can sign in here and with what
|
|
role, and ticket escalation routing.
|
|
</p>
|
|
|
|
{/* --- MAIN TABS --- */}
|
|
<div className="flex items-center gap-8 border-b border-slate-800/80 mt-8 text-sm font-semibold">
|
|
{["Roles & Permissions", "Tenant Access", "Escalation Matrix"].map((tab) => (
|
|
<Button
|
|
key={tab}
|
|
onClick={() => setActiveTopTab(tab)}
|
|
className={`pb-3 relative transition-colors ${
|
|
activeTopTab === tab
|
|
? "text-emerald-400 font-bold"
|
|
: "text-slate-400 hover:text-slate-200"
|
|
}`}
|
|
>
|
|
{tab}
|
|
{activeTopTab === tab && (
|
|
<span className="absolute bottom-0 left-0 right-0 h-0.5 bg-emerald-400 rounded-full" />
|
|
)}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
|
|
{/* --- MATRIX CONTAINER --- */}
|
|
<div className="mt-6 bg-[#091322]/80 border border-slate-800/80 rounded-xl overflow-hidden grid grid-cols-1 md:grid-cols-12">
|
|
{/* --- LEFT ROLES SIDEBAR --- */}
|
|
<div className="md:col-span-3 border-r border-slate-800/80 py-3 divide-y divide-slate-800/40">
|
|
{rolesList.map((role) => {
|
|
const isSelected = selectedRole === role.id;
|
|
return (
|
|
<Button
|
|
key={role.id}
|
|
onClick={() => setSelectedRole(role.id)}
|
|
className={`w-full flex items-center justify-between px-5 py-4 text-left transition-all relative ${
|
|
isSelected
|
|
? "bg-[#0c1c2e] text-emerald-400 font-bold"
|
|
: "text-slate-300 hover:bg-slate-900/40 hover:text-white"
|
|
}`}
|
|
>
|
|
{/* Active side indicator */}
|
|
{isSelected && (
|
|
<span className="absolute left-0 top-0 bottom-0 w-1 bg-emerald-400" />
|
|
)}
|
|
|
|
<span className="text-sm">{role.label}</span>
|
|
<span
|
|
className={`text-[10px] font-mono px-2 py-0.5 rounded border ${
|
|
role.badge === "all"
|
|
? "bg-slate-800/80 text-slate-300 border-slate-700"
|
|
: "bg-slate-900/80 text-slate-400 border-slate-800"
|
|
}`}
|
|
>
|
|
{role.badge}
|
|
</span>
|
|
</Button>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* --- RIGHT PERMISSIONS TABLE --- */}
|
|
<div className="md:col-span-9 overflow-x-auto">
|
|
<table className="w-full text-left border-collapse">
|
|
<thead>
|
|
<tr className="border-b border-slate-800/80 text-[11px] font-bold text-slate-400 uppercase tracking-wider font-mono">
|
|
<th className="py-4 px-6 font-medium">MODULE</th>
|
|
<th className="py-4 px-6 font-medium">MENU</th>
|
|
<th className="py-4 px-4 text-center font-medium">ALL</th>
|
|
<th className="py-4 px-4 text-center font-medium">VIEW</th>
|
|
<th className="py-4 px-4 text-center font-medium">ADD</th>
|
|
<th className="py-4 px-4 text-center font-medium">EDIT</th>
|
|
<th className="py-4 px-4 text-center font-medium">DELETE</th>
|
|
<th className="py-4 px-4 text-center font-medium">CANCEL</th>
|
|
<th className="py-4 px-4 text-center font-medium">PRINT</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-slate-800/50 text-xs">
|
|
{permissions.map((row) => (
|
|
<tr key={row.id} className="hover:bg-slate-900/30 transition-colors">
|
|
{/* Module Name */}
|
|
<td className="py-4 px-6 font-mono text-slate-400">
|
|
{row.module}
|
|
</td>
|
|
|
|
{/* Menu Item Name */}
|
|
<td className="py-4 px-6 font-semibold text-slate-100 whitespace-nowrap">
|
|
{row.menu}
|
|
</td>
|
|
|
|
{/* Permission Checkboxes */}
|
|
{(["all", "view", "add", "edit", "delete", "cancel", "print"] as const).map(
|
|
(permKey) => {
|
|
const isChecked = row.permissions[permKey];
|
|
return (
|
|
<td key={permKey} className="py-4 px-4 text-center">
|
|
<Button
|
|
|
|
|
|
className={`w-5 h-5 rounded flex items-center justify-center transition-all border mx-auto ${
|
|
isChecked
|
|
? "bg-[#2dd4bf] border-[#2dd4bf] text-slate-950"
|
|
: "bg-slate-900/60 border-slate-700/80 hover:border-slate-500"
|
|
}`}
|
|
>
|
|
{isChecked && <Check className="w-3.5 h-3.5 stroke-[3]" />}
|
|
</Button>
|
|
</td>
|
|
);
|
|
}
|
|
)}
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{/* --- SAVE BUTTON --- */}
|
|
<div className="flex justify-end mt-6">
|
|
<Button className="bg-[#2dd4bf] hover:bg-teal-300 text-slate-950 font-bold text-xs px-5 py-2.5 rounded-lg flex items-center gap-2 transition-all shadow-md">
|
|
<span>Save permissions</span>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |