cursor'

import { useState, useRef, useEffect, type JSX } from "react";
import { type ColDef } from "ag-grid-community";
import { Button } from "../../../Shared/Components/Button/Button";
import { Input } from "../../../Shared/Components/Input/Input";
import { Card, CardContent } from "../../../Shared/Components/Card/Card";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "../../../Shared/Components/Dialog/Dialog";
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "../../../Shared/Components/Collapsible/Collapsible";
import { toast } from "sonner";
import { Switch } from "../../../Shared/Components/Switch/Switch";
import { Textarea } from "../../../Shared/Components/Textarea/Textarea";
import { ChevronDown, ChevronRight } from "lucide-react";
import AGGrid, { type AGGridRef } from "../../../Shared/Components/Ag-grid/Ag-grid";
import ActionsRenderer from "../../../Shared/Components/CellRenderer/CellRenderer";

const ROLES_STORAGE_KEY = 'user_management_roles';
const PERMISSIONS_STORAGE_KEY = 'user_management_permissions';

interface Permission {
  label: string;
  value: string;
  field: string;
}

interface PermissionArea {
  label: string;
  key: string;
  children: Permission[];
}

interface UserRole {
  id: string;
  role_id: string;
  role_name: string;
  description: string;
  last_updated_time?: string;
  last_updated_by?: string;
  active?: boolean;
  permissions?: Record<string, Record<string, boolean>>;
}

// Initialize permissions structure
const initializePermissions = () => {
  if (!localStorage.getItem(PERMISSIONS_STORAGE_KEY)) {
    const defaultPermissions: PermissionArea[] = [
      {
        label: "User Management",
        key: "user_management",
        children: [
          { label: "Create", value: "create", field: "user_management_create" },
          { label: "Read", value: "read", field: "user_management_read" },
          { label: "Update", value: "update", field: "user_management_update" },
          { label: "Delete", value: "delete", field: "user_management_delete" },
        ]
      },
      {
        label: "Reports",
        key: "reports",
        children: [
          { label: "View", value: "view", field: "reports_view" },
          { label: "Export", value: "export", field: "reports_export" },
        ]
      },
      {
        label: "Settings",
        key: "settings",
        children: [
          { label: "Configure", value: "configure", field: "settings_configure" },
          { label: "Manage", value: "manage", field: "settings_manage" },
        ]
      }
    ];
    localStorage.setItem(PERMISSIONS_STORAGE_KEY, JSON.stringify(defaultPermissions));
  }

  if (!localStorage.getItem(ROLES_STORAGE_KEY)) {
    const mockRoles: UserRole[] = [
      {
        id: "role_1",
        role_id: "role_1",
        role_name: "Admin",
        description: "Full system access",
        permissions: {
          user_management: { create: true, read: true, update: true, delete: true },
          reports: { view: true, export: true },
          settings: { configure: true, manage: true }
        }
      },
      {
        id: "role_2",
        role_id: "role_2",
        role_name: "QA-ADMIN",
        description: "Quality assurance administrator",
        permissions: {
          user_management: { create: false, read: true, update: true, delete: false },
          reports: { view: true, export: true },
          settings: { configure: false, manage: false }
        }
      },
      {
        id: "role_3",
        role_id: "role_3",
        role_name: "Test new role",
        description: "Test role for new features",
        permissions: {
          user_management: { create: false, read: true, update: false, delete: false },
          reports: { view: true, export: false },
          settings: { configure: false, manage: false }
        }
      },
      {
        id: "role_4",
        role_id: "role_4",
        role_name: "User",
        description: "Standard user access",
        permissions: {
          user_management: { create: false, read: true, update: false, delete: false },
          reports: { view: true, export: false },
          settings: { configure: false, manage: false }
        }
      }
    ];
    localStorage.setItem(ROLES_STORAGE_KEY, JSON.stringify(mockRoles));
  }
};

function PermissionToggle({
  label,
  description,
  checked,
  onCheckedChange,
}: {
  label: string;
  description: string;
  checked: boolean;
  onCheckedChange: (checked: boolean) => void;
}) {
  return (
    <div className="flex items-center justify-between py-2">
      <div className="flex-1">
        <div className="flex items-center gap-3">
          <Switch checked={checked} onCheckedChange={onCheckedChange} />
          <div>
            <p className="text-sm font-medium">{label}</p>
            <p className="text-xs text-gray-500">{description}</p>
          </div>
        </div>
      </div>
    </div>
  );
}

