677 lines
28 KiB
JavaScript
677 lines
28 KiB
JavaScript
import React, { useState } from "react";
|
|
import { base44 } from "@/api/base44Client";
|
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
import { Shield, Search, Save, Info, ChevronDown, ChevronRight, Users, Calendar, Package, DollarSign, FileText, Settings as SettingsIcon, BarChart3, MessageSquare, Briefcase, Building2 } from "lucide-react";
|
|
import PageHeader from "../components/common/PageHeader";
|
|
import { useToast } from "@/components/ui/use-toast";
|
|
import {
|
|
HoverCard,
|
|
HoverCardContent,
|
|
HoverCardTrigger,
|
|
} from "@/components/ui/hover-card";
|
|
|
|
// Role-specific permission sets
|
|
const ROLE_PERMISSIONS = {
|
|
admin: [
|
|
{
|
|
id: "system",
|
|
name: "System Administration",
|
|
icon: Shield,
|
|
color: "text-red-600",
|
|
permissions: [
|
|
{ id: "admin.1", name: "Manage All Users", description: "Create, edit, and delete user accounts" },
|
|
{ id: "admin.2", name: "Configure System Settings", description: "Modify platform-wide settings" },
|
|
{ id: "admin.3", name: "Manage Roles & Permissions", description: "Define and assign user roles" },
|
|
{ id: "admin.4", name: "View All Activity Logs", description: "Access complete audit trail" },
|
|
{ id: "admin.5", name: "Manage Integrations", description: "Configure external integrations" },
|
|
{ id: "admin.6", name: "Access All Data", description: "Unrestricted access to all system data" },
|
|
]
|
|
},
|
|
{
|
|
id: "enterprises",
|
|
name: "Enterprise Management",
|
|
icon: Building2,
|
|
color: "text-purple-600",
|
|
permissions: [
|
|
{ id: "admin.7", name: "Create Enterprises", description: "Onboard new enterprise clients" },
|
|
{ id: "admin.8", name: "Manage Sectors", description: "Create and configure sectors" },
|
|
{ id: "admin.9", name: "Manage Partners", description: "Onboard and manage partners" },
|
|
{ id: "admin.10", name: "Set Global Policies", description: "Define enterprise-wide policies" },
|
|
]
|
|
},
|
|
{
|
|
id: "vendors",
|
|
name: "Vendor Oversight",
|
|
icon: Package,
|
|
color: "text-amber-600",
|
|
permissions: [
|
|
{ id: "admin.11", name: "Approve/Suspend Vendors", description: "Control vendor status" },
|
|
{ id: "admin.12", name: "View All Vendor Performance", description: "Access all vendor scorecards" },
|
|
{ id: "admin.13", name: "Manage Vendor Rates", description: "Override and approve rate cards" },
|
|
]
|
|
},
|
|
{
|
|
id: "financial",
|
|
name: "Financial Administration",
|
|
icon: DollarSign,
|
|
color: "text-green-600",
|
|
permissions: [
|
|
{ id: "admin.14", name: "View All Financials", description: "Access all financial data" },
|
|
{ id: "admin.15", name: "Process All Payments", description: "Approve and process payments" },
|
|
{ id: "admin.16", name: "Manage Payroll", description: "Process workforce payroll" },
|
|
{ id: "admin.17", name: "Generate Financial Reports", description: "Create P&L and financial analytics" },
|
|
]
|
|
}
|
|
],
|
|
|
|
procurement: [
|
|
{
|
|
id: "vendors",
|
|
name: "Vendor Management",
|
|
icon: Package,
|
|
color: "text-purple-600",
|
|
permissions: [
|
|
{ id: "proc.1", name: "View All Vendors", description: "Access vendor directory" },
|
|
{ id: "proc.2", name: "Onboard New Vendors", description: "Add vendors to the platform" },
|
|
{ id: "proc.3", name: "Edit Vendor Details", description: "Modify vendor information" },
|
|
{ id: "proc.4", name: "Review Vendor Compliance", description: "Check COI, W9, certifications" },
|
|
{ id: "proc.5", name: "Approve/Suspend Vendors", description: "Change vendor approval status" },
|
|
{ id: "proc.6", name: "View Vendor Performance", description: "Access scorecards and KPIs" },
|
|
]
|
|
},
|
|
{
|
|
id: "rates",
|
|
name: "Rate Card Management",
|
|
icon: DollarSign,
|
|
color: "text-green-600",
|
|
permissions: [
|
|
{ id: "proc.7", name: "View All Rate Cards", description: "See vendor pricing" },
|
|
{ id: "proc.8", name: "Create Rate Cards", description: "Set up new rate cards" },
|
|
{ id: "proc.9", name: "Edit Rate Cards", description: "Modify existing rates" },
|
|
{ id: "proc.10", name: "Approve Rate Cards", description: "Approve vendor rates" },
|
|
{ id: "proc.11", name: "Set Markup Rules", description: "Define markup percentages" },
|
|
]
|
|
},
|
|
{
|
|
id: "orders",
|
|
name: "Order Management",
|
|
icon: Calendar,
|
|
color: "text-blue-600",
|
|
permissions: [
|
|
{ id: "proc.12", name: "View All Orders", description: "Access all orders across sectors" },
|
|
{ id: "proc.13", name: "Assign Vendors to Orders", description: "Match vendors with orders" },
|
|
{ id: "proc.14", name: "Monitor Order Fulfillment", description: "Track order completion" },
|
|
]
|
|
},
|
|
{
|
|
id: "reports",
|
|
name: "Analytics & Reports",
|
|
icon: BarChart3,
|
|
color: "text-indigo-600",
|
|
permissions: [
|
|
{ id: "proc.15", name: "View Vendor Analytics", description: "Access vendor performance data" },
|
|
{ id: "proc.16", name: "Generate Procurement Reports", description: "Create spend and compliance reports" },
|
|
{ id: "proc.17", name: "Export Data", description: "Download reports as CSV/PDF" },
|
|
]
|
|
}
|
|
],
|
|
|
|
operator: [
|
|
{
|
|
id: "events",
|
|
name: "Event Management",
|
|
icon: Calendar,
|
|
color: "text-blue-600",
|
|
permissions: [
|
|
{ id: "op.1", name: "View My Enterprise Events", description: "See events in my enterprise" },
|
|
{ id: "op.2", name: "Create Events", description: "Create new event orders" },
|
|
{ id: "op.3", name: "Edit Events", description: "Modify event details" },
|
|
{ id: "op.4", name: "Cancel Events", description: "Cancel event orders" },
|
|
{ id: "op.5", name: "Approve Events", description: "Approve event requests from sectors" },
|
|
{ id: "op.6", name: "View Event Financials", description: "See event costs and billing" },
|
|
]
|
|
},
|
|
{
|
|
id: "sectors",
|
|
name: "Sector Management",
|
|
icon: Building2,
|
|
color: "text-cyan-600",
|
|
permissions: [
|
|
{ id: "op.7", name: "View My Sectors", description: "See sectors under my enterprise" },
|
|
{ id: "op.8", name: "Manage Sector Settings", description: "Configure sector policies" },
|
|
{ id: "op.9", name: "Assign Vendors to Sectors", description: "Approve vendors for sectors" },
|
|
]
|
|
},
|
|
{
|
|
id: "workforce",
|
|
name: "Workforce Management",
|
|
icon: Users,
|
|
color: "text-emerald-600",
|
|
permissions: [
|
|
{ id: "op.10", name: "View Workforce", description: "See staff across my enterprise" },
|
|
{ id: "op.11", name: "Assign Staff to Events", description: "Schedule staff for events" },
|
|
{ id: "op.12", name: "Approve Timesheets", description: "Review and approve hours" },
|
|
{ id: "op.13", name: "View Staff Performance", description: "Access ratings and reviews" },
|
|
]
|
|
},
|
|
{
|
|
id: "reports",
|
|
name: "Reports",
|
|
icon: BarChart3,
|
|
color: "text-indigo-600",
|
|
permissions: [
|
|
{ id: "op.14", name: "View Enterprise Dashboards", description: "Access my enterprise analytics" },
|
|
{ id: "op.15", name: "Export Reports", description: "Download reports" },
|
|
]
|
|
}
|
|
],
|
|
|
|
sector: [
|
|
{
|
|
id: "events",
|
|
name: "Event Management",
|
|
icon: Calendar,
|
|
color: "text-blue-600",
|
|
permissions: [
|
|
{ id: "sec.1", name: "View My Sector Events", description: "See events at my location" },
|
|
{ id: "sec.2", name: "Create Event Requests", description: "Request new events" },
|
|
{ id: "sec.3", name: "Edit My Events", description: "Modify event details" },
|
|
{ id: "sec.4", name: "View Event Costs", description: "See event billing information" },
|
|
]
|
|
},
|
|
{
|
|
id: "workforce",
|
|
name: "Staff Management",
|
|
icon: Users,
|
|
color: "text-emerald-600",
|
|
permissions: [
|
|
{ id: "sec.5", name: "View My Location Staff", description: "See staff at my sector" },
|
|
{ id: "sec.6", name: "Schedule Staff", description: "Assign staff to shifts" },
|
|
{ id: "sec.7", name: "Approve Timesheets", description: "Review hours worked" },
|
|
{ id: "sec.8", name: "Rate Staff Performance", description: "Provide performance feedback" },
|
|
]
|
|
},
|
|
{
|
|
id: "vendors",
|
|
name: "Vendor Relations",
|
|
icon: Package,
|
|
color: "text-purple-600",
|
|
permissions: [
|
|
{ id: "sec.9", name: "View Approved Vendors", description: "See vendors available to my sector" },
|
|
{ id: "sec.10", name: "View Vendor Rates", description: "Access rate cards" },
|
|
{ id: "sec.11", name: "Request Vendor Services", description: "Submit staffing requests" },
|
|
]
|
|
}
|
|
],
|
|
|
|
client: [
|
|
{
|
|
id: "orders",
|
|
name: "Order Management",
|
|
icon: Calendar,
|
|
color: "text-blue-600",
|
|
permissions: [
|
|
{ id: "client.1", name: "View My Orders", description: "See my event orders" },
|
|
{ id: "client.2", name: "Create New Orders", description: "Request staffing for events" },
|
|
{ id: "client.3", name: "Edit My Orders", description: "Modify order details before confirmation" },
|
|
{ id: "client.4", name: "Cancel Orders", description: "Cancel pending or confirmed orders" },
|
|
{ id: "client.5", name: "View Order Status", description: "Track order fulfillment" },
|
|
]
|
|
},
|
|
{
|
|
id: "vendors",
|
|
name: "Vendor Selection",
|
|
icon: Package,
|
|
color: "text-purple-600",
|
|
permissions: [
|
|
{ id: "client.6", name: "View Available Vendors", description: "See vendors I can work with" },
|
|
{ id: "client.7", name: "View Vendor Rates", description: "See pricing for services" },
|
|
{ id: "client.8", name: "Request Specific Vendors", description: "Prefer specific vendors for orders" },
|
|
]
|
|
},
|
|
{
|
|
id: "workforce",
|
|
name: "Staff Review",
|
|
icon: Users,
|
|
color: "text-emerald-600",
|
|
permissions: [
|
|
{ id: "client.9", name: "View Assigned Staff", description: "See who's working my events" },
|
|
{ id: "client.10", name: "Rate Staff Performance", description: "Provide feedback on staff" },
|
|
{ id: "client.11", name: "Request Staff Changes", description: "Request staff replacements" },
|
|
]
|
|
},
|
|
{
|
|
id: "billing",
|
|
name: "Billing & Invoices",
|
|
icon: DollarSign,
|
|
color: "text-green-600",
|
|
permissions: [
|
|
{ id: "client.12", name: "View My Invoices", description: "Access invoices for my orders" },
|
|
{ id: "client.13", name: "Download Invoices", description: "Export invoice PDFs" },
|
|
{ id: "client.14", name: "View Spend Analytics", description: "See my spending trends" },
|
|
]
|
|
}
|
|
],
|
|
|
|
vendor: [
|
|
{
|
|
id: "orders",
|
|
name: "Order Fulfillment",
|
|
icon: Calendar,
|
|
color: "text-blue-600",
|
|
permissions: [
|
|
{ id: "vendor.1", name: "View My Orders", description: "See orders assigned to me" },
|
|
{ id: "vendor.2", name: "Accept/Decline Orders", description: "Respond to order requests" },
|
|
{ id: "vendor.3", name: "Update Order Status", description: "Mark orders as in progress/completed" },
|
|
{ id: "vendor.4", name: "View Order Details", description: "Access order requirements" },
|
|
]
|
|
},
|
|
{
|
|
id: "workforce",
|
|
name: "My Workforce",
|
|
icon: Users,
|
|
color: "text-emerald-600",
|
|
permissions: [
|
|
{ id: "vendor.5", name: "View My Staff", description: "See my workforce members" },
|
|
{ id: "vendor.6", name: "Add New Staff", description: "Onboard new workers" },
|
|
{ id: "vendor.7", name: "Edit Staff Details", description: "Update staff information" },
|
|
{ id: "vendor.8", name: "Assign Staff to Orders", description: "Schedule staff for orders" },
|
|
{ id: "vendor.9", name: "Manage Staff Compliance", description: "Track certifications and background checks" },
|
|
{ id: "vendor.10", name: "View Staff Performance", description: "See ratings and feedback" },
|
|
]
|
|
},
|
|
{
|
|
id: "rates",
|
|
name: "Rate Management",
|
|
icon: DollarSign,
|
|
color: "text-green-600",
|
|
permissions: [
|
|
{ id: "vendor.11", name: "View My Rate Cards", description: "See my approved rates" },
|
|
{ id: "vendor.12", name: "Submit Rate Proposals", description: "Propose new rates" },
|
|
{ id: "vendor.13", name: "View Rate History", description: "Track rate changes" },
|
|
]
|
|
},
|
|
{
|
|
id: "performance",
|
|
name: "Performance & Analytics",
|
|
icon: BarChart3,
|
|
color: "text-indigo-600",
|
|
permissions: [
|
|
{ id: "vendor.14", name: "View My Scorecard", description: "See my performance metrics" },
|
|
{ id: "vendor.15", name: "View Fill Rate", description: "Track order fulfillment rate" },
|
|
{ id: "vendor.16", name: "View Revenue Analytics", description: "See my earnings trends" },
|
|
]
|
|
},
|
|
{
|
|
id: "billing",
|
|
name: "Invoices & Payments",
|
|
icon: FileText,
|
|
color: "text-cyan-600",
|
|
permissions: [
|
|
{ id: "vendor.17", name: "View My Invoices", description: "Access invoices I've issued" },
|
|
{ id: "vendor.18", name: "Create Invoices", description: "Generate invoices for completed work" },
|
|
{ id: "vendor.19", name: "Track Payments", description: "Monitor payment status" },
|
|
]
|
|
}
|
|
],
|
|
|
|
workforce: [
|
|
{
|
|
id: "shifts",
|
|
name: "My Shifts",
|
|
icon: Calendar,
|
|
color: "text-blue-600",
|
|
permissions: [
|
|
{ id: "work.1", name: "View My Schedule", description: "See my upcoming shifts" },
|
|
{ id: "work.2", name: "Clock In/Out", description: "Record shift start and end times" },
|
|
{ id: "work.3", name: "Request Time Off", description: "Submit time off requests" },
|
|
{ id: "work.4", name: "View Shift History", description: "See past shifts worked" },
|
|
]
|
|
},
|
|
{
|
|
id: "profile",
|
|
name: "My Profile",
|
|
icon: Users,
|
|
color: "text-emerald-600",
|
|
permissions: [
|
|
{ id: "work.5", name: "View My Profile", description: "See my worker profile" },
|
|
{ id: "work.6", name: "Edit Contact Info", description: "Update phone/email" },
|
|
{ id: "work.7", name: "Update Availability", description: "Set my available days/times" },
|
|
{ id: "work.8", name: "Upload Certifications", description: "Add certificates and licenses" },
|
|
]
|
|
},
|
|
{
|
|
id: "earnings",
|
|
name: "Earnings & Payments",
|
|
icon: DollarSign,
|
|
color: "text-green-600",
|
|
permissions: [
|
|
{ id: "work.9", name: "View My Earnings", description: "See my pay and hours" },
|
|
{ id: "work.10", name: "View Timesheets", description: "Access my timesheet records" },
|
|
{ id: "work.11", name: "View Payment History", description: "See past payments" },
|
|
{ id: "work.12", name: "Download Pay Stubs", description: "Export payment records" },
|
|
]
|
|
},
|
|
{
|
|
id: "performance",
|
|
name: "My Performance",
|
|
icon: BarChart3,
|
|
color: "text-indigo-600",
|
|
permissions: [
|
|
{ id: "work.13", name: "View My Ratings", description: "See feedback from clients" },
|
|
{ id: "work.14", name: "View Performance Stats", description: "See my reliability metrics" },
|
|
{ id: "work.15", name: "View Badges/Achievements", description: "See earned badges" },
|
|
]
|
|
}
|
|
]
|
|
};
|
|
|
|
const ROLE_TEMPLATES = {
|
|
admin: {
|
|
name: "Administrator",
|
|
description: "Full system access",
|
|
color: "bg-red-100 text-red-700",
|
|
defaultPermissions: "all"
|
|
},
|
|
procurement: {
|
|
name: "Procurement Manager",
|
|
description: "Vendor and rate management",
|
|
color: "bg-purple-100 text-purple-700",
|
|
defaultPermissions: ["proc.1", "proc.2", "proc.3", "proc.4", "proc.5", "proc.6", "proc.7", "proc.8", "proc.9", "proc.10", "proc.12", "proc.13", "proc.15", "proc.16"]
|
|
},
|
|
operator: {
|
|
name: "Operator",
|
|
description: "Enterprise management",
|
|
color: "bg-blue-100 text-blue-700",
|
|
defaultPermissions: ["op.1", "op.2", "op.3", "op.5", "op.6", "op.7", "op.8", "op.10", "op.11", "op.12", "op.14"]
|
|
},
|
|
sector: {
|
|
name: "Sector Manager",
|
|
description: "Location-specific management",
|
|
color: "bg-cyan-100 text-cyan-700",
|
|
defaultPermissions: ["sec.1", "sec.2", "sec.3", "sec.4", "sec.5", "sec.6", "sec.7", "sec.9", "sec.10"]
|
|
},
|
|
client: {
|
|
name: "Client",
|
|
description: "Order creation and viewing",
|
|
color: "bg-green-100 text-green-700",
|
|
defaultPermissions: ["client.1", "client.2", "client.3", "client.5", "client.6", "client.7", "client.9", "client.12"]
|
|
},
|
|
vendor: {
|
|
name: "Vendor Partner",
|
|
description: "Vendor-specific access",
|
|
color: "bg-amber-100 text-amber-700",
|
|
defaultPermissions: ["vendor.1", "vendor.2", "vendor.3", "vendor.5", "vendor.6", "vendor.7", "vendor.8", "vendor.11", "vendor.14", "vendor.17", "vendor.18"]
|
|
},
|
|
workforce: {
|
|
name: "Workforce Member",
|
|
description: "Basic access for staff",
|
|
color: "bg-slate-100 text-slate-700",
|
|
defaultPermissions: ["work.1", "work.2", "work.4", "work.5", "work.6", "work.9", "work.10", "work.13"]
|
|
}
|
|
};
|
|
|
|
export default function Permissions() {
|
|
const [selectedRole, setSelectedRole] = useState("operator");
|
|
const [searchTerm, setSearchTerm] = useState("");
|
|
const [expandedCategories, setExpandedCategories] = useState({});
|
|
const [permissions, setPermissions] = useState({});
|
|
const [overrides, setOverrides] = useState({});
|
|
const { toast } = useToast();
|
|
|
|
const { data: user } = useQuery({
|
|
queryKey: ['current-user-permissions'],
|
|
queryFn: () => base44.auth.me(),
|
|
});
|
|
|
|
const userRole = user?.user_role || user?.role || "admin";
|
|
|
|
// Get role-specific permissions
|
|
const roleCategories = ROLE_PERMISSIONS[selectedRole] || [];
|
|
|
|
// Initialize permissions based on role template
|
|
React.useEffect(() => {
|
|
const template = ROLE_TEMPLATES[selectedRole];
|
|
if (template) {
|
|
const newPermissions = {};
|
|
if (template.defaultPermissions === "all") {
|
|
// Admin gets all permissions
|
|
roleCategories.forEach(category => {
|
|
category.permissions.forEach(perm => {
|
|
newPermissions[perm.id] = true;
|
|
});
|
|
});
|
|
} else {
|
|
// Other roles get specific permissions
|
|
template.defaultPermissions.forEach(permId => {
|
|
newPermissions[permId] = true;
|
|
});
|
|
}
|
|
setPermissions(newPermissions);
|
|
setOverrides({});
|
|
}
|
|
}, [selectedRole]);
|
|
|
|
const toggleCategory = (categoryId) => {
|
|
setExpandedCategories(prev => ({
|
|
...prev,
|
|
[categoryId]: !prev[categoryId]
|
|
}));
|
|
};
|
|
|
|
const handlePermissionChange = (permId, value) => {
|
|
setPermissions(prev => ({
|
|
...prev,
|
|
[permId]: value
|
|
}));
|
|
setOverrides(prev => ({
|
|
...prev,
|
|
[permId]: true
|
|
}));
|
|
};
|
|
|
|
const handleInherit = (permId) => {
|
|
const template = ROLE_TEMPLATES[selectedRole];
|
|
const shouldBeEnabled = template.defaultPermissions === "all" || template.defaultPermissions.includes(permId);
|
|
setPermissions(prev => ({
|
|
...prev,
|
|
[permId]: shouldBeEnabled
|
|
}));
|
|
setOverrides(prev => {
|
|
const newOverrides = { ...prev };
|
|
delete newOverrides[permId];
|
|
return newOverrides;
|
|
});
|
|
};
|
|
|
|
const handleSave = () => {
|
|
toast({
|
|
title: "Permissions Saved",
|
|
description: `Permissions for ${ROLE_TEMPLATES[selectedRole].name} role have been updated successfully.`,
|
|
});
|
|
};
|
|
|
|
const filteredCategories = roleCategories.map(category => ({
|
|
...category,
|
|
permissions: category.permissions.filter(perm =>
|
|
perm.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
perm.description.toLowerCase().includes(searchTerm.toLowerCase())
|
|
)
|
|
})).filter(category => category.permissions.length > 0);
|
|
|
|
// Only admins can access this page
|
|
if (userRole !== "admin") {
|
|
return (
|
|
<div className="p-8 text-center">
|
|
<Shield className="w-16 h-16 mx-auto text-red-500 mb-4" />
|
|
<h2 className="text-2xl font-bold text-slate-900 mb-2">Access Denied</h2>
|
|
<p className="text-slate-600">Only administrators can manage permissions.</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="p-4 md:p-8 bg-slate-50 min-h-screen">
|
|
<div className="max-w-6xl mx-auto">
|
|
<PageHeader
|
|
title="Permissions Management"
|
|
subtitle="Configure role-based access control - each role sees only relevant permissions"
|
|
/>
|
|
|
|
{/* Role Selector */}
|
|
<Card className="mb-6 border-slate-200 shadow-sm">
|
|
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100">
|
|
<CardTitle className="text-lg">Select Role to Configure</CardTitle>
|
|
<p className="text-sm text-slate-500 mt-1">Permissions shown below are contextual to the selected role</p>
|
|
</CardHeader>
|
|
<CardContent className="p-6">
|
|
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3">
|
|
{Object.entries(ROLE_TEMPLATES).map(([roleKey, role]) => (
|
|
<button
|
|
key={roleKey}
|
|
onClick={() => setSelectedRole(roleKey)}
|
|
className={`p-4 rounded-xl border-2 transition-all text-left ${
|
|
selectedRole === roleKey
|
|
? 'border-[#0A39DF] bg-blue-50 shadow-md scale-105'
|
|
: 'border-slate-200 bg-white hover:border-slate-300 hover:shadow-sm'
|
|
}`}
|
|
>
|
|
<Badge className={role.color + " mb-2"}>{role.name}</Badge>
|
|
<p className="text-xs text-slate-600">{role.description}</p>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Search */}
|
|
<Card className="mb-6 border-slate-200 shadow-sm">
|
|
<CardContent className="p-4">
|
|
<div className="relative">
|
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
|
|
<Input
|
|
placeholder="Search permissions..."
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
className="pl-10 border-slate-300"
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Permission Categories */}
|
|
<div className="space-y-4">
|
|
{filteredCategories.map((category) => {
|
|
const Icon = category.icon;
|
|
const isExpanded = expandedCategories[category.id] !== false; // Default to expanded
|
|
|
|
return (
|
|
<Card key={category.id} className="border-slate-200 shadow-sm">
|
|
<CardHeader
|
|
className="bg-gradient-to-br from-slate-50 to-white border-b border-slate-100 cursor-pointer hover:bg-slate-100 transition-colors"
|
|
onClick={() => toggleCategory(category.id)}
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
{isExpanded ? (
|
|
<ChevronDown className="w-5 h-5 text-slate-400" />
|
|
) : (
|
|
<ChevronRight className="w-5 h-5 text-slate-400" />
|
|
)}
|
|
<Icon className={`w-5 h-5 ${category.color}`} />
|
|
<CardTitle className="text-base">{category.name}</CardTitle>
|
|
<Badge variant="outline" className="text-xs">
|
|
{category.permissions.filter(p => permissions[p.id]).length}/{category.permissions.length}
|
|
</Badge>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
|
|
{isExpanded && (
|
|
<CardContent className="p-0">
|
|
<div className="divide-y divide-slate-100">
|
|
{category.permissions.map((perm) => {
|
|
const isOverridden = overrides[perm.id];
|
|
const isEnabled = permissions[perm.id];
|
|
|
|
return (
|
|
<div
|
|
key={perm.id}
|
|
className="flex items-center justify-between p-4 hover:bg-slate-50 transition-colors"
|
|
>
|
|
<div className="flex items-center gap-3 flex-1">
|
|
<span className="text-sm text-slate-500 font-mono w-16">{perm.id}</span>
|
|
<div className="flex items-center gap-2 flex-1">
|
|
<span className="text-sm font-medium text-slate-900">{perm.name}</span>
|
|
<HoverCard>
|
|
<HoverCardTrigger>
|
|
<Info className="w-4 h-4 text-slate-400 cursor-help" />
|
|
</HoverCardTrigger>
|
|
<HoverCardContent className="w-80">
|
|
<p className="text-sm text-slate-700">{perm.description}</p>
|
|
</HoverCardContent>
|
|
</HoverCard>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-3">
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => handleInherit(perm.id)}
|
|
className={`text-xs ${
|
|
!isOverridden
|
|
? "text-blue-600 hover:text-blue-700 hover:bg-blue-50 font-semibold"
|
|
: "text-slate-500 hover:text-slate-700"
|
|
}`}
|
|
>
|
|
Inherit
|
|
</Button>
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => handlePermissionChange(perm.id, !isEnabled)}
|
|
className={`text-xs ${
|
|
isOverridden
|
|
? "text-[#0A39DF] hover:text-[#0A39DF]/90 hover:bg-blue-50 font-semibold"
|
|
: "text-slate-500 hover:text-slate-700"
|
|
}`}
|
|
>
|
|
Override
|
|
</Button>
|
|
<Checkbox
|
|
checked={isEnabled}
|
|
onCheckedChange={(checked) => handlePermissionChange(perm.id, checked)}
|
|
className="border-slate-300 data-[state=checked]:bg-[#0A39DF] data-[state=checked]:border-[#0A39DF]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</CardContent>
|
|
)}
|
|
</Card>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* Save Button */}
|
|
<div className="flex items-center justify-end gap-4 mt-8 p-6 bg-white rounded-xl border border-slate-200 shadow-sm">
|
|
<div className="text-sm text-slate-600">
|
|
{Object.keys(overrides).length} permission{Object.keys(overrides).length !== 1 ? 's' : ''} overridden
|
|
</div>
|
|
<Button onClick={handleSave} className="bg-[#0A39DF] hover:bg-[#0A39DF]/90 shadow-md">
|
|
<Save className="w-4 h-4 mr-2" />
|
|
Save Permissions
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |