S SmartDocs
Serie: Golden-Hour-backend-layer-2 typescript 240 righe · Aggiornato 2026-02-22

PermissionsManagement.tsx

Golden-Hour-backend-layer-2/pages/PermissionsManagement.tsx


import React, { useState } from 'react';

interface ModulePermission {
  module: string;
  read: boolean;
  write: boolean;
  delete: boolean;
  export: boolean;
}

interface Role {
  id: string;
  name: string;
  count: number;
  permissions: ModulePermission[];
}

const PermissionsManagement: React.FC = () => {
  const [selectedRoleId, setSelectedRoleId] = useState('1');
  const [activeTab, setActiveTab] = useState<'Roles' | 'Users'>('Roles');

  const [roles, setRoles] = useState<Role[]>([
    { 
      id: '1', name: 'Super Admin', count: 2, 
      permissions: [
        { module: 'Dashboard', read: true, write: true, delete: true, export: true },
        { module: 'Content', read: true, write: true, delete: true, export: true },
        { module: 'Orders', read: true, write: true, delete: true, export: true },
        { module: 'Invoices', read: true, write: true, delete: true, export: true },
        { module: 'Staff', read: true, write: true, delete: true, export: true },
      ]
    },
    { 
      id: '2', name: 'Manager', count: 5, 
      permissions: [
        { module: 'Dashboard', read: true, write: true, delete: false, export: true },
        { module: 'Content', read: true, write: true, delete: false, export: true },
        { module: 'Orders', read: true, write: true, delete: false, export: true },
        { module: 'Invoices', read: true, write: false, delete: false, export: true },
        { module: 'Staff', read: true, write: true, delete: false, export: false },
      ]
    },
    { 
      id: '3', name: 'Clerk / Staff', count: 18, 
      permissions: [
        { module: 'Dashboard', read: true, write: false, delete: false, export: false },
        { module: 'Content', read: true, write: true, delete: false, export: false },
        { module: 'Orders', read: true, write: false, delete: false, export: false },
        { module: 'Invoices', read: false, write: false, delete: false, export: false },
        { module: 'Staff', read: false, write: false, delete: false, export: false },
      ]
    },
  ]);

  const selectedRole = roles.find(r => r.id === selectedRoleId);

  const togglePermission = (moduleIndex: number, action: keyof Omit<ModulePermission, 'module'>) => {
    const updatedRoles = [...roles];
    const role = updatedRoles.find(r => r.id === selectedRoleId);
    if (role) {
      role.permissions[moduleIndex][action] = !role.permissions[moduleIndex][action];
      setRoles(updatedRoles);
    }
  };

  return (
    <div className="fade-in-section space-y-16 pb-24">
      {/* Editorial Header */}
      <div className="flex flex-col md:flex-row md:items-end justify-between gap-10 border-b border-[#c5a059]/10 pb-12 px-2">
        <div className="flex items-baseline space-x-6">
          <span className="font-serif italic text-6xl text-slate-200">Protocol</span>
          <div>
            <h2 className="font-serif italic text-6xl text-slate-900 tracking-tight">Security</h2>
            <p className="text-[10px] font-black uppercase tracking-[0.6em] text-[#c5a059] mt-2">Authority & Access Control</p>
          </div>
        </div>
        
        <div className="flex bg-[#fdfcf9] p-1 border border-[#c5a059]/10 rounded-full">
          <button 
            onClick={() => setActiveTab('Roles')}
            className={`px-10 py-3 rounded-full text-[9px] font-black uppercase tracking-[0.4em] transition-all ${activeTab === 'Roles' ? 'bg-black text-white shadow-xl' : 'text-slate-300 hover:text-slate-600'}`}
          >
            Ledger
          </button>
          <button 
            onClick={() => setActiveTab('Users')}
            className={`px-10 py-3 rounded-full text-[9px] font-black uppercase tracking-[0.4em] transition-all ${activeTab === 'Users' ? 'bg-black text-white shadow-xl' : 'text-slate-300 hover:text-slate-600'}`}
          >
            Overrides
          </button>
        </div>
      </div>

      {activeTab === 'Roles' ? (
        <div className="flex flex-col xl:flex-row gap-12">
          {/* Roles Selection - Gallery Style */}
          <div className="xl:w-1/3 space-y-8">
            <h3 className="font-serif italic text-3xl text-slate-900 px-2">Access Tiers</h3>
            <div className="grid grid-cols-1 gap-4">
              {roles.map((role, idx) => (
                <button 
                  key={role.id}
                  onClick={() => setSelectedRoleId(role.id)}
                  className={`relative group flex items-center p-10 rounded-[2.5rem] transition-all duration-700 text-left border overflow-hidden ${
                    selectedRoleId === role.id 
                      ? 'bg-white border-[#c5a059]/20 gallery-shadow translate-x-4' 
                      : 'bg-[#fdfcf9]/50 border-transparent hover:bg-white hover:border-[#c5a059]/10'
                  }`}
                >
                  <div className="mr-8">
                    <span className="font-serif italic text-4xl text-slate-200 group-hover:text-[#c5a059] transition-colors">
                      {String(idx + 1).padStart(2, '0')}
                    </span>
                  </div>
                  <div>
                    <h4 className={`text-xl font-serif italic ${selectedRoleId === role.id ? 'text-slate-900' : 'text-slate-400'}`}>
                      {role.name}
                    </h4>
                    <p className="text-[9px] font-black uppercase tracking-[0.3em] text-[#c5a059]/50 mt-2">
                      {role.count} Active Profiles
                    </p>
                  </div>
                  {selectedRoleId === role.id && (
                    <div className="absolute right-10 top-1/2 -translate-y-1/2">
                       <i className="fa-solid fa-arrow-right-long text-[#c5a059] opacity-40"></i>
                    </div>
                  )}
                </button>
              ))}
            </div>
            
            <button className="w-full py-8 border-2 border-dashed border-[#c5a059]/10 rounded-[2.5rem] text-[10px] font-black uppercase tracking-[0.4em] text-slate-300 hover:text-[#c5a059] hover:border-[#c5a059]/30 transition-all flex flex-col items-center group">
              <i className="fa-solid fa-plus mb-3 opacity-20 group-hover:opacity-100 transition-opacity"></i>
              Register New Tier
            </button>
          </div>

          {/* Permissions Matrix - Detailed Plate Style */}
          <div className="xl:w-2/3 bg-white gallery-shadow rounded-[4rem] border border-[#c5a059]/5 overflow-hidden flex flex-col">
            <div className="p-16 border-b border-[#c5a059]/5 bg-[#fdfcf9]/30 flex flex-col md:flex-row md:items-center justify-between gap-8">
              <div>
                <span className="text-[9px] font-black uppercase tracking-[0.6em] text-[#c5a059] block mb-4">Authority Configuration</span>
                <h3 className="font-serif italic text-5xl text-slate-900">{selectedRole?.name}</h3>
              </div>
              <button className="bg-black text-white px-12 py-5 rounded-full text-[10px] font-black uppercase tracking-[0.4em] hover:bg-[#c5a059] transition-all duration-700 shadow-2xl">
                Commit Changes
              </button>
            </div>

            <div className="divide-y divide-[#c5a059]/5">
              {selectedRole?.permissions.map((perm, idx) => (
                <div key={idx} className="p-16 hover:bg-[#fdfcf9] transition-all group/perm">
                  <div className="flex flex-col lg:flex-row lg:items-center justify-between gap-12">
                    <div className="flex items-start lg:w-1/3">
                      <div className="w-16 h-16 rounded-2xl border border-[#c5a059]/10 flex items-center justify-center text-[#c5a059] bg-white gallery-shadow mr-8 transform group-hover/perm:rotate-3 transition-transform duration-500">
                        <i className={`fa-solid ${
                          perm.module === 'Dashboard' ? 'fa-chart-pie' :
                          perm.module === 'Content' ? 'fa-pen-to-square' :
                          perm.module === 'Orders' ? 'fa-cart-shopping' :
                          perm.module === 'Invoices' ? 'fa-file-invoice' : 'fa-users-gear'
                        } text-xl`}></i>
                      </div>
                      <div>
                        <h5 className="font-serif italic text-3xl text-slate-900">{perm.module}</h5>
                        <p className="text-[8px] font-black uppercase tracking-[0.3em] text-slate-300 mt-2">Section Module Control</p>
                      </div>
                    </div>

                    <div className="grid grid-cols-2 sm:grid-cols-4 gap-8 flex-1">
                      {(['read', 'write', 'delete', 'export'] as const).map(action => (
                        <div key={action} className="flex flex-col items-center">
                          <span className="text-[8px] font-black uppercase tracking-[0.5em] text-slate-300 mb-6">{action}</span>
                          <button 
                            onClick={() => togglePermission(idx, action)}
                            className={`w-12 h-6 rounded-full relative transition-all duration-500 border ${
                              perm[action] 
                                ? 'bg-black border-black' 
                                : 'bg-transparent border-[#c5a059]/20'
                            }`}
                          >
                            <div className={`absolute top-1/2 -translate-y-1/2 w-3.5 h-3.5 rounded-full transition-all duration-500 ${
                              perm[action] 
                                ? 'right-1.5 bg-[#c5a059]' 
                                : 'left-1.5 bg-slate-200'
                            }`}></div>
                          </button>
                        </div>
                      ))}
                    </div>
                  </div>
                </div>
              ))}
            </div>

            <div className="p-16 bg-[#fdfcf9]/50 border-t border-[#c5a059]/10">
              <div className="max-w-xl flex items-start space-x-8">
                <div className="text-3xl text-[#c5a059] opacity-30 italic font-serif leading-none">!</div>
                <div>
                  <h6 className="text-[9px] font-black uppercase tracking-[0.4em] text-slate-900 mb-3">Security Mandate</h6>
                  <p className="text-[12px] font-serif italic text-slate-500 leading-relaxed">
                    Note that administrative adjustments to the <span className="text-[#c5a059]">{selectedRole?.name}</span> ledger will propagate across all {selectedRole?.count} verified accounts within this tier.
                  </p>
                </div>
              </div>
            </div>
          </div>
        </div>
      ) : (
        <div className="flex flex-col items-center justify-center min-h-[500px] text-center px-4">
          <div className="w-48 h-48 rounded-full border border-[#c5a059]/10 bg-white gallery-shadow flex items-center justify-center mb-12 relative">
             <div className="absolute inset-0 border border-[#c5a059]/5 rounded-full animate-ping opacity-20"></div>
             <i className="fa-solid fa-user-lock text-4xl text-[#c5a059] opacity-20"></i>
          </div>
          <h3 className="font-serif italic text-5xl text-slate-900 mb-6">User Overrides</h3>
          <p className="text-xl font-serif italic text-slate-400 max-w-2xl leading-relaxed mb-16">
            Refine individual access protocols without compromising general tier constraints. 
            A precise method for temporary executive delegation.
          </p>
          <div className="w-full max-w-2xl relative group">
            <i className="fa-solid fa-magnifying-glass absolute left-10 top-1/2 -translate-y-1/2 text-slate-200 group-focus-within:text-[#c5a059] transition-all"></i>
            <input 
              type="text" 
              placeholder="Query Identity archives..." 
              className="w-full pl-24 pr-12 py-8 bg-white border border-[#c5a059]/10 rounded-[2rem] text-[11px] font-bold uppercase tracking-[0.3em] outline-none gallery-shadow focus:border-[#c5a059] transition-all placeholder:text-slate-100"
            />
          </div>
          
          <div className="mt-20 flex space-x-12 grayscale opacity-20">
             {[1,2,3,4,5].map(i => (
                <div key={i} className="w-16 h-16 rounded-full bg-slate-100 border border-slate-200"></div>
             ))}
          </div>
        </div>
      )}
    </div>
  );
};

export default PermissionsManagement;

Articoli correlati