function PermissionSection({
  title,
  permissions,
  permissionKeys,
  onPermissionChange,
}: {
  title: string;
  permissions: Record<string, boolean>;
  permissionKeys: string[];
  onPermissionChange: (permission: string, value: boolean) => void;
}) {
  const [isOpen, setIsOpen] = useState(true);

  const permissionDescriptions = (key: string) => {
    return `Can ${key.toLowerCase()} ${title.toLowerCase()}`;
  };

  return (
    <Collapsible open={isOpen} onOpenChange={setIsOpen}>
      <CollapsibleTrigger className="flex items-center justify-between w-full p-3 bg-gray-50 hover:bg-gray-100 rounded-lg transition-colors">
        <h4 className="font-medium">{title}</h4>
        {isOpen ? (
          <ChevronDown className="w-4 h-4" />
        ) : (
          <ChevronRight className="w-4 h-4" />
        )}
      </CollapsibleTrigger>
      <CollapsibleContent className="px-3 pb-3">
        <div className="space-y-2 pt-2">
          {permissionKeys.map((key) => (
            <PermissionToggle
              key={key}
              label={key.charAt(0).toUpperCase() + key.slice(1)}
              description={permissionDescriptions(key)}
              checked={permissions[key] || false}
              onCheckedChange={(checked) => onPermissionChange(key, checked)}
            />
          ))}
        </div>
      </CollapsibleContent>
    </Collapsible>
  );
}

type UserRolesGridProps = {
  onEdit: (role: UserRole) => void;
  onDelete: (role: UserRole) => void;
  refreshTrigger: number;
};

function UserRolesGrid({ onEdit, onDelete, refreshTrigger }: UserRolesGridProps) {
  const gridRef = useRef<AGGridRef>(null);
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([]);
  const [userRoleRowData, setUserRoleRowData] = useState<UserRole[]>([]);
  const [loading, setLoading] = useState(true);

  const handleActionClick = (actionType: string, row: UserRole) => {
    switch (actionType) {
      case "edit":
        onEdit(row);
        break;
      case "delete":
        onDelete(row);
        break;
      default:
        console.warn("Unhandled action:", actionType);
    }
  };

  const fetchData = () => {
    try {
      setLoading(true);
      initializePermissions();

      const storedRoles = localStorage.getItem(ROLES_STORAGE_KEY);
      const roles: UserRole[] = storedRoles ? JSON.parse(storedRoles) : [];

      const columns: ColDef[] = [
        {
          headerName: "Role Name",
          field: "role_name",
          sortable: true,
          resizable: true,
        },
        {
          headerName: "Description",
          field: "description",
          sortable: true,
          resizable: true,
        },
        {
          headerName: "Actions",
          field: "actions",
          width: 100,
          cellRendererFramework: ActionsRenderer,
          cellRendererParams: {
            actions: [
              { action: "edit", tooltip: "Edit", type: "edit", class: "fa fa-pencil" },
              { action: "delete", tooltip: "Delete", type: "delete", class: "fa fa-trash" }
            ],
            onActionClick: handleActionClick,
          },
          suppressMenu: true,
          sortable: false,
          filter: false,
          resizable: false,
        }
      ];

      setColumnDefs(columns);
      setUserRoleRowData(roles);
    } catch (error) {
      console.error("Failed to load roles from localStorage:", error);
      toast.error("Failed to load roles");
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchData();
  }, [refreshTrigger]);

  return (
    <div className="space-y-4">
      <div className="hidden md:block">
        <div className="ag-theme-alpine" style={{ height: 400, width: "100%" }}>
          {loading ? (
            <div className="flex justify-center items-center h-full">
              <div className="text-gray-500">Loading...</div>
            </div>
          ) : userRoleRowData.length > 0 ? (
            <AGGrid
              ref={gridRef}
              columnDefs={columnDefs}
              cacheBlockSize={100}
              maxBlocksInCache={5}
              rowData={userRoleRowData}
              height={400}
              enableSorting={false}
              enableFiltering={false}
              enableResizing={true}
              animateRows={true}
              headerHeight={40}
              rowHeight={35}
              domLayout="normal"
            />
          ) : (
            <div className="flex justify-center items-center h-full text-gray-500">
              No user roles found.
            </div>
          )}
        </div>
      </div>
      <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between p-4 bg-white border border-[#b8bcbf]">
        <div className="flex items-center space-x-6 text-sm font-['Roboto',sans-serif]">
          <div className="flex items-center gap-1">
            <span className="font-normal">Total Roles</span>
            <span>:</span>
            <span className="font-medium">{userRoleRowData.length}</span>
          </div>
        </div>
      </div>
    </div>
  );
}

export default function UserRoles() {
  const [showCreateForm, setShowCreateForm] = useState(false);
  const [editingRole, setEditingRole] = useState<UserRole | null>(null);
  const [showDeleteDialog, setShowDeleteDialog] = useState(false);
  const [deletingRole, setDeletingRole] = useState<UserRole | null>(null);
  const [permissionAreas, setPermissionAreas] = useState<PermissionArea[]>([]);
  const [userRoleFormData, setUserRoleFormData] = useState<Omit<UserRole, "id">>({
    role_id: "",
    description: "",
    active: true,
    role_name: "",
    permissions: {}
  });
  const [refreshTrigger, setRefreshTrigger] = useState(0);

  const handleEdit = (role: UserRole) => {
    try {
      initializePermissions();
      const storedPermissions = localStorage.getItem(PERMISSIONS_STORAGE_KEY);
      const permissionAreas: PermissionArea[] = storedPermissions ? JSON.parse(storedPermissions) : [];
      setPermissionAreas(permissionAreas);

      const initializedPermissions = permissionAreas.reduce(
        (acc: any, area: { key: string | number; children: any[] }) => ({
          ...acc,
          [area.key]: area.children.reduce(
            (permAcc, perm) => ({
              ...permAcc,
              [perm.value]: role.permissions?.[area.key]?.[perm.value] || false,
            }),
            {} as Record<string, boolean>
          ),
        }),
        {} as Record<string, Record<string, boolean>>
      );

      setUserRoleFormData({
        role_name: role.role_name,
        description: role.description,
        permissions: initializedPermissions,
        role_id: role.role_id
      });
      setEditingRole(role);
      setShowCreateForm(true);
    } catch (error) {
      console.error("Failed to edit user role:", error);
      toast.error("Failed to load role details. Please try again.");
    }
  };

  const handleCreate = () => {
    try {
      initializePermissions();
      const storedPermissions = localStorage.getItem(PERMISSIONS_STORAGE_KEY);
      const permissionAreas: PermissionArea[] = storedPermissions ? JSON.parse(storedPermissions) : [];
      setPermissionAreas(permissionAreas);

      const initializedPermissions = permissionAreas.reduce(
        (acc: any, area: { key: any; children: any[] }) => ({
          ...acc,
          [area.key]: area.children.reduce(
            (permAcc: any, perm: { value: any }) => ({
              ...permAcc,
              [perm.value]: false,
            }),
            {} as Record<string, boolean>
          ),
        }),
        {} as Record<string, Record<string, boolean>>
      );

      setUserRoleFormData({
        role_name: "",
        description: "",
        permissions: initializedPermissions,
        role_id: "",
      });
      setShowCreateForm(true);
    } catch (error) {
      console.error("Failed to initialize form:", error);
      toast.error("Failed to load permissions. Please try again.");
    }
  };

  const handlePermissionChange = (section: string, permission: string, value: boolean) => {
    setUserRoleFormData((prev) => ({
      ...prev,
      permissions: {
        ...(prev.permissions ?? {}),
        [section]: {
          ...(prev.permissions?.[section] ?? {}),
          [permission]: value,
        },
      },
    }));
  };

  const handleDelete = (role: UserRole) => {
    setDeletingRole(role);
    setShowDeleteDialog(true);
  };

  const confirmDeleteRole = () => {
    if (!deletingRole) return;

    try {
      const storedRoles = localStorage.getItem(ROLES_STORAGE_KEY);
      const roles: UserRole[] = storedRoles ? JSON.parse(storedRoles) : [];

      const updatedRoles = roles.filter((role) => role.id !== deletingRole.id);
      localStorage.setItem(ROLES_STORAGE_KEY, JSON.stringify(updatedRoles));

      toast.success(`Role "${deletingRole.role_name}" has been deleted.`);
      setShowDeleteDialog(false);
      setDeletingRole(null);
      setRefreshTrigger(prev => prev + 1);
    } catch (error) {
      console.error("Delete failed:", error);
      toast.error("Failed to delete role. Please try again.");
    }
  };

  const handleSave = () => {
    if (!userRoleFormData.role_name.trim()) {
      toast.error("Role name is required");
      return;
    }

    try {
      const storedRoles = localStorage.getItem(ROLES_STORAGE_KEY);
      const roles: UserRole[] = storedRoles ? JSON.parse(storedRoles) : [];

      if (editingRole) {
        // Update existing role
        const updatedRoles = roles.map((role) =>
          role.id === editingRole.id
            ? {
                ...role,
                role_name: userRoleFormData.role_name,
                description: userRoleFormData.description,
                permissions: userRoleFormData.permissions,
              }
            : role
        );
        localStorage.setItem(ROLES_STORAGE_KEY, JSON.stringify(updatedRoles));
        toast.success("User role updated successfully");
      } else {
        // Create new role
        const newRole: UserRole = {
          ...userRoleFormData,
          id: `role_${Date.now()}`,
          role_id: `role_${Date.now()}`,
        };
        roles.push(newRole);
        localStorage.setItem(ROLES_STORAGE_KEY, JSON.stringify(roles));
        toast.success("User role created successfully");
      }

      handleCancel();
      setRefreshTrigger(prev => prev + 1);
    } catch (error) {
      console.error("Error saving user role:", error);
      toast.error("Failed to save user role. Please try again.");
    }
  };

  const handleCancel = () => {
    setUserRoleFormData({
      role_name: "",
      description: "",
      permissions: {},
      role_id: "",
    });
    setShowCreateForm(false);
    setEditingRole(null);
    setPermissionAreas([]);
  };

  if (showCreateForm) {
    return (
      <div className="space-y-4">
        <div className="flex justify-between items-center">
          <div>
            <h3 className="text-lg font-medium">
              {editingRole ? "Edit User Role" : "Create New User Role"}
            </h3>
            <p className="text-sm text-gray-600 mt-1">
              {editingRole
                ? "Update the role information and permissions below."
                : "Fill in the role information and configure permissions below."}
            </p>
          </div>
          <Button variant="outline" onClick={handleCancel}>
            Back to Roles
          </Button>
        </div>
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
          <div className="space-y-6">
            <Card>
              <CardContent className="p-6">
                <h4 className="font-medium mb-4">Role Information</h4>
                <div className="space-y-4">
                  <div>
                    <label className="text-sm font-medium text-black mb-2 block">
                      Role Name *
                    </label>
                    <Input
                      value={userRoleFormData.role_name}
                      onChange={(e) =>
                        setUserRoleFormData({
                          ...userRoleFormData,
                          role_name: e.target.value,
                        })
                      }
                      placeholder="Enter role name"
                      className="w-full"
                      required
                    />
                  </div>
                  <div>
                    <label className="text-sm font-medium text-black mb-2 block">
                      Description
                    </label>
                    <Textarea
                      value={userRoleFormData.description}
                      onChange={(e) =>
                        setUserRoleFormData({
                          ...userRoleFormData,
                          description: e.target.value,
                        })
                      }
                      placeholder="Enter role description"
                      className="w-full min-h-[80px]"
                      rows={3}
                    />
                  </div>
                </div>
              </CardContent>
            </Card>
          </div>
          <div className="space-y-6">
            <Card>
              <CardContent className="p-6">
                <h4 className="font-medium mb-4">Access Permissions</h4>
                <div className="space-y-3">
                  {permissionAreas.map((area) => (
                    <PermissionSection
                      key={area.key}
                      title={area.label}
                      permissions={userRoleFormData.permissions ? userRoleFormData.permissions[area.key] || {} : {}}
                      permissionKeys={area.children.map((perm) => perm.value)}
                      onPermissionChange={(permission, value) =>
                        handlePermissionChange(area.key, permission, value)
                      }
                    />
                  ))}
                  {!permissionAreas.length && (
                    <p className="text-sm text-gray-500">
                      No permission areas available. Please try again.
                    </p>
                  )}
                </div>
              </CardContent>
            </Card>
            <div className="flex justify-end gap-3">
              <Button variant="outline" onClick={handleCancel}>
                Cancel
              </Button>
              <Button
                onClick={handleSave}
                className="bg-[#000000] text-white hover:bg-gray-800"
              >
                {editingRole ? "Update Role" : "Create Role"}
              </Button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <div className="flex justify-end">
        <Button
          onClick={handleCreate}
          className="bg-[#000000] text-white hover:bg-gray-800 h-[34px] px-4 rounded-[5px]"
        >
          Add Role +
        </Button>
      </div>
      <UserRolesGrid
        onEdit={handleEdit}
        onDelete={handleDelete}
        refreshTrigger={refreshTrigger}
      />
      <Dialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>Delete Role</DialogTitle>
            <DialogDescription>
              Are you sure you want to delete the role "{deletingRole?.role_name}"? This action cannot be undone.
            </DialogDescription>
          </DialogHeader>
          <div className="py-4">
            <p className="text-sm text-gray-600">
              This will permanently remove the role from the system. Users assigned to this role may lose their permissions.
            </p>
          </div>
          <div className="flex justify-end gap-3">
            <Button variant="outline" onClick={() => setShowDeleteDialog(false)}>
              Cancel
            </Button>
            <Button
              onClick={confirmDeleteRole}
              className="bg-red-600 hover:bg-red-700 text-white"
            >
              Delete Role
            </Button>
          </div>
        </DialogContent>
      </Dialog>
    </div>
  );
}

Comments

Popular posts from this blog

Homesit

Login.js